[
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at marcin@ziabek.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: QuestPDF\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nPlease provide an example, minimalistic code that shows the problem.\nProviding working example or example repository greatly helps us investigate the problem and react faster.\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Environment**\nWhat version of the library do you use? \nWhat operating system do you use? (OS type, x64 vs x86 vs arm64)\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/companion_app_feedback.md",
    "content": "---\nname: Companion App Feedback\nabout: Suggest an idea for this project\ntitle: ''\nlabels: 'companion-app'\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is.\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is.\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n| Version   | Supported          | Scope                                                                                                                      | License                                         |\n|-----------|--------------------|----------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|\n| 2024.X.Y  | :white_check_mark: | full: feature, quality and bug-fix updates ([branch](https://github.com/QuestPDF/QuestPDF))                                | Hybrid: Community MIT, Professional, Enterprise |\n| 2023.X.Y  | :white_check_mark: | limited until Q4 2024: quality and bug-fix updates ([branch](https://github.com/QuestPDF/QuestPDF))                                | Hybrid: Community MIT, Professional, Enterprise |\n| 2022.12.X | :x: | supported until Q2 2024, no longer supported ([branch](https://github.com/QuestPDF/QuestPDF/tree/2022.12.X-support)) | MIT                                             |\n| Older     | :x:                | no support                                                                                                                 | MIT                                             |\n\n\n## Reporting a Vulnerability\n\nPlease report any code vulnerabilities using GitHub Issues. We are trying to respond within 1 day and analyze reported situation as soon as possible.\nPlease collaborate with us to find best solutation available.\nOnce the vulnerability is recognized and fixed, the issue is closed with appropraite message. \n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: Build, Test And Create Nuget Package\n\npermissions: {}\n\non:\n  push:\n    branches: [ main ]\n  workflow_dispatch:\n\njobs:\n  main:\n    name: ${{ matrix.runtime.name }}\n    runs-on: ${{ matrix.runtime.runs-on }}\n    container: ${{ matrix.runtime.container }}\n    timeout-minutes: 20\n  \n    strategy:\n      fail-fast: false\n      matrix:\n        runtime: \n        - name: win-x64\n          runs-on: windows-latest-xlarge\n        # - name: win-x86\n        #   runs-on: windows-latest-xlarge\n        - name: linux-x64\n          runs-on: ubuntu-latest-xlarge\n          container: ubuntu:24.04\n        - name: linux-arm64\n          runs-on: ubuntu-latest-xlarge-arm64\n          container: ubuntu:24.04\n        - name: linux-musl-x64\n          runs-on: ubuntu-latest-xlarge\n          container: alpine:3.20\n        - name: osx-x64\n          runs-on: macos-latest-large\n        - name: osx-arm64\n          runs-on: macos-latest-xlarge\n\n    steps:\n      - name: Checkout sources\n        uses: actions/checkout@v4\n\n\n      - name: Install Build Tools (Linux)\n        if: matrix.runtime.name == 'linux-x64' || matrix.runtime.name == 'linux-arm64'\n        shell: sh\n        run: |\n          apt update --yes\n          apt upgrade --yes\n\n          # required by actions/setup-dotnet\n          apt install bash wget --yes\n\n          # required by conformance testing tools: veraPDF and mustang\n          apt install unzip default-jre --yes\n          java -version\n\n\n      - name: Install Build Tools (Alpine)\n        if: matrix.runtime.name == 'linux-musl-x64'\n        shell: sh\n        run: |\n          apk update\n          apk upgrade\n\n          # required by actions/setup-dotnet\n          apk add bash wget\n\n          # required by dotnet build command\n          apk add libstdc++ libgcc\n\n\n      - name: Setup dotnet\n        uses: actions/setup-dotnet@v5\n        with:\n          dotnet-version: '10.0.x'\n\n\n      - name: Install veraPDF - PDF conformance testing tool\n        if: matrix.runtime.name == 'linux-x64'\n        run: |\n          mkdir -p ~/verapdf\n          cd ~/verapdf\n          \n          wget -q https://software.verapdf.org/rel/verapdf-installer.zip\n          unzip -q verapdf-installer.zip\n          \n          rm verapdf-installer.zip\n          mv verapdf* verapdf \n\n          cd verapdf\n          printf \"1\\n\\nO\\n1\\nY\\nY\\nN\\n1\\nY\\n\\n\" | ./verapdf-install\n          alias verapdf='/root/verapdf/verapdf'\n          verapdf --version\n\n\n      - name: Install mustang - ZUGFeRD conformance testing tool\n        if: matrix.runtime.name == 'linux-x64'\n        run: |\n          mkdir -p /root/mustang\n          cd /root/mustang\n          \n          wget https://repo1.maven.org/maven2/org/mustangproject/Mustang-CLI/2.20.0/Mustang-CLI-2.20.0.jar -O mustang-cli.jar\n\n          alias mustang='java -jar /root/mustang/mustang-cli.jar'\n          mustang --help\n\n\n      - name: Build and test solution\n        shell: bash\n        working-directory: ./Source\n        env:\n          VERAPDF_EXECUTABLE_PATH: '/root/verapdf/verapdf'\n          MUSTANG_EXECUTABLE_PATH: '/root/mustang/mustang-cli.jar'\n          DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1\n        run: |\n          dotnet build --configuration Release --property WarningLevel=0\n          dotnet test QuestPDF.UnitTests --configuration Release --runtime ${{ matrix.runtime.name }} --framework net10.0\n          dotnet test QuestPDF.LayoutTests --configuration Release --runtime ${{ matrix.runtime.name }} --framework net10.0\n          dotnet test QuestPDF.VisualTests --configuration Release --runtime ${{ matrix.runtime.name }} --framework net10.0\n          dotnet test QuestPDF.DocumentationExamples --configuration Release --runtime ${{ matrix.runtime.name }} --framework net10.0\n          dotnet test QuestPDF.ReportSample --configuration Release --runtime ${{ matrix.runtime.name }} --framework net10.0\n          dotnet test QuestPDF.ZUGFeRD --configuration Release --runtime ${{ matrix.runtime.name }} --framework net10.0\n\n          \n          if [ \"${{ matrix.runtime.name }}\" == \"linux-x64\" ]; then\n            dotnet test QuestPDF.ConformanceTests --configuration Release --runtime ${{ matrix.runtime.name }} --framework net10.0\n          fi\n\n          dotnet build QuestPDF/QuestPDF.csproj --configuration Release --property WarningLevel=0 --property BUILD_PACKAGE=true\n\n          TEST_EXECUTION_PATH='QuestPDF.ReportSample/bin/Release/net10.0/${{ matrix.runtime.name }}'\n          mkdir -p testOutput/${{ matrix.runtime.name }} \n          cp -r $TEST_EXECUTION_PATH/report.pdf testOutput/${{ matrix.runtime.name }} \n\n\n      - name: Upload test results\n        uses: actions/upload-artifact@v4\n        with:\n          name: questpdf-test-results-${{ matrix.runtime.name }}\n          path: |\n            **/*.pdf\n\n        \n      - name: Upload nuget artifacts\n        uses: actions/upload-artifact@v4\n        if: ${{ matrix.runtime.name == 'win-x64' }}\n        with:\n          name: questpdf-nuget-package\n          path: |\n            **/*.nupkg\n            **/*.snupkg\n            !.nuget\n\n  merge:\n    runs-on: ubuntu-latest\n    needs: main\n    steps:\n      - name: Merge Artifacts\n        uses: actions/upload-artifact/merge@v4\n        with:\n          name: questpdf-test-results\n          pattern: questpdf-test-results-*\n          delete-merged: true\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbuild/\nbld/\n[Bb]in/\n[Oo]bj/\nartifacts/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n*.cachefile\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n*.ncrunchsolution\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings \n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n\n# Windows Azure Build Output\ncsx/\n*.build.csdef\n\n# Windows Store app package directory\nAppPackages/\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n[Ss]tyle[Cc]op.*\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Project Rider\n*.iml\n.idea\n\n# macOS\n.DS_Store\n**/.DS_Store\n"
  },
  {
    "path": "LICENSE.md",
    "content": "﻿# QuestPDF License\n\n## License Selection Guide\n\nWelcome to QuestPDF! This guide will help you understand how to select the appropriate license for our library, based on your usage context.\n\nThe licensing options for QuestPDF include the MIT license (which is free), and two tiers of paid licenses: the Professional License and the Enterprise License.\n\n### License Equality\n\nWe believe in offering the full power of QuestPDF to all our users, regardless of the license they choose. Whether you're operating under our Community MIT, Professional, or Enterprise licenses, you can enjoy the same comprehensive range of features:\n\n- Full access to all QuestPDF features.\n- Support for commercial usage.\n- Freedom to create and deploy unlimited closed-source projects, applications, and APIs.\n- Royalty-free redistribution of the compiled library with your applications.\n  Transitive Dependency Usage\n  If you're using QuestPDF as a transitive dependency, you're free to use it under the MIT license without any cost. However, you're welcomed and encouraged to support the project by purchasing a paid license if you find the library valuable.\n\n### Non-profit Usage\n\nIf you represent an open-source project, a charitable organization, or are using QuestPDF for evaluation, learning or training purposes, you can also use QuestPDF for free under the MIT license.\n\n### Small Businesses\n\nFor companies generating less than $1M USD in annual gross revenue, you can use QuestPDF under the MIT license for free.\n\n### Larger Businesses\n\nCompanies with an annual gross revenue exceeding $1M USD are required to purchase a paid license. The type of license you need depends on the number of developers working on projects that use QuestPDF:\n\nProfessional License - If there are up to 10 developers in your company who are using QuestPDF, you need to purchase the Professional License.\n\nEnterprise License - If your company has more than 10 developers using QuestPDF, the Enterprise License is the right choice.\n\n### Beyond Compliance\n\nRemember, purchasing a license isn't just about adhering to our guidelines, but also supporting the development of QuestPDF. Your contribution helps us to improve the library and offer top-notch support to all users.\n\n<br>\n<hr>\n<br>\n\n## QuestPDF Community MIT License\n\n### License Permissions\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n### Copyright\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n### Limitation Of Liability\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n<br>\n<hr>\n<br>\n\n## QuestPDF Professional and Enterprise Use License\n\n### Do No Harm\n\nBy downloading or using the Software, the Licensee agrees not to utilize the software in a manner which is disparaging to QuestPDF, and not to rent, lease or otherwise transfer rights to the Software.\n\n### License Permissions\n\nGrants the use of the Software by a specified number of developers to create and deploy closed-source software for unlimited end user organizations (\"The Organization\") in multiple locations. This license covers unlimited applications or projects. The Software may be deployed upon any number of machines for the end-use of The Organization. This license also intrinsically covers for development, staging and production servers for each project.\n\nGrants the right to distribute the Software (without royalty) as part of packaged commercial products.\n\n### License Fees\n\nA. If you wish to use the Software in a production environment, the purchase of a license is required. This license is perpetual, granting you continued use of the Software in accordance with the terms and conditions of this Agreement. The cost of the license is as indicated on the pricing page.\n\nB. Upon purchasing a license, you are also enrolled in a yearly, recurring subscription for software updates. This subscription is valid for a period of one year from the date of purchase, and it will automatically renew each year unless cancelled. We recommend maintaining your subscription as long as you are performing active software development to ensure you have access to the latest updates and improvements to the Software.\n\nC. However, it should be noted that the perpetual license allows use of only the latest library revision available at the time of or within the active subscription period, in accordance with the terms and conditions of this Agreement.\n\nD. If you wish to use the Software in a non-production environment, such as for testing and evaluation purposes, you may download and access the source and/or binaries at no charge. This access is subject to all license limitations and restrictions set forth in this Agreement.\n\n### Ownership\n\nQuestPDF shall at all times retain ownership of the QuestPDF Software library and all subsequent copies.\n\n### Copyright\n\nTitle, ownership rights, and intellectual property rights in and to the Software shall remain with QuestPDF. The Software is protected by the international copyright laws. Title, ownership rights, and intellectual property rights in and to the content accessed through the Software is the property of the applicable content owner and may be protected by applicable copyright or other law. This License gives you no rights to such content.\n\n### Limitation Of Liability\n\nTHIS SOFTWARE IS PROVIDED \"AS IS,\" WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. QUESTPDF AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL QUESTPDF OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF QUESTPDF HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n"
  },
  {
    "path": "README.md",
    "content": "<picture>\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/user-attachments/assets/9535de26-aeac-42ac-ac45-019a2893ed6b\">\n  <source media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/user-attachments/assets/e9d197ee-0cad-44f0-9efa-80ad68c31abe\">\n  <img src=\"https://github.com/user-attachments/assets/e9d197ee-0cad-44f0-9efa-80ad68c31abe\" width=\"300\">\n</picture>\n\n<br>\n<br>\n\n## Modern PDF library for C# developers\n\nQuestPDF is a production-ready library that lets you design documents the way you design software: with clean, maintainable, strong-typed C# code.\nStop fighting with HTML-to-PDF conversion. Build pixel-perfect reports, invoices, and exports using the language and tools you already love.\n\n\n[![GitHub Stars and Stargazers](https://img.shields.io/github/stars/QuestPDF/QuestPDF?style=for-the-badge&label=GitHub%20Stars&logo=github&color=FFEB3B&logoColor=white)](https://github.com/QuestPDF/QuestPDF)\n<br>\n[![Nuget package download](https://img.shields.io/nuget/dt/QuestPDF?style=for-the-badge&label=NuGet%20downloads&logo=nuget&color=0277BD&logoColor=white)](https://www.nuget.org/packages/QuestPDF/)\n<br>\n[![QuestPDF License](https://img.shields.io/badge/LICENSE-Community%20and%20commercial-2E7D32?style=for-the-badge&logo=googledocs&logoColor=white)](https://www.questpdf.com/license.html)\n\n<br>\n<hr>\n\n[Home Page](https://www.questpdf.com)\n&nbsp;&nbsp;•&nbsp;&nbsp;\n[Quick Start](https://www.questpdf.com/quick-start.html)\n&nbsp;&nbsp;•&nbsp;&nbsp;\n[Real-world Invoice Tutorial](https://www.questpdf.com/invoice-tutorial.html)\n&nbsp;&nbsp;•&nbsp;&nbsp;\n[Features Overview](https://www.questpdf.com/features-overview.html)\n&nbsp;&nbsp;•&nbsp;&nbsp;\n[License & Pricing](https://www.questpdf.com/license/)\n&nbsp;&nbsp;•&nbsp;&nbsp;\n[NuGet](https://www.nuget.org/packages/QuestPDF)\n\n<hr>\n<br>\n\n## 🚀 Quick start\n\nLearn how easy it is to design, implement and generate PDF documents using QuestPDF. <br>\nEffortlessly create documents of all types such as invoices and reports.\n\n```c#\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\n// set your license here:\n// QuestPDF.Settings.License = LicenseType.Community;\n\nDocument.Create(container =>\n{\n    container.Page(page =>\n    {\n        page.Size(PageSizes.A4);\n        page.Margin(2, Unit.Centimetre);\n        page.PageColor(Colors.White);\n        page.DefaultTextStyle(x => x.FontSize(20));\n        \n        page.Header()\n            .Text(\"Hello PDF!\")\n            .SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);\n        \n        page.Content()\n            .PaddingVertical(1, Unit.Centimetre)\n            .Column(x =>\n            {\n                x.Spacing(20);\n                \n                x.Item().Text(Placeholders.LoremIpsum());\n                x.Item().Image(Placeholders.Image(200, 100));\n            });\n        \n        page.Footer()\n            .AlignCenter()\n            .Text(x =>\n            {\n                x.Span(\"Page \");\n                x.CurrentPageNumber();\n            });\n    });\n})\n.GeneratePdf(\"hello.pdf\");\n```\n\nThe code above produces the following PDF document:\n\n<img width=\"300\" alt=\"image\" src=\"https://github.com/user-attachments/assets/46784e17-e8be-41d2-87f4-d6322c3b5e52\" />\n\n[![Quick Start Tutorial](https://img.shields.io/badge/read-tutorial-0288D1?style=for-the-badge)](https://www.questpdf.com/quick-start.html)\n\n> [!TIP]\n> The library is free for individuals, non-profits, all FOSS projects, and organizations under $1M in annual revenue.\n> Read more about licensing [here](https://www.questpdf.com/license/)\n\n<br>\n<br>\n\n## Installation\n\nQuestPDF is available as a NuGet package. You can install it through your IDE by searching for phrase `QuestPDF`. If you are not familiar how to do that, please refer to the following guides: \n- [Visual Studio](https://learn.microsoft.com/en-us/nuget/consume-packages/install-use-packages-visual-studio)\n- [Visual Code](https://code.visualstudio.com/docs/csharp/package-management)\n- [JetBrains Rider](https://www.jetbrains.com/help/rider/Using_NuGet.html)\n\nOr use the following command in your terminal:\n\n```bash\ndotnet add package QuestPDF\n```\n\n<br>\n<br>\n\n## Everything you need to generate PDFs\n\nFrom layout and styling to production features, QuestPDF gives you the flexibility to create documents of any complexity.\n\n### 🎨 Visual Content:\n- Page attributes (header, footer, background, watermark, margin),\n- Text (font style, paragraph style, page numbers),\n- Styled containers (background, border, rounded corners, colors and gradients, shadows),\n- Lines (vertical and horizontal, colors and gradients, dash pattern)\n- Images (PNG, JPG, WEBP, SVG),\n\n### 🔀 Layout: \n- Tables,\n- Lists,\n- Layers,\n- Column / Row,\n- Inlined,\n\n### 📐 Positional:\n- Alignment,\n- Size Controls (width / height),\n- Padding, \n\n### 🛠️ Other: \n- Page Breaking Control,\n- Aspect Ratio,\n- Integrations (maps, charts, barcodes, QR codes),\n- Hyperlinks,\n- Z-index,\n\n[![Explore All QuestPDF Features](https://img.shields.io/badge/explore%20all%20features-0288D1?style=for-the-badge)](https://www.questpdf.com/features-overview.html)\n\n<br>\n<br>\n\n## Familiar Programming Patterns\n\nUse your existing programming language and patterns to ship faster with less training. \n\nLoops, conditionals, functions are natively supported. Leverage IntelliSense, inspections, navigation, and safe refactoring.\n\n```csharp\ncontainer.Column(column =>\n{\n    column.Item().Text(\"Order Items\").Bold();\n\n    if (Model.ShowSummary)\n        column.Item().Element(ComposeOrderSummary);\n\n    foreach (var item in Model.Items)\n        column.Item().Element(c => ComposeItem(c, item));\n});\n```\n\nReview document changes like any other code. Get clean diffs, PR approvals, and traceable history.\n\n```diff\nvoid ComposeItem(IContainer container, OrderItem item)\n{\n    container\n        .Border(1, Colors.Grey.Darken2)\n        .Background(item.HighlightColor)\n-       .Padding(12)\n+       .Padding(16)\n        .Row(row =>\n        {\n            row.RelativeItem().Text(item.Name);\n            row.AutoItem().Text($\"{item.Price:F2} USD\");\n        });\n}\n```\n\n<br>\n<br>\n\n## Companion App\n\nAccelerate development with live document preview and hot-reload capability. See your changes instantly without recompiling.\n\n- Explore PDF document hierarchy and navigate its structure\n- Quickly magnify and measure content\n- Debug runtime exceptions with stack traces and code snippets\n- Identify, understand and solve layout errors\n\n<picture>\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/user-attachments/assets/7ab596d4-eebc-44e6-b36d-c358b16ed0ba\">\n  <source media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/user-attachments/assets/39d4c08c-6a78-4743-8837-208c0c1718fd\">\n  <img src=\"https://github.com/user-attachments/assets/ce394258-1f10-498d-b65f-26c9fbed2994\" width=\"600\">\n</picture>\n\n[![Learn about QuestPDF Companion App](https://img.shields.io/badge/learn%20more-0288D1?style=for-the-badge)]([https://www.questpdf.com/companion/features.html](https://www.questpdf.com/companion/usage.html))\n[![Learn about QuestPDF Companion App](https://img.shields.io/badge/features-666666?style=for-the-badge)](https://www.questpdf.com/companion/features.html)\n\n<br>\n<br>\n\n## Enterprise-grade foundations\n\n- **Predictable Development** — Eliminate CSS debugging, browser quirks, and layout surprises common with HTML-to-PDF tools. What you code is what you get.\n\n- **Source-available** - Entire QuestPDF source code is available for review and customization, ensuring transparency and compliance with your organization's requirements.\n\n- **Complete Data Privacy** - QuestPDF runs entirely within your infrastructure with no external API calls, internet requirement, or background data collection. As a company, we do not access, collect, store, or process your private data.\n\n- **Comprehensive Layout Engine** - A powerful layout engine built specifically for PDF generation. Gain full control over document structure, precise content positioning, and automatic pagination.\n\n- **Advanced Language Support** - Create multilingual documents with full RTL language support, advanced text shaping, and bi-directional layout handling.\n\n- **High Performance** - Generate thousands of pages per second while maintaining minimal CPU and memory usage. Perfect for high-throughput enterprise applications.\n\n- **Optimized File Size** - Drastically reduce file sizes without compromising quality. Benefit from automatic font subsetting, optimal image compression, and efficient file compression.\n\n<br>\n<br>\n\n## Perform common PDF operations\n\nLeverage a powerful C# Fluent API to create, customize, and manage your PDF documents with ease.\n- Merge documents\n- Attach files\n- Extract pages\n- Encrypt / decrypt\n- Extend metadata\n– Limit access\n- Optimize for Web\n- Overlay / underlay\n\n```c#\nDocumentOperation\n    .LoadFile(\"input.pdf\")\n    .TakePages(\"1-10\")\n    .MergeFile(\"appendix.pdf\", \"1-z\") // all pages\n    .AddAttachment(new DocumentAttachment\n    {\n        FilePath = \"metadata.xml\"\n    })\n    .Encrypt(new Encryption256Bit\n    {\n        OwnerPassword = \"mypassword\",\n        AllowPrinting = true,\n        AllowContentExtraction = false\n    })\n    .Save(\"final-document.pdf\");\n```\n\n[![Learn Document Operation API](https://img.shields.io/badge/learn%20more-0288D1?style=for-the-badge)](https://www.questpdf.com/concepts/document-operations.html)\n\n<br>\n<br>\n\n## Works everywhere you do\n\nDeploy on any major operating system and integrate seamlessly with your favorite IDEs, cloud platforms, and development tools.\n\n| Platform | Support |\n|----------|---------|\n| **Operating Systems** | Windows, Linux, macOS |\n| **Frameworks** | .NET 6+ and .NET Framework 4.6.2+ |\n| **Cloud** | Azure, AWS, Google Cloud, Others |\n| **Containers** | Docker, Kubernetes |\n| **IDEs** | Visual Studio, VS Code, JetBrains Rider, Others |\n\n<br>\n<br>\n\n## Industry-standard PDF compliance\n\nGenerate PDF documents that meet the strictest archival and accessibility requirements. Every build is automatically validated using the open-source veraPDF and Mustang tools.\n\n- PDF/A (Archival):\n  - Purpose: ISO 19005 standard for long-term preservation. Ensures PDFs remain readable and visually identical for decades without external dependencies.\n  - Supported Standards: `PDF/A-2b`, `PDF/A-2u`, `PDF/A-2a`, `PDF/A-3b`, `PDF/A-3u`, `PDF/A-3a`\n\n- PDF/UA (Accessibility):\n  - Purpose: ISO 14289 standard for universal accessibility. Includes full support for screen readers and assistive technologies for people with disabilities.\n  - Supported Standards: `PDF/UA-1`\n\n- EN 16931 (E-Invoicing):\n  - Purpose: European standard for electronic invoicing. Embeds structured invoice data (XML) within PDF documents for automated processing.\n  - Supported Standards: `ZUGFeRD`, `Factur-X`\n\n<br>\n<br>\n\n## Fair and Sustainable License\n\nA model that benefits everyone. Commercial licensing provides businesses with legal safety and long-term stability, while funding a feature-complete, unrestricted library for the open-source community.\n\n- Actively maintained with regular feature, quality, and security updates\n- Full source code available on GitHub\n- All features included in every tier without restrictions\n- Predictable pricing: no per-seat, per-server, or usage fees\n\n> [!TIP]\n> Free for individuals, non-profits, all FOSS projects, and organizations under $1M in annual revenue.\n\n[![QuestPDF Pricing](https://img.shields.io/badge/view%20pricing-388E3C?style=for-the-badge)](https://www.questpdf.com/license.html)\n[![QuestPDF License Terms](https://img.shields.io/badge/license%20terms-666666?style=for-the-badge)](https://www.questpdf.com/license/guide.html)\n\n<br>\n<br>\n\n## See a real-world example\n\nFollow our detailed tutorial and see how easy it is to generate a fully functional invoice with fewer than 250 lines of C# code.\n\n- Step-by-step guidance\n- Production-ready code\n- Best practices included\n\n<img width=\"300\" alt=\"Example Invoice\" src=\"https://github.com/user-attachments/assets/dd268fe2-e558-4b9a-944d-b2f41ce52940\" />\n\n[![Read Real-world Invoice Tutorial](https://img.shields.io/badge/read%20tutorial-0288D1?style=for-the-badge)](https://www.questpdf.com/invoice-tutorial.html)\n\n<br>\n<br>\n\n## Community QuestPDF\n\nWe are incredibly grateful to our .NET Community for their positive reviews and recommendations of the QuestPDF library. \nYour support and feedback are invaluable and motivate us to keep improving and expanding this project. \nThank you for helping us grow and reach more developers!\n\n### Nick Chapsas: The Easiest Way to Create PDFs in .NET\n\n[![Nick Chapsas The Easiest Way to Create PDFs in .NET](https://github.com/user-attachments/assets/5c7fc84b-65d6-4ec2-9cc2-b2acbc9764d0)](https://www.youtube.com/watch?v=_M0IgtGWnvE)\n\n### JetBrains: OSS Power-Ups: QuestPDF\n\n[![JetBrains OSS Power-Ups: QuestPDF](https://github.com/user-attachments/assets/3519b532-c2aa-430e-ab1b-f40edd3fa120)](https://www.youtube.com/watch?v=-iYvZvpLX0g)\n\n<br>\n<br>\n\n## Please help by giving a star ⭐\n\nGitHub stars guide developers toward great tools. If you find this project valuable, please give it a star – it helps the community and takes just a second! \n\n<img src=\"https://github.com/user-attachments/assets/cb7077b5-ebbf-493b-96c4-af6ae25eca56\" width=\"700\" />\n"
  },
  {
    "path": "Source/.config/dotnet-tools.json",
    "content": "{\n  \"version\": 1,\n  \"isRoot\": true,\n  \"tools\": {\n    \"dotnet-stryker\": {\n      \"version\": \"3.11.1\",\n      \"commands\": [\n        \"dotnet-stryker\"\n      ]\n    }\n  }\n}"
  },
  {
    "path": "Source/.config/stryker-config.json",
    "content": "{\n  \"stryker-config\":\n  {\n    \"solution\": \"../QuestPDF.sln\",\n    \"project\": \"QuestPDF/QuestPDF.csproj\",\n    \"test-projects\": [\"../QuestPDF.LayoutTests/QuestPDF.LayoutTests.csproj\"],\n    \"mutate\": [\"**/*Column.cs\"],\n    \"reporters\": [\n      \"progress\",\n      \"html\"\n    ],\n    \"disable-mix-mutants\": true,\n    \"disable-bail\": true\n  }\n}"
  },
  {
    "path": "Source/.editorconfig",
    "content": "# 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\n# You can modify the rules from these initially generated values to suit your own policies\n# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference\n[*.cs]\n\n\n#Core editorconfig formatting - indentation\n\n#use soft tabs (spaces) for indentation\nindent_style = space\n\n#Formatting - new line options\n\n#place catch statements on a new line\ncsharp_new_line_before_catch = true\n#place else statements on a new line\ncsharp_new_line_before_else = true\n#require members of anonymous types to be on separate lines\ncsharp_new_line_before_members_in_anonymous_types = true\n#require members of object intializers to be on separate lines\ncsharp_new_line_before_members_in_object_initializers = true\n#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)\ncsharp_new_line_before_open_brace =all\n\n#Formatting - organize using options\n\n#sort System.* using directives alphabetically, and place them before other usings\ndotnet_sort_system_directives_first = true\n\n#Formatting - spacing options\n\n#require NO space between a cast and the value\ncsharp_space_after_cast = false\n#require a space before the colon for bases or interfaces in a type declaration\ncsharp_space_after_colon_in_inheritance_clause = true\n#require a space after a keyword in a control flow statement such as a for loop\ncsharp_space_after_keywords_in_control_flow_statements = true\n#require a space before the colon for bases or interfaces in a type declaration\ncsharp_space_before_colon_in_inheritance_clause = true\n#remove space within empty argument list parentheses\ncsharp_space_between_method_call_empty_parameter_list_parentheses = false\n#remove space between method call name and opening parenthesis\ncsharp_space_between_method_call_name_and_opening_parenthesis = false\n#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call\ncsharp_space_between_method_call_parameter_list_parentheses = false\n#remove space within empty parameter list parentheses for a method declaration\ncsharp_space_between_method_declaration_empty_parameter_list_parentheses = false\n#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.\ncsharp_space_between_method_declaration_parameter_list_parentheses = false\n\n#Formatting - wrapping options\n\n#leave code block on single line\ncsharp_preserve_single_line_blocks = true\n\n#Style - Code block preferences\n\n#prefer no curly braces if allowed\ncsharp_prefer_braces = false:suggestion\n\n#Style - expression bodied member options\n\n#prefer block bodies for constructors\ncsharp_style_expression_bodied_constructors = false:suggestion\n#prefer block bodies for methods\ncsharp_style_expression_bodied_methods = false:suggestion\n#prefer expression-bodied members for properties\ncsharp_style_expression_bodied_properties = true:suggestion\n\n#Style - expression level options\n\n#prefer out variables to be declared inline in the argument list of a method call when possible\ncsharp_style_inlined_variable_declaration = true:suggestion\n#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them\ndotnet_style_predefined_type_for_member_access = true:suggestion\n\n#Style - Expression-level  preferences\n\n#prefer objects to be initialized using object initializers when possible\ndotnet_style_object_initializer = true:suggestion\n#prefer inferred anonymous type member names\ndotnet_style_prefer_inferred_anonymous_type_member_names = false:suggestion\n#prefer inferred tuple element names\ndotnet_style_prefer_inferred_tuple_names = true:suggestion\n\n#Style - implicit and explicit types\n\n#prefer var over explicit type in all cases, unless overridden by another code style rule\ncsharp_style_var_elsewhere = true:suggestion\n#prefer var is used to declare variables with built-in system types such as int\ncsharp_style_var_for_built_in_types = true:suggestion\n#prefer var when the type is already mentioned on the right-hand side of a declaration expression\ncsharp_style_var_when_type_is_apparent = true:suggestion\n\n#Style - language keyword and framework type options\n\n#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\ndotnet_style_predefined_type_for_locals_parameters_members = true:suggestion\n\n#Style - Miscellaneous preferences\n\n#prefer local functions over anonymous functions\ncsharp_style_pattern_local_over_anonymous_function = true:suggestion\n\n#Style - modifier options\n\n#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.\ndotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion\n\n#Style - Modifier preferences\n\n#when this rule is set to a list of modifiers, prefer the specified ordering.\ncsharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent\n\n#Style - Pattern matching\n\n#prefer pattern matching instead of is expression with type casts\ncsharp_style_pattern_matching_over_as_with_null_check = true:suggestion\n\n#Style - qualification options\n\n#prefer fields not to be prefaced with this. or Me. in Visual Basic\ndotnet_style_qualification_for_field = false:suggestion\n#prefer methods not to be prefaced with this. or Me. in Visual Basic\ndotnet_style_qualification_for_method = false:suggestion\n#prefer properties not to be prefaced with this. or Me. in Visual Basic\ndotnet_style_qualification_for_property = false:suggestion\n\n[*.{cs,vb}]\ntab_width=4\nindent_size=4"
  },
  {
    "path": "Source/QuestPDF/Build/QuestPDF.targets",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n    <ItemGroup>\n        <None Include=\"$(MSBuildThisFileDirectory)\\..\\LatoFont\\*.*\">\n            <Visible>$(TargetFramework.StartsWith('net4'))</Visible>\n            <Link>LatoFont\\%(RecursiveDir)%(Filename)%(Extension)</Link>\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n        </None>\n    </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF/Build/net4/QuestPDF.targets",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n    <ItemGroup>\n        <None Include=\"$(MSBuildThisFileDirectory)\\..\\..\\runtimes\\**\\*.*\">\n            <Link>runtimes\\%(RecursiveDir)%(Filename)%(Extension)</Link>\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n        </None>\n    </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF/Companion/CompanionExtensions.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Companion\n{\n    public static class CompanionExtensions\n    {\n        static CompanionExtensions()\n        {\n            LicenseChecker.ValidateLicense();\n        }\n\n        #if NET6_0_OR_GREATER\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"companion.supported\"]/*' />\n        public static void ShowInCompanion(this IDocument document, int port = 12500)\n        {\n            document.ShowInCompanionAsync(port).ConfigureAwait(true).GetAwaiter().GetResult();\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"companion.supported\"]/*' />\n        public static async Task ShowInCompanionAsync(this IDocument document, int port = 12500, CancellationToken cancellationToken = default)\n        {\n            Settings.EnableCaching = false;\n            Settings.EnableDebugging = true;\n            \n            if (document is MergedDocument)\n                throw new NotSupportedException(\"The QuestPDF Companion App does not currently support merged documents. Please use the tool with a single document at a time.\");\n            \n            var companionService = new CompanionService(port);\n            \n            using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n            companionService.OnCompanionStopped += () => cancellationTokenSource.Cancel();\n\n            await companionService.Connect();\n            companionService.StartRenderRequestedPageSnapshotsTask(cancellationToken);\n            await RefreshPreview();\n\n            HotReloadManager.UpdateApplicationRequested += (_, _) =>\n            {\n                CompanionService.IsDocumentHotReloaded = true;\n                RefreshPreview();\n            };\n            \n            await KeepApplicationAlive(cancellationTokenSource.Token);\n            \n            Task RefreshPreview()\n            {\n                try\n                {\n                    var pictures = DocumentGenerator.GenerateCompanionContent(document);\n                    return companionService.RefreshPreview(pictures);\n                }\n                catch (Exception exception)\n                {\n                    return companionService.InformAboutGenericException(exception);\n                }\n            }\n\n            async Task KeepApplicationAlive(CancellationToken cancellationToken)\n            {\n                while (true)\n                {\n                    if (cancellationToken.IsCancellationRequested)\n                        return;\n                \n                    await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);\n                }\n            }\n        }\n\n        #else\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"companion.notSupported\"]/*' />\n        public static void ShowInCompanion(this IDocument document, int port = 12500)\n        {\n            throw new Exception(\"The hot-reload feature requires .NET 6 or later.\");\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"companion.notSupported\"]/*' />\n        public static async Task ShowInCompanionAsync(this IDocument document, int port = 12500, CancellationToken cancellationToken = default)\n        {\n            throw new Exception(\"The hot-reload feature requires .NET 6 or later.\");\n        }\n\n        #endif\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Companion/CompanionModels.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Companion\n{\n    sealed class PageSnapshotIndex\n    {\n        public int PageIndex { get; set; }\n        public int ZoomLevel { get; set; }\n\n        public override string ToString() => $\"{ZoomLevel}/{PageIndex}\";\n    }\n    \n    static internal class CompanionCommands\n    {\n        internal sealed class Notify\n        {\n            private static readonly string CurrentClientId = Guid.NewGuid().ToString();\n            \n            public string ClientId => CurrentClientId;\n            public LicenseType License => Settings.License ?? LicenseType.Community;\n        }\n        \n        internal sealed class UpdateDocumentStructure\n        {\n            public bool IsDocumentHotReloaded { get; set; }\n            public ICollection<PageSize> Pages { get; set; }\n            public DocumentHierarchyElement Hierarchy { get; set; }\n    \n            public sealed class PageSize\n            {\n                public float Width { get; set; }\n                public float Height { get; set; }\n            }\n            \n            internal sealed record DocumentHierarchyElement\n            {\n                internal Element Element { get; set; }\n                \n                public string ElementType { get; set; }\n                public string? Hint { get; set; }\n                public string? SearchableContent { get; set; }\n                public bool IsSingleChildContainer { get; set; }\n                public ICollection<PageLocation> PageLocations { get; set; }\n                public ICollection<LayoutErrorMeasurement> LayoutErrorMeasurements { get; set; }\n                public ICollection<ElementProperty> Properties { get; set; }\n                public SourceCodePath? SourceCodeDeclarationPath { get; set; }\n                public ICollection<DocumentHierarchyElement> Children { get; set; }\n            }\n\n            internal sealed class PageLocation\n            {\n                public int PageNumber { get; init; }\n                public float Left { get; init; }\n                public float Top { get; init; }\n                public float Right { get; init; }\n                public float Bottom { get; init; }\n            }\n\n            internal sealed class LayoutErrorMeasurement\n            {\n                public int PageNumber { get; set; }\n                public ElementSize? AvailableSpace { get; set; }\n                public ElementSize? MeasurementSize { get; set; }\n                public SpacePlanType? SpacePlanType { get; set; }\n                public string? WrapReason { get; set; }\n                public bool IsLayoutErrorRootCause { get; set; }\n            }\n            \n            internal sealed class SourceCodePath\n            {\n                public string FilePath { get; set; }\n                public int LineNumber { get; set; }\n            }\n        }\n        \n        internal sealed class ProvideRenderedDocumentPage\n        {\n            public ICollection<RenderedPage> Pages { get; set; }\n\n            internal sealed class RenderedPage\n            {\n                public int PageIndex { get; set; }\n                public int ZoomLevel { get; set; }\n                public string ImageData { get; set; } // base64\n            }\n        }\n        \n        internal sealed class ShowGenericException\n        {\n            public GenericExceptionDetails Exception { get; set; }\n            \n            internal sealed class GenericExceptionDetails\n            {\n                public string Type { get; set; }\n                public string Message { get; set; }\n                public ICollection<StackFrame> StackTrace { get; set; }\n                public GenericExceptionDetails? InnerException { get; set; }\n            }\n            \n            internal sealed class StackFrame\n            {\n                public string CodeLocation { get; set; }\n                public string? FileName { get; set; }\n                public int? LineNumber { get; set; }\n            }\n        }\n\n        internal sealed class ElementSize\n        {\n            public float Width { get; set; }\n            public float Height { get; set; }\n        }\n        \n        internal sealed class ElementProperty\n        {\n            public string Label { get; set; }\n            public string Value { get; set; }\n        }\n\n        internal sealed class GetVersionCommandResponse\n        {\n            public ICollection<int> SupportedVersions { get; set; }\n        }\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Companion/CompanionService.cs",
    "content": "﻿#if NET6_0_OR_GREATER\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Net.Http;\nusing System.Net.Http.Json;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.DocumentCanvases;\n\nnamespace QuestPDF.Companion\n{\n    internal sealed class CompanionService\n    {\n        private int Port { get; }\n        private HttpClient HttpClient { get; }\n        \n        public event Action? OnCompanionStopped;\n\n        private const int RequiredCompanionApiVersion = 3;\n        \n        private static CompanionDocumentSnapshot? CurrentDocumentSnapshot { get; set; }\n\n        public static bool IsCompanionAttached { get; private set; }\n        public static bool IsDocumentHotReloaded { get; set; } = false;\n        \n        JsonSerializerOptions JsonSerializerOptions = new()\n        {\n            MaxDepth = 256,\n            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n            Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }\n        };\n        \n        public CompanionService(int port)\n        {\n            IsCompanionAttached = true;\n            \n            Port = port;\n            HttpClient = new()\n            {\n                BaseAddress = new Uri($\"http://localhost:{port}/\"), \n                Timeout = TimeSpan.FromSeconds(5)\n            };\n        }\n\n        public async Task Connect()\n        {\n            await CheckIfCompanionIsRunning();\n            await CheckCompanionVersionCompatibility();\n            StartNotifyPresenceTask();\n        }\n\n        private async Task CheckIfCompanionIsRunning()\n        {\n            try\n            {\n                using var result = await HttpClient.GetAsync(\"/ping\");\n                result.EnsureSuccessStatusCode();\n            }\n            catch\n            {\n                throw new Exception(\"Cannot connect to the QuestPDF Companion tool. Please ensure that the tool is running and the port is correct. Learn more: https://www.questpdf.com/companion/usage.html\");\n            }\n        }\n        \n        internal async Task StartNotifyPresenceTask()\n        {\n            while (true)\n            {\n                try\n                {\n                    using var result = await HttpClient.PostAsJsonAsync($\"/v{RequiredCompanionApiVersion}/notify\", new CompanionCommands.Notify(), JsonSerializerOptions);\n                }\n                catch\n                {\n                    \n                }\n                \n                await Task.Delay(TimeSpan.FromMilliseconds(250));\n            }\n        }\n        \n        private async Task CheckCompanionVersionCompatibility()\n        {\n            using var result = await HttpClient.GetAsync(\"/version\");\n            var response = await result.Content.ReadFromJsonAsync<CompanionCommands.GetVersionCommandResponse>();\n            \n            if (response.SupportedVersions.Contains(RequiredCompanionApiVersion))\n                return;\n            \n            throw new Exception($\"The QuestPDF Companion application is not compatible. Please install the QuestPDF Companion tool in a proper version.\");\n        }\n\n        public async Task RefreshPreview(CompanionDocumentSnapshot companionDocumentSnapshot)\n        {\n            // clean old state\n            if (CurrentDocumentSnapshot != null)\n            {\n                foreach (var companionPageSnapshot in CurrentDocumentSnapshot.Pictures)\n                    companionPageSnapshot.Picture.Dispose();\n            }\n            \n            // set new state\n            CurrentDocumentSnapshot = companionDocumentSnapshot;\n            \n            var documentStructure = new CompanionCommands.UpdateDocumentStructure\n            {\n                Hierarchy = companionDocumentSnapshot.Hierarchy.ImproveHierarchyStructure(),\n                IsDocumentHotReloaded = IsDocumentHotReloaded,\n                \n                Pages = companionDocumentSnapshot\n                    .Pictures\n                    .Select(x => new CompanionCommands.UpdateDocumentStructure.PageSize\n                    {\n                        Width = x.Size.Width,\n                        Height = x.Size.Height\n                    })\n                    .ToArray()\n            };\n\n            await HttpClient.PostAsJsonAsync($\"/v{RequiredCompanionApiVersion}/documentPreview/update\", documentStructure, JsonSerializerOptions);\n        }\n        \n        public void StartRenderRequestedPageSnapshotsTask(CancellationToken cancellationToken)\n        {\n            Task.Run(async () =>\n            {\n                while (!cancellationToken.IsCancellationRequested)\n                {\n                    try\n                    {\n                        await RenderRequestedPageSnapshots();\n                    }\n                    catch\n                    {\n                        await Task.Delay(TimeSpan.FromMilliseconds(250), cancellationToken);\n                    }\n                }\n            });\n        }\n\n        private async Task RenderRequestedPageSnapshots()\n        {\n            // get requests\n            var getRequestedSnapshots = await HttpClient.GetAsync($\"/v{RequiredCompanionApiVersion}/documentPreview/getRenderingRequests\");\n            getRequestedSnapshots.EnsureSuccessStatusCode();\n            \n            var requestedSnapshots = await getRequestedSnapshots.Content.ReadFromJsonAsync<ICollection<PageSnapshotIndex>>();\n            \n            if (!requestedSnapshots.Any())\n                return;\n            \n            if (CurrentDocumentSnapshot == null)\n                return;\n      \n            // render snapshots\n            if (!requestedSnapshots.Any())\n                return;\n\n            var renderingTasks = requestedSnapshots\n                .Select(index => Task.Run(() =>\n                {\n                    var image = CurrentDocumentSnapshot\n                        .Pictures\n                        .ElementAt(index.PageIndex)\n                        .RenderImage(index.ZoomLevel);\n\n                    return new CompanionCommands.ProvideRenderedDocumentPage.RenderedPage\n                    {\n                        PageIndex = index.PageIndex,\n                        ZoomLevel = index.ZoomLevel,\n                        ImageData = Convert.ToBase64String(image)\n                    };\n                }))\n                .ToList();\n\n            var renderedPages = await Task.WhenAll(renderingTasks);\n            var command = new CompanionCommands.ProvideRenderedDocumentPage { Pages = renderedPages };\n            await HttpClient.PostAsJsonAsync($\"/v{RequiredCompanionApiVersion}/documentPreview/provideRenderedImages\", command);\n        }\n        \n        internal async Task InformAboutGenericException(Exception exception)\n        {\n            var command = new CompanionCommands.ShowGenericException\n            {\n                Exception = Map(exception)\n            };\n            \n            await HttpClient.PostAsJsonAsync($\"/v{RequiredCompanionApiVersion}/genericException/show\", command, JsonSerializerOptions);\n            return;\n\n            static CompanionCommands.ShowGenericException.GenericExceptionDetails Map(Exception exception)\n            {\n                return new CompanionCommands.ShowGenericException.GenericExceptionDetails\n                {\n                    Type = exception.GetType().FullName ?? \"Unknown\", \n                    Message = exception.Message, \n                    StackTrace = exception.StackTrace.ParseStackTrace(),\n                    InnerException = exception.InnerException == null ? null : Map(exception.InnerException)\n                };\n            }\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Source/QuestPDF/Companion/Helpers.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.RegularExpressions;\nusing QuestPDF.Drawing.Proxy;\nusing QuestPDF.Elements;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Companion;\n\ninternal static class CompanionModelHelpers\n{\n    internal static CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement ExtractHierarchy(this Element container)\n    {\n        var layoutTree = container.ExtractElementsOfType<LayoutProxy>().Single();\n        return Traverse(layoutTree);\n        \n        CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement Traverse(TreeNode<LayoutProxy> node)\n        {\n            var child = node.Value.Child;\n\n            while (child is ElementProxy elementProxy)\n                child = elementProxy.Child;\n\n            if (child is Container)\n                return Traverse(node.Children.Single());\n            \n            var hierarchyElement = MapToHierarchyElement(node);\n            \n            // special case to optimize the hierarchy structure in the Companion App\n            if (child is StyledBox styledBox)\n            {\n                var customContentChildren = styledBox\n                    .GetCompanionCustomContent()\n                    .Select(x => hierarchyElement with { ElementType = x.Type, Hint = x.Hint })\n                    .ToArray();\n\n                if (customContentChildren.Length == 0)\n                    return hierarchyElement;\n                \n                for (var i = 0; i <= customContentChildren.Length - 2; i++)\n                    customContentChildren[i].Children = [customContentChildren[i + 1]];\n                \n                return customContentChildren.First();\n            }\n\n            return hierarchyElement;\n        }\n        \n        CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement MapToHierarchyElement(TreeNode<LayoutProxy> node)\n        {\n            var layout = node.Value;\n            var child = layout.Child;\n\n            while (child is ElementProxy proxy)\n                child = proxy.Child;\n                \n            return new CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement\n            {\n                Element = child,\n                ElementType = child.GetType().Name,\n                Hint = child.GetCompanionHint(),\n                SearchableContent = child.GetCompanionSearchableContent(),\n                PageLocations = layout.Snapshots,\n                SourceCodeDeclarationPath = GetSourceCodePath(child.CodeLocation),\n                LayoutErrorMeasurements = layout.LayoutErrorMeasurements,\n                IsSingleChildContainer = child is ContainerElement,\n                Properties = child.GetCompanionProperties()?.Select(x => new CompanionCommands.ElementProperty { Label = x.Key, Value = x.Value }).ToList() ?? [],\n                Children = node.Children.Select(Traverse).ToList()\n            };\n        }\n    }\n\n    private static CompanionCommands.UpdateDocumentStructure.SourceCodePath? GetSourceCodePath(SourceCodePath? path)\n    {\n        if (path == null)\n            return null;\n        \n        return new CompanionCommands.UpdateDocumentStructure.SourceCodePath\n        {\n            FilePath = path.Value.FilePath,\n            LineNumber = path.Value.LineNumber\n        };\n    }\n    \n    #if NET6_0_OR_GREATER\n    \n    internal static CompanionCommands.ShowGenericException.StackFrame[] ParseStackTrace(this string stackTrace)\n    {\n        var lines = stackTrace.Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries);\n        \n        var frames = new List<CompanionCommands.ShowGenericException.StackFrame>();\n\n        foreach (string line in lines)\n        {\n            var fullMatch = Regex.Match(line, @\"at\\s+(?<codeLocation>.+)\\s+in\\s(?<fileName>.+)\\s*:line\\s(?<lineNumber>\\d+)\");\n            var codeOnlyMatch = Regex.Match(line, @\"at\\s+(?<codeLocation>.+)\");\n\n            if (fullMatch.Success)\n            {\n                frames.Add(new CompanionCommands.ShowGenericException.StackFrame\n                {\n                    CodeLocation = fullMatch.Groups[\"codeLocation\"].Value,\n                    FileName = fullMatch.Groups[\"fileName\"].Value,\n                    LineNumber = int.Parse(fullMatch.Groups[\"lineNumber\"].Value)\n                });\n            }\n            else if (codeOnlyMatch.Success)\n            {\n                frames.Add(new CompanionCommands.ShowGenericException.StackFrame\n                {\n                    CodeLocation = codeOnlyMatch.Groups[\"codeLocation\"].Value\n                });\n            }\n        }\n\n        return frames.ToArray();\n    }\n\n    #endif\n    \n    internal static CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement ImproveHierarchyStructure(this CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement root)\n    {\n        var document = FindDocumentStructurePointersThat(root, x => x == DocumentStructureTypes.Document).Single();\n        document.IsSingleChildContainer = false;\n\n        var pages = FindDocumentStructurePointersThat(document, x => x == DocumentStructureTypes.Page).ToList();\n\n        foreach (var page in pages)\n        {\n            page.IsSingleChildContainer = false;\n            page.Children = FindDocumentStructurePointersThat(page, x => x is not (DocumentStructureTypes.Document or DocumentStructureTypes.Page)).ToList();\n        }\n        \n        document.Children = pages;\n\n        if (pages.Count == 1)\n            document.Children = pages.Single().Children;\n\n        return document;\n\n        ICollection<CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement> FindDocumentStructurePointersThat(CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement root, Predicate<DocumentStructureTypes> predicate)\n        {\n            var result = new List<CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement>();\n            Traverse(root);\n            return result;\n\n            void Traverse(CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement element)\n            {\n                if (element.Element is DebugPointer { Type: DebugPointerType.DocumentStructure } debugPointer && Enum.TryParse<DocumentStructureTypes>(debugPointer.Label, out var structureType) && predicate(structureType))\n                {\n                    result.Add(element);\n                    return;\n                }\n                \n                foreach (var child in element.Children)\n                    Traverse(child);\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Companion/HotReloadManager.cs",
    "content": "﻿#if NET6_0_OR_GREATER\n\nusing System;\nusing QuestPDF.Companion;\n\n[assembly: System.Reflection.Metadata.MetadataUpdateHandler(typeof(HotReloadManager))]\n\nnamespace QuestPDF.Companion\n{\n    /// <summary>\n    /// Helper to subscribe to hot reload notifications.\n    /// </summary>\n    internal static class HotReloadManager\n    {\n        public static event EventHandler? UpdateApplicationRequested;\n\n        public static void UpdateApplication(Type[]? _)\n        {\n            UpdateApplicationRequested?.Invoke(null, EventArgs.Empty);\n        }\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/QuestPDF/Companion/Previewer.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing QuestPDF.Companion;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Previewer;\n\npublic static class PreviewerExtensions\n{\n    private const string ObsoleteMessage = \"The Previewer application is no longer supprted. Please use a new QuestPDF Companion application by calling ShowInCompanion() or ShowInCompanionAsync() methods.\";\n    \n    #if NET6_0_OR_GREATER\n    \n    [Obsolete(ObsoleteMessage)]\n    [ExcludeFromCodeCoverage]\n    public static void ShowInPreviewer(this IDocument document, int port = 12500)\n    {\n        throw new NotImplementedException(ObsoleteMessage);\n    }\n    \n    [Obsolete(ObsoleteMessage)]\n    [ExcludeFromCodeCoverage]\n    public static Task ShowInPreviewerAsync(this IDocument document, int port = 12500, CancellationToken cancellationToken = default)\n    {\n        throw new NotImplementedException(ObsoleteMessage);\n    }\n    \n    #else\n\n    [Obsolete(ObsoleteMessage)]\n    [ExcludeFromCodeCoverage]\n    public static void ShowInPreviewer(this IDocument document, int port = 12500)\n    {\n        throw new NotSupportedException(ObsoleteMessage);\n    }\n\n    [Obsolete(ObsoleteMessage)]\n    [ExcludeFromCodeCoverage]\n    public static async Task ShowInPreviewerAsync(this IDocument document, int port = 12500, CancellationToken cancellationToken = default)\n    {\n        throw new NotSupportedException(ObsoleteMessage);\n    }\n\n    #endif\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentCanvases/CompanionDocumentCanvas.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing QuestPDF.Companion;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Drawing.DocumentCanvases\n{\n    internal sealed class CompanionPageSnapshot\n    {\n        public SkPicture Picture { get; set; }\n        public Size Size { get; set; }\n\n        public CompanionPageSnapshot(SkPicture picture, Size size)\n        {\n            Picture = picture;\n            Size = size;\n        }\n        \n        public byte[] RenderImage(int zoomLevel)\n        {\n            // prepare canvas\n            var scale = (float)Math.Pow(2, zoomLevel);\n            \n            using var bitmap = new SkBitmap((int)(Size.Width * scale), (int)(Size.Height * scale));\n            using var canvas = SkCanvas.CreateFromBitmap(bitmap);\n            canvas.Scale(scale, scale);\n            \n            // draw white background\n            using var backgroundPaint = new SkPaint();\n            backgroundPaint.SetSolidColor(Colors.White);\n            \n            var backgroundRect = new SkRect(0, 0, Size.Width, Size.Height);\n            canvas.DrawRectangle(backgroundRect, backgroundPaint);\n            \n            // draw content\n            canvas.DrawPicture(Picture);\n            \n            // export as image\n            using var encodedBitmapData = bitmap.EncodeAsJpeg(90);\n            return encodedBitmapData.ToBytes();\n        }\n    }\n    \n    internal sealed class CompanionDocumentSnapshot\n    {\n        public ICollection<CompanionPageSnapshot> Pictures { get; set; }\n        public CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement Hierarchy { get; set; }\n    }\n    \n    internal sealed class CompanionDocumentCanvas : IDocumentCanvas, IDisposable\n    {\n        private ProxyDrawingCanvas DrawingCanvas { get; } = new();\n        private Size CurrentPageSize { get; set; } = Size.Zero;\n\n        private ICollection<CompanionPageSnapshot> PageSnapshots { get; } = new List<CompanionPageSnapshot>();\n        \n        internal CompanionCommands.UpdateDocumentStructure.DocumentHierarchyElement Hierarchy { get; set; }\n\n        public CompanionDocumentSnapshot GetContent()\n        {\n            return new CompanionDocumentSnapshot\n            {\n                Pictures = PageSnapshots,\n                Hierarchy = Hierarchy\n            };\n        }\n\n        #region IDisposable\n        \n        ~CompanionDocumentCanvas()\n        {\n            this.WarnThatFinalizerIsReached();\n            Dispose();\n        }\n        \n        public void Dispose()\n        {\n            DrawingCanvas.Dispose();\n            GC.SuppressFinalize(this);\n        }\n        \n        #endregion\n        \n        #region IDocumentCanvas\n\n        public void SetSemanticTree(SemanticTreeNode? semanticTree)\n        {\n            \n        }\n        \n        public void BeginDocument()\n        {\n            PageSnapshots.Clear();\n        }\n\n        public void EndDocument()\n        {\n            \n        }\n\n        public void BeginPage(Size size)\n        {\n            CurrentPageSize = size;\n            \n            DrawingCanvas.Target = new SkiaDrawingCanvas(size.Width, size.Height);\n            DrawingCanvas.SetZIndex(0);\n        }\n\n        public void EndPage()\n        {\n            Debug.Assert(!CurrentPageSize.IsCloseToZero());\n            \n            using var pictureRecorder = new SkPictureRecorder();\n            using var canvas = pictureRecorder.BeginRecording(CurrentPageSize.Width, CurrentPageSize.Height);\n\n            using var snapshot = DrawingCanvas.GetSnapshot();\n            snapshot.DrawOnSkCanvas(canvas);\n            canvas.Save();\n            \n            var picture = pictureRecorder.EndRecording();\n            PageSnapshots.Add(new CompanionPageSnapshot(picture, CurrentPageSize));\n        }\n\n        \n        public IDrawingCanvas GetDrawingCanvas()\n        {\n            return DrawingCanvas;\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentCanvases/DiscardDocumentCanvas.cs",
    "content": "using QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Drawing.DocumentCanvases;\n\ninternal sealed class DiscardDocumentCanvas : IDocumentCanvas\n{\n    private DiscardDrawingCanvas DrawingCanvas { get; } = new();\n        \n    public void SetSemanticTree(SemanticTreeNode? semanticTree)\n    {\n            \n    }\n    \n    public void BeginDocument()\n    {\n            \n    }\n\n    public void EndDocument()\n    {\n            \n    }\n\n    public void BeginPage(Size size)\n    {\n            \n    }\n\n    public void EndPage()\n    {\n            \n    }\n\n    public IDrawingCanvas GetDrawingCanvas()\n    {\n        return DrawingCanvas;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentCanvases/ImageDocumentCanvas.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Drawing.DocumentCanvases\n{\n    internal sealed class ImageDocumentCanvas : IDocumentCanvas, IDisposable\n    {\n        private ImageGenerationSettings Settings { get; }\n        private SkBitmap Bitmap { get; set; }\n        \n        private SkCanvas? CurrentPageCanvas { get; set; }\n        private ProxyDrawingCanvas DrawingCanvas { get; } = new();\n        \n        internal ICollection<byte[]> Images { get; } = new List<byte[]>();\n        \n        public ImageDocumentCanvas(ImageGenerationSettings settings)\n        {\n            Settings = settings;\n        }\n\n        #region IDisposable\n        \n        ~ImageDocumentCanvas()\n        {\n            this.WarnThatFinalizerIsReached();\n            Dispose();\n        }\n        \n        public void Dispose()\n        {\n            CurrentPageCanvas?.Dispose();\n            Bitmap?.Dispose();\n            DrawingCanvas?.Dispose();\n            \n            GC.SuppressFinalize(this);\n        }\n        \n        #endregion\n        \n        #region IDocumentCanvas\n        \n        public void SetSemanticTree(SemanticTreeNode? semanticTree)\n        {\n            \n        }\n        \n        public void BeginDocument()\n        {\n            \n        }\n\n        public void EndDocument()\n        {\n            CurrentPageCanvas?.Dispose();\n            Bitmap?.Dispose();\n        }\n\n        public void BeginPage(Size size)\n        {\n            var scalingFactor = Settings.RasterDpi / (float) PageSizes.PointsPerInch;\n\n            Bitmap = new SkBitmap((int) (size.Width * scalingFactor), (int) (size.Height * scalingFactor));\n            CurrentPageCanvas = SkCanvas.CreateFromBitmap(Bitmap);\n            \n            CurrentPageCanvas.Scale(scalingFactor, scalingFactor);\n\n            if (Settings.ImageFormat == ImageFormat.Jpeg)\n            {\n                using var whitePaint = new SkPaint();\n                whitePaint.SetSolidColor(Colors.White);\n                \n                CurrentPageCanvas.DrawRectangle(new SkRect(0, 0, size.Width, size.Height), whitePaint);\n            }\n            \n            DrawingCanvas.Target = new SkiaDrawingCanvas(size.Width, size.Height);\n            DrawingCanvas.SetZIndex(0);\n        }\n\n        public void EndPage()\n        {\n            Debug.Assert(CurrentPageCanvas != null);\n            \n            using var documentPageSnapshot = DrawingCanvas.GetSnapshot();\n            documentPageSnapshot.DrawOnSkCanvas(CurrentPageCanvas);\n            \n            CurrentPageCanvas.Save();\n            CurrentPageCanvas.Dispose();\n            CurrentPageCanvas = null;\n            \n            using var imageData = EncodeBitmap();\n            var imageBytes = imageData.ToBytes();\n            Images.Add(imageBytes);\n            \n            Bitmap.Dispose();\n\n            SkData EncodeBitmap()\n            {\n                return Settings.ImageFormat switch\n                {\n                    ImageFormat.Jpeg => Bitmap.EncodeAsJpeg(Settings.ImageCompressionQuality.ToQualityValue()),\n                    ImageFormat.Png => Bitmap.EncodeAsPng(),\n                    ImageFormat.Webp => Bitmap.EncodeAsWebp(Settings.ImageCompressionQuality.ToQualityValue()),\n                    _ => throw new ArgumentOutOfRangeException()\n                };\n            }\n        }\n        \n        public IDrawingCanvas GetDrawingCanvas()\n        {\n            return DrawingCanvas;\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentCanvases/PdfDocumentCanvas.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Linq;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Drawing.DocumentCanvases\n{\n    internal sealed class PdfDocumentCanvas : IDocumentCanvas, IDisposable\n    {\n        private SkWriteStream WriteStream { get; }\n        private DocumentMetadata DocumentMetadata { get; }\n        private DocumentSettings DocumentSettings { get; }\n        private SkPdfTag? SemanticTag { get; set; }\n        \n        private SkDocument? Document { get; set; }\n        private SkCanvas? CurrentPageCanvas { get; set; }\n        private ProxyDrawingCanvas DrawingCanvas { get; } = new();\n        \n        public PdfDocumentCanvas(SkWriteStream stream, DocumentMetadata documentMetadata, DocumentSettings documentSettings)\n        {\n            WriteStream = stream;\n            DocumentMetadata = documentMetadata;\n            DocumentSettings = documentSettings;\n        }\n\n        private SkDocument CreatePdf()\n        {\n            // do not extract to another method, as it will cause the SkText objects\n            // to be disposed before the SkPdfDocument is created\n            using var title = new SkText(DocumentMetadata.Title);\n            using var author = new SkText(DocumentMetadata.Author);\n            using var subject = new SkText(DocumentMetadata.Subject);\n            using var keywords = new SkText(DocumentMetadata.Keywords);\n            using var creator = new SkText(DocumentMetadata.Creator);\n            using var producer = new SkText(DocumentMetadata.Producer);\n            using var language = new SkText(DocumentMetadata.Language);\n            \n            var internalMetadata = new SkPdfDocumentMetadata\n            {\n                Title = title,\n                Author = author,\n                Subject = subject,\n                Keywords = keywords,\n                Creator = creator,\n                Producer = producer,\n                Language = language,\n                \n                CreationDate = new SkDateTime(DocumentMetadata.CreationDate),\n                ModificationDate = new SkDateTime(DocumentMetadata.ModifiedDate),\n                \n                PDFA_Conformance = GetPDFAConformanceLevel(DocumentSettings.PDFA_Conformance),\n                PDFUA_Conformance = GetPDFUAConformanceLevel(DocumentSettings.PDFUA_Conformance),\n                \n                RasterDPI = DocumentSettings.ImageRasterDpi,\n                CompressDocument = DocumentSettings.CompressDocument,\n                \n                SemanticNodeRoot = SemanticTag?.Instance ?? IntPtr.Zero\n            };\n            \n            try\n            {\n                return SkPdfDocument.Create(WriteStream, internalMetadata);\n            }\n            catch (TypeInitializationException exception)\n            {\n                throw new InitializationException(\"PDF\", exception);\n            }\n        }\n\n        static Skia.PDFA_Conformance GetPDFAConformanceLevel(Infrastructure.PDFA_Conformance conformanceLevel)\n        {\n            return conformanceLevel switch\n            {\n                Infrastructure.PDFA_Conformance.None => Skia.PDFA_Conformance.None,\n                // Infrastructure.PDFA_Conformance.PDFA_1A => Skia.PDFA_Conformance.PDFA_1A,\n                // Infrastructure.PDFA_Conformance.PDFA_1B => Skia.PDFA_Conformance.PDFA_1B,\n                Infrastructure.PDFA_Conformance.PDFA_2A => Skia.PDFA_Conformance.PDFA_2A,\n                Infrastructure.PDFA_Conformance.PDFA_2B => Skia.PDFA_Conformance.PDFA_2B,\n                Infrastructure.PDFA_Conformance.PDFA_2U => Skia.PDFA_Conformance.PDFA_2U,\n                Infrastructure.PDFA_Conformance.PDFA_3A => Skia.PDFA_Conformance.PDFA_3A,\n                Infrastructure.PDFA_Conformance.PDFA_3B => Skia.PDFA_Conformance.PDFA_3B,\n                Infrastructure.PDFA_Conformance.PDFA_3U => Skia.PDFA_Conformance.PDFA_3U,\n                _ => throw new ArgumentOutOfRangeException(nameof(conformanceLevel), conformanceLevel, \"Unsupported PDF/A conformance level\")\n            };\n        }\n        \n        static Skia.PDFUA_Conformance GetPDFUAConformanceLevel(Infrastructure.PDFUA_Conformance conformanceLevel)\n        {\n            return conformanceLevel switch\n            {\n                Infrastructure.PDFUA_Conformance.None => Skia.PDFUA_Conformance.None,\n                Infrastructure.PDFUA_Conformance.PDFUA_1 => Skia.PDFUA_Conformance.PDFUA_1,\n                _ => throw new ArgumentOutOfRangeException(nameof(conformanceLevel), conformanceLevel, \"Unsupported PDF/UA conformance level\")\n            };\n        }\n        \n        #region IDisposable\n        \n        ~PdfDocumentCanvas()\n        {\n            this.WarnThatFinalizerIsReached();\n            Dispose();\n        }\n        \n        public void Dispose()\n        {\n            Document?.Dispose();\n            CurrentPageCanvas?.Dispose();\n            DrawingCanvas?.Dispose();\n            SemanticTag?.Dispose();\n            \n            // don't dispose WriteStream - its lifetime is managed externally\n            \n            GC.SuppressFinalize(this);\n        }\n        \n        #endregion\n        \n        #region IDocumentCanvas\n        \n        public void SetSemanticTree(SemanticTreeNode? semanticTree)\n        {\n            if (semanticTree == null)\n            {\n                SemanticTag?.Dispose();\n                SemanticTag = null;\n                return;\n            }\n            \n            SemanticTag = Convert(semanticTree);\n            \n            static SkPdfTag Convert(SemanticTreeNode node)\n            {\n                var result = SkPdfTag.Create(node.NodeId, node.Type, node.Alt, node.Lang);\n                var children = node.Children.Select(Convert).ToArray();\n                result.SetChildren(children);\n                \n                foreach (var nodeAttribute in node.Attributes)\n                    result.AddAttribute(nodeAttribute.Owner, nodeAttribute.Name, nodeAttribute.Value);\n                \n                return result;\n            }\n        }\n        \n        public void BeginDocument()\n        {\n            Document ??= CreatePdf();\n        }\n\n        public void EndDocument()\n        {\n            Document?.Close();\n            Document?.Dispose();\n        }\n\n        public void BeginPage(Size size)\n        {\n            CurrentPageCanvas = Document?.BeginPage(size.Width, size.Height);\n            \n            DrawingCanvas.Target = new SkiaDrawingCanvas(size.Width, size.Height);\n            DrawingCanvas.SetZIndex(0);\n        }\n\n        public void EndPage()\n        {\n            Debug.Assert(CurrentPageCanvas != null);\n            \n            using var documentPageSnapshot = DrawingCanvas.GetSnapshot();\n            documentPageSnapshot.DrawOnSkCanvas(CurrentPageCanvas);\n            \n            CurrentPageCanvas.Save();\n            CurrentPageCanvas.Dispose();\n            CurrentPageCanvas = null;\n            \n            Document.EndPage();\n        }\n        \n        public IDrawingCanvas GetDrawingCanvas()\n        {\n            return DrawingCanvas;\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentCanvases/SemanticDocumentCanvas.cs",
    "content": "using QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Drawing.DocumentCanvases;\n\ninternal sealed class SemanticDocumentCanvas : IDocumentCanvas\n{\n    private SemanticDrawingCanvas DrawingCanvas { get; } = new();\n        \n    public void SetSemanticTree(SemanticTreeNode? semanticTree)\n    {\n            \n    }\n    \n    public void BeginDocument()\n    {\n            \n    }\n\n    public void EndDocument()\n    {\n            \n    }\n\n    public void BeginPage(Size size)\n    {\n            \n    }\n\n    public void EndPage()\n    {\n            \n    }\n\n    public IDrawingCanvas GetDrawingCanvas()\n    {\n        return DrawingCanvas;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentCanvases/SvgDocumentCanvas.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Text;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Drawing.DocumentCanvases\n{\n    internal sealed class SvgDocumentCanvas : IDocumentCanvas, IDisposable\n    {\n        private SkCanvas? CurrentPageCanvas { get; set; }\n        private ProxyDrawingCanvas DrawingCanvas { get; } = new();\n        \n        private MemoryStream WriteStream { get; set; }\n        private SkWriteStream SkiaStream { get; set; }\n        internal ICollection<string> Images { get; } = new List<string>();\n        \n        #region IDisposable\n        \n        ~SvgDocumentCanvas()\n        {\n            this.WarnThatFinalizerIsReached();\n            Dispose();\n        }\n        \n        public void Dispose()\n        {\n            CurrentPageCanvas?.Dispose();\n            WriteStream?.Dispose();\n            SkiaStream?.Dispose();\n            DrawingCanvas?.Dispose();\n            \n            GC.SuppressFinalize(this);\n        }\n        \n        #endregion\n        \n        #region IDocumentCanvas\n        \n        public void SetSemanticTree(SemanticTreeNode? semanticTree)\n        {\n            \n        }\n        \n        public void BeginDocument()\n        {\n            \n        }\n\n        public void EndDocument()\n        {\n            CurrentPageCanvas?.Dispose();\n            WriteStream?.Dispose();\n            SkiaStream?.Dispose();\n        }\n\n        public void BeginPage(Size size)\n        {\n            WriteStream?.Dispose();\n            SkiaStream?.Dispose();\n            \n            WriteStream = new MemoryStream();\n            SkiaStream = new SkWriteStream(WriteStream);\n            CurrentPageCanvas = SkSvgCanvas.CreateSvg(size.Width, size.Height, SkiaStream);\n            \n            DrawingCanvas.Target = new SkiaDrawingCanvas(size.Width, size.Height);\n            DrawingCanvas.SetZIndex(0);\n        }\n\n        public void EndPage()\n        {\n            Debug.Assert(CurrentPageCanvas != null);\n\n            using var documentPageSnapshot = DrawingCanvas.GetSnapshot();\n            documentPageSnapshot.DrawOnSkCanvas(CurrentPageCanvas);\n            \n            CurrentPageCanvas.Save();\n            CurrentPageCanvas.Dispose();\n            CurrentPageCanvas = null;\n            \n            SkiaStream.Flush();\n\n            var data = WriteStream.ToArray();\n            var svgImage = Encoding.UTF8.GetString(data);\n            Images.Add(svgImage);\n            \n            SkiaStream.Dispose();\n            WriteStream.Dispose();\n        }\n        \n        public IDrawingCanvas GetDrawingCanvas()\n        {\n            return DrawingCanvas;\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentCanvases/XpsDocumentCanvas.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Drawing.DocumentCanvases\n{\n    internal sealed class XpsDocumentCanvas : IDocumentCanvas, IDisposable\n    {\n        private SkDocument Document { get; }\n        private SkCanvas? CurrentPageCanvas { get; set; }\n        private ProxyDrawingCanvas DrawingCanvas { get; } = new();\n        \n        public XpsDocumentCanvas(SkWriteStream stream, DocumentSettings documentSettings)\n        {\n            Document = CreateXps(stream, documentSettings);\n        }\n        \n        private static SkDocument CreateXps(SkWriteStream stream, DocumentSettings documentSettings)\n        {\n            try\n            {\n                return SkXpsDocument.Create(stream, documentSettings.ImageRasterDpi);\n            }\n            catch (TypeInitializationException exception)\n            {\n                throw new InitializationException(\"XPS\", exception);\n            }\n        }\n        \n        #region IDisposable\n        \n        ~XpsDocumentCanvas()\n        {\n            this.WarnThatFinalizerIsReached();\n            Dispose();\n        }\n        \n        public void Dispose()\n        {\n            Document?.Dispose();\n            CurrentPageCanvas?.Dispose();\n            DrawingCanvas?.Dispose();\n            \n            GC.SuppressFinalize(this);\n        }\n        \n        #endregion\n        \n        #region IDocumentCanvas\n        \n        public void SetSemanticTree(SemanticTreeNode? semanticTree)\n        {\n            \n        }\n        \n        public void BeginDocument()\n        {\n            \n        }\n\n        public void EndDocument()\n        {\n            Document?.Close();\n            Document?.Dispose();\n        }\n\n        public void BeginPage(Size size)\n        {\n            CurrentPageCanvas = Document?.BeginPage(size.Width, size.Height);\n            \n            DrawingCanvas.Target = new SkiaDrawingCanvas(size.Width, size.Height);\n            DrawingCanvas.SetZIndex(0);\n        }\n\n        public void EndPage()\n        {\n            Debug.Assert(CurrentPageCanvas != null);\n            \n            using var documentPageSnapshot = DrawingCanvas.GetSnapshot();\n            documentPageSnapshot.DrawOnSkCanvas(CurrentPageCanvas);\n            \n            CurrentPageCanvas.Save();\n            CurrentPageCanvas.Dispose();\n            CurrentPageCanvas = null;\n            \n            Document.EndPage();\n        }\n        \n        public IDrawingCanvas GetDrawingCanvas()\n        {\n            return DrawingCanvas;\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentContainer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Drawing\n{\n    internal sealed class DocumentContainer : IDocumentContainer\n    {\n        internal List<IComponent> Pages { get; set; } = [];\n        \n        internal Container Compose()\n        {\n            var container = new Container();\n            ComposeContainer(container);\n            return container;\n\n            void ComposeContainer(IContainer container)\n            {\n                if (Pages.Count == 0)\n                    Pages.Add(new Page());\n\n                container = container.DebugPointer(DebugPointerType.DocumentStructure, DocumentStructureTypes.Document.ToString());\n                \n                if (Pages.Count == 1)\n                {\n                    container.Component(Pages.First());\n                    return;\n                }\n\n                container\n                    .Column(column =>\n                    {\n                        Pages\n                            .SelectMany(x => new List<Action>()\n                            {\n                                () => column.Item().PageBreak(),\n                                () => column.Item().SemanticTag(\"Part\").Component(x)\n                            })\n                            .Skip(1)\n                            .ToList()\n                            .ForEach(x => x());\n                    });\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentGenerator.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Companion;\nusing QuestPDF.Drawing.DocumentCanvases;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Drawing.Proxy;\nusing QuestPDF.Elements;\nusing QuestPDF.Elements.Text;\nusing QuestPDF.Elements.Text.Items;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing PDFA_Conformance = QuestPDF.Infrastructure.PDFA_Conformance;\nusing PDFUA_Conformance = QuestPDF.Infrastructure.PDFUA_Conformance;\n\nnamespace QuestPDF.Drawing\n{\n    static class DocumentGenerator\n    {\n        static DocumentGenerator()\n        {\n            SkNativeDependencyCompatibilityChecker.Test();\n        }\n        \n        internal static void GeneratePdf(SkWriteStream stream, IDocument document)\n        {\n            LicenseChecker.ValidateLicense();\n            \n            var metadata = document.GetMetadata();\n            var settings = document.GetSettings();\n            \n            if (Settings.License == LicenseType.Evaluation)\n                metadata.Producer = \"QuestPDF (Evaluation Mode)\";\n\n            using var canvas = new PdfDocumentCanvas(stream, metadata, settings);\n            RenderDocument(canvas, document, settings);\n        }\n        \n        internal static void GenerateXps(SkWriteStream stream, IDocument document)\n        {\n            LicenseChecker.ValidateLicense();\n            \n            var settings = document.GetSettings();\n            using var canvas = new XpsDocumentCanvas(stream, settings);\n            RenderDocument(canvas, document, settings);\n        }\n        \n        internal static ICollection<byte[]> GenerateImages(IDocument document, ImageGenerationSettings imageGenerationSettings)\n        {\n            LicenseChecker.ValidateLicense();\n            \n            var documentSettings = document.GetSettings();\n            documentSettings.ImageRasterDpi = imageGenerationSettings.RasterDpi;\n            \n            using var canvas = new ImageDocumentCanvas(imageGenerationSettings);\n            RenderDocument(canvas, document, documentSettings);\n\n            return canvas.Images;\n        }\n        \n        internal static ICollection<string> GenerateSvg(IDocument document)\n        {\n            LicenseChecker.ValidateLicense();\n            \n            using var canvas = new SvgDocumentCanvas();\n            RenderDocument(canvas, document, document.GetSettings());\n\n            return canvas.Images;\n        }\n\n        internal static CompanionDocumentSnapshot GenerateCompanionContent(IDocument document)\n        {\n            using var canvas = new CompanionDocumentCanvas();\n            RenderDocument(canvas, document, DocumentSettings.Default);\n            return canvas.GetContent();\n        }\n\n        internal static void RenderDocument(IDocumentCanvas canvas, IDocument document, DocumentSettings settings)\n        {\n            if (document is MergedDocument mergedDocument)\n            {\n                RenderMergedDocument(canvas, mergedDocument, settings);\n                return;\n            }\n            \n            var semanticTreeManager = CreateSemanticTreeManager(settings);\n            var useOriginalImages = canvas is ImageDocumentCanvas;\n            var content = ConfigureContent(document, settings, semanticTreeManager, useOriginalImages);\n            \n            if (canvas is CompanionDocumentCanvas)\n                content.VisitChildren(x => x.CreateProxy(y => new LayoutProxy(y)));\n            \n            try\n            {\n                var pageContext = new PageContext();\n                RenderPass(pageContext, new SemanticDocumentCanvas(), content);\n                pageContext.ProceedToNextRenderingPhase();\n\n                canvas.ConfigureWithSemanticTree(semanticTreeManager);\n                \n                canvas.BeginDocument();\n                RenderPass(pageContext, canvas, content);\n                canvas.EndDocument();\n            \n                if (canvas is CompanionDocumentCanvas companionCanvas)\n                    companionCanvas.Hierarchy = content.ExtractHierarchy();\n            }\n            finally\n            {\n                content.ReleaseDisposableChildren();\n            }\n        }\n        \n        private static void RenderMergedDocument(IDocumentCanvas canvas, MergedDocument document, DocumentSettings settings)\n        {\n            var useOriginalImages = canvas is ImageDocumentCanvas;\n            \n            var sharedPageContent = new PageContext();\n            var useSharedPageContext = document.PageNumberStrategy == MergedDocumentPageNumberStrategy.Continuous;\n\n            var semanticTreeManager = CreateSemanticTreeManager(settings);\n            var semanticDocumentCanvas = new SemanticDocumentCanvas();\n            \n            var documentParts = Enumerable\n                .Range(0, document.Documents.Count)\n                .Select(index => new\n                {\n                    DocumentId = index,\n                    Content = ConfigureContent(document.Documents[index], settings, semanticTreeManager, useOriginalImages),\n                    PageContext = useSharedPageContext ? sharedPageContent : new PageContext()\n                })\n                .ToList();\n            \n            try\n            {\n                foreach (var documentPart in documentParts)\n                {\n                    documentPart.PageContext.SetDocumentId(documentPart.DocumentId);\n                    RenderPass(documentPart.PageContext, semanticDocumentCanvas, documentPart.Content);\n                }\n\n                foreach (var documentPart in documentParts)\n                    documentPart.PageContext.ProceedToNextRenderingPhase();\n                \n                canvas.ConfigureWithSemanticTree(semanticTreeManager);\n                \n                canvas.BeginDocument();\n\n                foreach (var documentPart in documentParts)\n                {\n                    documentPart.PageContext.SetDocumentId(documentPart.DocumentId);\n                    RenderPass(documentPart.PageContext, canvas, documentPart.Content);\n                    documentPart.Content.ReleaseDisposableChildren();\n                }\n                \n                canvas.EndDocument();\n            }\n            finally\n            {\n                documentParts.ForEach(x => x.Content.ReleaseDisposableChildren());\n            }\n        }\n\n        private static SemanticTreeManager? CreateSemanticTreeManager(DocumentSettings settings)\n        {\n            return IsDocumentSemanticAware() ? new SemanticTreeManager() : null;\n\n            bool IsDocumentSemanticAware()\n            {\n                if (settings.PDFUA_Conformance is not PDFUA_Conformance.None)\n                    return true;\n\n                //if (settings.PDFA_Conformance is PDFA_Conformance.PDFA_1A or PDFA_Conformance.PDFA_2A or PDFA_Conformance.PDFA_3A)\n                if (settings.PDFA_Conformance is PDFA_Conformance.PDFA_2A or PDFA_Conformance.PDFA_3A)\n                    return true;\n\n                return false;\n            }\n        }\n\n        private static void ConfigureWithSemanticTree(this IDocumentCanvas canvas, SemanticTreeManager? semanticTreeManager)\n        {\n            if (semanticTreeManager == null) \n                return;\n            \n            var semanticTree = semanticTreeManager.GetSemanticTree();\n            semanticTreeManager.Reset();\n            canvas.SetSemanticTree(semanticTree);\n        }\n\n        private static Container ConfigureContent(IDocument document, DocumentSettings settings, SemanticTreeManager? semanticTreeManager, bool useOriginalImages)\n        {\n            var container = new DocumentContainer();\n            document.Compose(container);\n            \n            var content = container.Compose();\n            \n            content.ApplyInheritedAndGlobalTexStyle(TextStyle.Default);\n            content.ApplyContentDirection(settings.ContentDirection);\n            content.ApplyDefaultImageConfiguration(settings.ImageRasterDpi, settings.ImageCompressionQuality, useOriginalImages);\n\n            if (Settings.EnableCaching)\n                content.ApplyCaching();\n            \n            if (semanticTreeManager != null)\n            {\n                content.ApplySemanticParagraphs();\n                content.InjectSemanticTreeManager(semanticTreeManager);\n            }\n            \n            return content;\n        }\n\n        private static void RenderPass(PageContext pageContext, IDocumentCanvas canvas, ContainerElement content)\n        {\n            content.InjectDependencies(pageContext, canvas.GetDrawingCanvas());\n            content.VisitChildren(x => (x as IStateful)?.ResetState(hardReset: true));\n\n            while(true)\n            {\n                pageContext.IncrementPageNumber();\n                var spacePlan = content.Measure(Size.Max);\n\n                if (spacePlan.Type == SpacePlanType.Wrap)\n                {\n                    pageContext.DecrementPageNumber();\n                    canvas.EndDocument();\n\n                    #if NET6_0_OR_GREATER\n                    if (!CompanionService.IsCompanionAttached)\n                        ThrowLayoutException();\n                    #else\n                    ThrowLayoutException();\n                    #endif\n                    \n                    ApplyLayoutDebugging();\n                }\n\n                try\n                {\n                    canvas.BeginPage(spacePlan);\n                    content.Draw(spacePlan);\n                }\n                catch (Exception exception)\n                {\n                    canvas.EndDocument();\n                    throw new DocumentDrawingException(\"An exception occured during document drawing.\", exception);\n                }\n\n                canvas.EndPage();\n\n                if (spacePlan.Type == SpacePlanType.FullRender)\n                    break;\n            }\n            \n            void ApplyLayoutDebugging()\n            {\n                content.VisitChildren(x => (x as SnapshotCacheRecorderProxy)?.Dispose());\n                content.RemoveExistingProxiesOfType<SnapshotCacheRecorderProxy>();\n\n                content.ApplyLayoutOverflowDetection();\n                content.Measure(Size.Max);\n\n                var overflowState = content.ExtractElementsOfType<OverflowDebuggingProxy>().Single();\n                overflowState.StopMeasuring();\n                overflowState.TryToFixTheLayoutOverflowIssue();\n                \n                content.ApplyContentDirection();\n                content.InjectDependencies(pageContext, canvas.GetDrawingCanvas());\n\n                content.VisitChildren(x => (x as LayoutProxy)?.CaptureLayoutErrorMeasurement());\n                content.RemoveExistingProxiesOfType<OverflowDebuggingProxy>();\n            }\n            \n            void ThrowLayoutException()\n            {\n                var newLine = \"\\n\";\n                var newParagraph = newLine + newLine;\n                \n                const string debuggingSettingsName = $\"{nameof(QuestPDF)}.{nameof(Settings)}.{nameof(Settings.EnableDebugging)}\";\n\n                var message =\n                    $\"The provided document content contains conflicting size constraints. \" +\n                    $\"For example, some elements may require more space than is available. {newParagraph}\";\n                \n                if (Settings.EnableDebugging)\n                {\n                    var (ancestors, layout) = GenerateLayoutExceptionDebuggingInfo();\n\n                    var ancestorsText = ancestors.FormatAncestors();\n                    var layoutText = layout.FormatLayoutSubtree();\n\n                    message +=\n                        $\"The layout issue is likely present in the following part of the document: {newParagraph}{ancestorsText}{newParagraph}\" +\n                        $\"To learn more, please analyse the document measurement of the problematic location: {newParagraph}{layoutText}\" +\n                        $\"{LayoutDebugging.LayoutVisualizationLegend}{newParagraph}\" +\n                        $\"This detailed information is generated because you run the application with a debugger attached or with the {debuggingSettingsName} flag set to true. \";\n                }\n                else\n                {\n                    message +=\n                        $\"To further investigate the location of the root cause, please run the application with a debugger attached or set the {debuggingSettingsName} flag to true. \" +\n                        $\"The library will generate additional debugging information such as probable code problem location and detailed layout measurement overview.\";\n                }\n                \n                throw new DocumentLayoutException(message);\n            }\n            \n            (ICollection<Element> ancestors, TreeNode<OverflowDebuggingProxy> layout) GenerateLayoutExceptionDebuggingInfo()\n            {\n                content.RemoveExistingProxies();\n                content.ApplyLayoutOverflowDetection();\n                content.Measure(Size.Max);\n                \n                var overflowState = content.ExtractElementsOfType<OverflowDebuggingProxy>().Single();\n                overflowState.StopMeasuring();\n                overflowState.TryToFixTheLayoutOverflowIssue();\n\n                var rootCause = overflowState.FindLayoutOverflowVisualizationNodes().First();\n                \n                var ancestors = rootCause\n                    .ExtractAncestors()\n                    .Select(x => x.Value.Child)\n                    .Where(x => x is DebugPointer or SourceCodePointer)\n                    .Reverse()\n                    .ToArray();\n\n                var layout = rootCause\n                    .ExtractAncestors()\n                    .First(x => x.Value.Child is SourceCodePointer or DebugPointer)\n                    .Children\n                    .First();\n\n                return (ancestors, layout);\n            }\n        }\n\n        internal static void InjectSemanticTreeManager(this Element content, SemanticTreeManager semanticTreeManager)\n        {\n            content.VisitChildren(x =>\n            {\n                if (x is ISemanticAware semanticAware)\n                {\n                    semanticAware.SemanticTreeManager = semanticTreeManager;\n                }\n                else if (x is TextBlock textBlock)\n                {\n                    foreach (var textBlockElement in textBlock.Items.OfType<TextBlockElement>())\n                    {\n                        textBlockElement.Element.InjectSemanticTreeManager(semanticTreeManager);\n                    }\n                }\n            });\n        }\n        \n        internal static void InjectDependencies(this Element content, IPageContext pageContext, IDrawingCanvas canvas)\n        {\n            content.VisitChildren(x =>\n            {\n                if (x == null)\n                    return;\n                \n                x.PageContext = pageContext;\n                x.Canvas = canvas;\n            });\n        }\n        \n        internal static void ApplyCaching(this Element? content)\n        {\n            var canApplyCaching = Traverse(content);\n            \n            if (canApplyCaching)\n                content?.CreateProxy(x => new SnapshotCacheRecorderProxy(x));\n\n            // returns true if can apply caching\n            bool Traverse(Element? content)\n            {\n                if (content is TextBlock textBlock)\n                {\n                    foreach (var textBlockItem in textBlock.Items)\n                    {\n                        if (textBlockItem is TextBlockPageNumber)\n                            return false;\n                        \n                        if (textBlockItem is TextBlockElement textBlockElement && !Traverse(textBlockElement.Element))\n                            return false;\n                    }\n\n                    return true;\n                }\n\n                if (content is Lazy lazy)\n                    return lazy.IsCacheable;\n\n                if (content is DynamicHost)\n                    return false;\n                \n                if (content is ContainerElement containerElement)\n                    return Traverse(containerElement.Child);\n\n                if (content is MultiColumn multiColumn)\n                {\n                    var multiColumnSupportsCaching = Traverse(multiColumn.Content) && Traverse(multiColumn.Spacer);\n                    \n                    multiColumn.Content.RemoveExistingProxies();\n                    multiColumn.Spacer.RemoveExistingProxies();\n                    \n                    return multiColumnSupportsCaching;\n                }\n\n                var canApplyCachingPerChild = content.GetChildren().Select(Traverse).ToArray();\n                \n                if (canApplyCachingPerChild.All(x => x))\n                    return true;\n\n                if (content is Row row && row.Items.Any(x => x.Type == RowItemType.Auto))\n                    return false;\n\n                var childIndex = 0;\n                \n                content.CreateProxy(x =>\n                {\n                    var canApplyCaching = canApplyCachingPerChild[childIndex];\n                    childIndex++;\n\n                    return canApplyCaching ? new SnapshotCacheRecorderProxy(x) : x;\n                });\n                \n                return false;\n            }\n        }\n        \n        internal static void ApplyContentDirection(this Element? content, ContentDirection? direction = null)\n        {\n            if (content == null)\n                return;\n\n            if (content is ContentDirectionSetter contentDirectionSetter)\n            {\n                ApplyContentDirection(contentDirectionSetter.Child, contentDirectionSetter.ContentDirection);\n                return;\n            }\n\n            if (content is IContentDirectionAware contentDirectionAware)\n                contentDirectionAware.ContentDirection = direction ?? contentDirectionAware.ContentDirection;\n            \n            foreach (var child in content.GetChildren())\n                ApplyContentDirection(child, direction);\n        }\n        \n        internal static void ApplyDefaultImageConfiguration(this Element? content, int imageRasterDpi, ImageCompressionQuality imageCompressionQuality, bool useOriginalImages)\n        {\n            content.VisitChildren(x =>\n            {\n                if (x is QuestPDF.Elements.Image image)\n                {\n                    image.TargetDpi ??= imageRasterDpi;\n                    image.CompressionQuality ??= imageCompressionQuality;\n                    image.UseOriginalImage |= useOriginalImages;\n                }\n\n                if (x is QuestPDF.Elements.DynamicImage dynamicImage)\n                {\n                    dynamicImage.TargetDpi ??= imageRasterDpi;\n                    dynamicImage.CompressionQuality ??= imageCompressionQuality;\n                    dynamicImage.UseOriginalImage |= useOriginalImages;\n                }\n\n                if (x is DynamicHost dynamicHost)\n                {\n                    dynamicHost.ImageTargetDpi ??= imageRasterDpi;\n                    dynamicHost.ImageCompressionQuality ??= imageCompressionQuality;\n                    dynamicHost.UseOriginalImage |= useOriginalImages;\n                }\n                \n                if (x is Lazy lazy)\n                {\n                    lazy.ImageTargetDpi ??= imageRasterDpi;\n                    lazy.ImageCompressionQuality ??= imageCompressionQuality;\n                    lazy.UseOriginalImage |= useOriginalImages;\n                }\n\n                if (x is TextBlock textBlock)\n                {\n                    foreach (var textBlockElement in textBlock.Items.OfType<TextBlockElement>())\n                    {\n                        textBlockElement.Element.ApplyDefaultImageConfiguration(imageRasterDpi, imageCompressionQuality, useOriginalImages);\n                    }\n                }\n            });\n        }\n\n        internal static void ApplyInheritedAndGlobalTexStyle(this Element? content, TextStyle documentDefaultTextStyle)\n        {\n            if (content == null)\n                return;\n            \n            if (content is TextBlock textBlock)\n            {\n                textBlock.DefaultTextStyle = textBlock.DefaultTextStyle.ApplyInheritedStyle(documentDefaultTextStyle).ApplyGlobalStyle();\n                \n                foreach (var textBlockItem in textBlock.Items)\n                {\n                    if (textBlockItem is TextBlockSpan textSpan)\n                        textSpan.Style = textSpan.Style.ApplyInheritedStyle(documentDefaultTextStyle).ApplyGlobalStyle();\n                    \n                    if (textBlockItem is TextBlockElement textElement)\n                        ApplyInheritedAndGlobalTexStyle(textElement.Element, documentDefaultTextStyle);\n                }\n                \n                return;\n            }\n\n            if (content is DynamicHost dynamicHost)\n                dynamicHost.TextStyle = dynamicHost.TextStyle.ApplyInheritedStyle(documentDefaultTextStyle);\n            \n            if (content is Lazy lazy)\n                lazy.TextStyle = lazy.TextStyle.ApplyInheritedStyle(documentDefaultTextStyle);\n            \n            if (content is DefaultTextStyle defaultTextStyleElement)\n               documentDefaultTextStyle = defaultTextStyleElement.TextStyle.ApplyInheritedStyle(documentDefaultTextStyle);\n\n            if (content is ContainerElement containerElement)\n            {\n                ApplyInheritedAndGlobalTexStyle(containerElement.Child, documentDefaultTextStyle);\n            }\n            else\n            {\n                foreach (var child in content.GetChildren())\n                    ApplyInheritedAndGlobalTexStyle(child, documentDefaultTextStyle);\n            }\n        }\n\n        internal static void ApplySemanticParagraphs(this Element root)\n        {\n            var isFooterContext = false;\n            \n            Traverse(root);\n            \n            void Traverse(Element element)\n            {\n                if (element is SemanticTag { TagType: \"H\" or \"H1\" or \"H2\" or \"H3\" or \"H4\" or \"H5\" or \"H6\" or \"P\" or \"Lbl\" })\n                {\n                    return;\n                }\n                else if (element is ArtifactTag)\n                {\n                    // ignore all Text elements that are marked as artifacts\n                }\n                else if (element is DebugPointer { Type: DebugPointerType.DocumentStructure, Label: nameof(DocumentStructureTypes.Footer) } debugPointer)\n                {\n                    isFooterContext = true;\n                    Traverse(debugPointer.Child);\n                    isFooterContext = false;\n                }\n                else if (element is ContainerElement container)\n                {\n                    if (container.Child is TextBlock textBlock)\n                    {\n                        var textBlockContainsPageNumber = textBlock.Items.Any(x => x is TextBlockPageNumber);\n\n                        if (isFooterContext && textBlockContainsPageNumber)\n                        {\n                            container.CreateProxy(x => new ArtifactTag\n                            {\n                                Child = x,\n                                Id = SkSemanticNodeSpecialId.PaginationArtifact\n                            });\n                        }\n                        else\n                        {\n                            container.CreateProxy(x => new SemanticTag\n                            {\n                                Child = x,\n                                TagType = \"P\"\n                            });\n                        }\n                    }\n                    else\n                    {\n                        Traverse(container.Child);\n                    }\n                }\n                else\n                {\n                    foreach (var child in element.GetChildren())\n                        Traverse(child);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Drawing/DocumentPageSnapshot.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Drawing;\n\ninternal class DocumentPageSnapshot : IDisposable\n{\n    public List<LayerSnapshot> Layers { get; init; }\n    \n    ~DocumentPageSnapshot()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        foreach (var layer in Layers)\n            layer.Picture.Dispose();\n\n        Layers.Clear();\n        GC.SuppressFinalize(this);\n    }\n    \n    public class LayerSnapshot\n    {\n        public int ZIndex { get; init; }\n        public SkPicture Picture { get; init; }\n    }\n\n    public void DrawOnSkCanvas(SkCanvas canvas)\n    {\n        foreach (var layerSnapshot in Layers.OrderBy(x => x.ZIndex))\n            canvas.DrawPicture(layerSnapshot.Picture);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DrawingCanvases/DiscardDrawingCanvas.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Numerics;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Drawing.DrawingCanvases\n{\n    internal sealed class DiscardDrawingCanvas : IDrawingCanvas\n    {\n        private Stack<Matrix4x4> MatrixStack { get; } = new();\n        private Matrix4x4 CurrentMatrix { get; set; } = Matrix4x4.Identity;\n        private int CurrentZIndex { get; set; } = 0;\n        \n        public DocumentPageSnapshot GetSnapshot()\n        {\n            return new DocumentPageSnapshot();\n        }\n\n        public void DrawSnapshot(DocumentPageSnapshot snapshot)\n        {\n            \n        }\n\n        public void Save()\n        {\n            MatrixStack.Push(CurrentMatrix);\n        }\n\n        public void Restore()\n        {\n            CurrentMatrix = MatrixStack.Pop();\n        }\n\n        public void SetZIndex(int index)\n        {\n            CurrentZIndex = index;\n        }\n\n        public int GetZIndex()\n        {\n            return CurrentZIndex;\n        }\n        \n        public SkCanvasMatrix GetCurrentMatrix()\n        {\n            return SkCanvasMatrix.FromMatrix4x4(CurrentMatrix);\n        }\n\n        public void SetMatrix(SkCanvasMatrix matrix)\n        {\n            CurrentMatrix = matrix.ToMatrix4x4();\n        }\n\n        public void Translate(Position vector)\n        {\n            CurrentMatrix = Matrix4x4.CreateTranslation(vector.X, vector.Y, 0) * CurrentMatrix;\n        }\n        \n        public void Scale(float scaleX, float scaleY)\n        {\n            CurrentMatrix = Matrix4x4.CreateScale(scaleX, scaleY, 1) * CurrentMatrix;\n        }\n        \n        public void Rotate(float angle)\n        {\n            CurrentMatrix = Matrix4x4.CreateRotationZ((float)Math.PI * angle / 180f) * CurrentMatrix;\n        }\n\n        public void DrawLine(Position start, Position end, SkPaint paint)\n        {\n            \n        }\n\n        public void DrawRectangle(Position vector, Size size, SkPaint paint)\n        {\n            \n        }\n\n        public void DrawComplexBorder(SkRoundedRect innerRect, SkRoundedRect outerRect, SkPaint paint)\n        {\n            \n        }\n        \n        public void DrawShadow(SkRoundedRect shadowRect, SkBoxShadow shadow)\n        {\n            \n        }\n        \n        public void DrawParagraph(SkParagraph paragraph, int lineFrom, int lineTo)\n        {\n            \n        }\n\n        public void DrawImage(SkImage image, Size size)\n        {\n            \n        }\n\n        public void DrawPicture(SkPicture picture)\n        {\n            \n        }\n\n        public void DrawSvgPath(string path, Color color)\n        {\n            \n        }\n\n        public void DrawSvg(SkSvgImage svgImage, Size size)\n        {\n            \n        }\n\n        public void DrawOverflowArea(SkRect area)\n        {\n            \n        }\n\n        public void ClipOverflowArea(SkRect availableSpace, SkRect requiredSpace)\n        {\n            \n        }\n\n        public void ClipRectangle(SkRect clipArea)\n        {\n            \n        }\n        \n        public void ClipRoundedRectangle(SkRoundedRect clipArea)\n        {\n            \n        }\n        \n        public void DrawHyperlink(Size size, string url, string? description)\n        {\n           \n        }\n\n        public void DrawSectionLink(Size size, string sectionName, string? description)\n        {\n            \n        }\n\n        public void DrawSection(string sectionName)\n        {\n            \n        }\n        \n        public int GetSemanticNodeId()\n        {\n            return 0;\n        }\n        \n        public void SetSemanticNodeId(int nodeId)\n        {\n            \n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DrawingCanvases/ProxyDrawingCanvas.cs",
    "content": "using System;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Drawing.DrawingCanvases;\n\ninternal sealed class ProxyDrawingCanvas : IDrawingCanvas, IDisposable\n{\n    public IDrawingCanvas Target { get; set; }\n\n    #region IDisposable\n    \n    ~ProxyDrawingCanvas()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        (Target as IDisposable)?.Dispose();\n        GC.SuppressFinalize(this);\n    }\n    \n    #endregion\n    \n    #region IDrawingCanvas\n    \n    public DocumentPageSnapshot GetSnapshot()\n    {\n        return Target.GetSnapshot();\n    }\n\n    public void DrawSnapshot(DocumentPageSnapshot snapshot)\n    {\n        Target.DrawSnapshot(snapshot);\n    }\n\n    public void Save()\n    {\n        Target.Save();\n    }\n\n    public void Restore()\n    {\n        Target.Restore();\n    }\n\n    public void SetZIndex(int index)\n    {\n        Target.SetZIndex(index);\n    }\n\n    public int GetZIndex()\n    {\n        return Target.GetZIndex();\n    }\n    \n    public SkCanvasMatrix GetCurrentMatrix()\n    {\n        return Target.GetCurrentMatrix();\n    }\n\n    public void SetMatrix(SkCanvasMatrix matrix)\n    {\n        Target.SetMatrix(matrix);\n    }\n    \n    public void Translate(Position vector)\n    {\n        Target.Translate(vector);\n    }\n    \n    public void Scale(float scaleX, float scaleY)\n    {\n        Target.Scale(scaleX, scaleY);\n    }\n    \n    public void Rotate(float angle)\n    {\n        Target.Rotate(angle);\n    }\n\n    public void DrawLine(Position start, Position end, SkPaint paint)\n    {\n        Target.DrawLine(start, end, paint);\n    }\n    \n    public void DrawRectangle(Position vector, Size size, SkPaint paint)\n    {\n        Target.DrawRectangle(vector, size, paint);\n    }\n    \n    public void DrawComplexBorder(SkRoundedRect innerRect, SkRoundedRect outerRect, SkPaint paint)\n    {\n        Target.DrawComplexBorder(innerRect, outerRect, paint);\n    }\n    \n    public void DrawShadow(SkRoundedRect shadowRect, SkBoxShadow shadow)\n    {\n        Target.DrawShadow(shadowRect, shadow);\n    }\n\n    public void DrawParagraph(SkParagraph paragraph, int lineFrom, int lineTo)\n    {\n        Target.DrawParagraph(paragraph, lineFrom, lineTo);\n    }\n\n    public void DrawImage(SkImage image, Size size)\n    {\n        Target.DrawImage(image, size);\n    }\n\n    public void DrawPicture(SkPicture picture)\n    {\n        Target.DrawPicture(picture);\n    }\n\n    public void DrawSvgPath(string path, Color color)\n    {\n        Target.DrawSvgPath(path, color);\n    }\n\n    public void DrawSvg(SkSvgImage svgImage, Size size)\n    {\n        Target.DrawSvg(svgImage, size);\n    }\n\n    public void DrawOverflowArea(SkRect area)\n    {\n        Target.DrawOverflowArea(area);\n    }\n\n    public void ClipOverflowArea(SkRect availableSpace, SkRect requiredSpace)\n    {\n        Target.ClipOverflowArea(availableSpace, requiredSpace);\n    }\n\n    public void ClipRectangle(SkRect clipArea)\n    {\n        Target.ClipRectangle(clipArea);\n    }\n    \n    public void ClipRoundedRectangle(SkRoundedRect clipArea)\n    {\n        Target.ClipRoundedRectangle(clipArea);\n    }\n\n    public void DrawHyperlink(Size size, string url, string? description)\n    {\n        Target.DrawHyperlink(size, url, description);\n    }\n\n    public void DrawSectionLink(Size size, string sectionName, string? description)\n    {\n        Target.DrawSectionLink(size, sectionName, description);\n    }\n\n    public void DrawSection(string sectionName)\n    {\n        Target.DrawSection(sectionName);\n    }\n    \n    public int GetSemanticNodeId()\n    {\n        return Target.GetSemanticNodeId();\n    }\n    \n    public void SetSemanticNodeId(int nodeId)\n    {\n        Target.SetSemanticNodeId(nodeId);\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DrawingCanvases/SemanticDrawingCanvas.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Numerics;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Drawing.DrawingCanvases\n{\n    internal sealed class SemanticDrawingCanvas : IDrawingCanvas\n    {\n        private Stack<Matrix4x4> MatrixStack { get; } = new();\n        private Matrix4x4 CurrentMatrix { get; set; } = Matrix4x4.Identity;\n        private int CurrentZIndex { get; set; } = 0;\n        \n        public DocumentPageSnapshot GetSnapshot()\n        {\n            return new DocumentPageSnapshot();\n        }\n\n        public void DrawSnapshot(DocumentPageSnapshot snapshot)\n        {\n            \n        }\n\n        public void Save()\n        {\n            MatrixStack.Push(CurrentMatrix);\n        }\n\n        public void Restore()\n        {\n            CurrentMatrix = MatrixStack.Pop();\n        }\n\n        public void SetZIndex(int index)\n        {\n            CurrentZIndex = index;\n        }\n\n        public int GetZIndex()\n        {\n            return CurrentZIndex;\n        }\n        \n        public SkCanvasMatrix GetCurrentMatrix()\n        {\n            return SkCanvasMatrix.FromMatrix4x4(CurrentMatrix);\n        }\n\n        public void SetMatrix(SkCanvasMatrix matrix)\n        {\n            CurrentMatrix = matrix.ToMatrix4x4();\n        }\n\n        public void Translate(Position vector)\n        {\n            CurrentMatrix = Matrix4x4.CreateTranslation(vector.X, vector.Y, 0) * CurrentMatrix;\n        }\n        \n        public void Scale(float scaleX, float scaleY)\n        {\n            CurrentMatrix = Matrix4x4.CreateScale(scaleX, scaleY, 1) * CurrentMatrix;\n        }\n        \n        public void Rotate(float angle)\n        {\n            CurrentMatrix = Matrix4x4.CreateRotationZ((float)Math.PI * angle / 180f) * CurrentMatrix;\n        }\n\n        public void DrawLine(Position start, Position end, SkPaint paint)\n        {\n            \n        }\n\n        public void DrawRectangle(Position vector, Size size, SkPaint paint)\n        {\n            \n        }\n\n        public void DrawComplexBorder(SkRoundedRect innerRect, SkRoundedRect outerRect, SkPaint paint)\n        {\n            \n        }\n        \n        public void DrawShadow(SkRoundedRect shadowRect, SkBoxShadow shadow)\n        {\n            \n        }\n        \n        public void DrawParagraph(SkParagraph paragraph, int lineFrom, int lineTo)\n        {\n            \n        }\n\n        public void DrawImage(SkImage image, Size size)\n        {\n            \n        }\n\n        public void DrawPicture(SkPicture picture)\n        {\n            \n        }\n\n        public void DrawSvgPath(string path, Color color)\n        {\n            \n        }\n\n        public void DrawSvg(SkSvgImage svgImage, Size size)\n        {\n            \n        }\n\n        public void DrawOverflowArea(SkRect area)\n        {\n            \n        }\n\n        public void ClipOverflowArea(SkRect availableSpace, SkRect requiredSpace)\n        {\n            \n        }\n\n        public void ClipRectangle(SkRect clipArea)\n        {\n            \n        }\n        \n        public void ClipRoundedRectangle(SkRoundedRect clipArea)\n        {\n            \n        }\n        \n        public void DrawHyperlink(Size size, string url, string? description)\n        {\n           \n        }\n\n        public void DrawSectionLink(Size size, string sectionName, string? description)\n        {\n            \n        }\n\n        public void DrawSection(string sectionName)\n        {\n            \n        }\n        \n        public int GetSemanticNodeId()\n        {\n            return 0;\n        }\n        \n        public void SetSemanticNodeId(int nodeId)\n        {\n            \n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/DrawingCanvases/SkiaDrawingCanvas.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Drawing.DrawingCanvases\n{\n    internal sealed class SkiaDrawingCanvas : IDrawingCanvas, IDisposable\n    {\n        public float Width { get; }\n        public float Height { get; }\n        \n        public SkiaDrawingCanvas(float width, float height)\n        {\n            Width = width;\n            Height = height;\n        }\n        \n        ~SkiaDrawingCanvas()\n        {\n            Dispose();\n        }\n        \n        public void Dispose()\n        {\n            CurrentCanvas?.Dispose();\n            CurrentCanvas = null;\n\n            foreach (var layer in ZIndexCanvases.Values)\n            {\n                layer.Canvas.Dispose();\n                layer.PictureRecorder.Dispose();\n            }\n            \n            ZIndexCanvases.Clear();\n            \n            GC.SuppressFinalize(this);\n        }\n        \n        #region ZIndex\n        \n        private SkCanvas CurrentCanvas { get; set; }\n        \n        private int CurrentZIndex { get; set; } = 0;\n        private IDictionary<int, (SkPictureRecorder PictureRecorder, SkCanvas Canvas)> ZIndexCanvases { get; } = new Dictionary<int, (SkPictureRecorder, SkCanvas)>();\n\n        private SkCanvas GetCanvasForZIndex(int zIndex)\n        {\n            if (ZIndexCanvases.TryGetValue(zIndex, out var value))\n                return value.Canvas;\n            \n            var pictureRecorder = new SkPictureRecorder();\n            var canvas = pictureRecorder.BeginRecording(Width, Height);\n            \n            ZIndexCanvases.Add(zIndex, (pictureRecorder, canvas));\n            return canvas;\n        }\n        \n        #endregion\n        \n        #region ICanvas\n\n        public DocumentPageSnapshot GetSnapshot()\n        { \n            return new DocumentPageSnapshot\n            {\n                Layers = ZIndexCanvases\n                    .Select(zindex =>\n                    {\n                        using var pictureRecorder = zindex.Value.PictureRecorder;\n                        var picture = pictureRecorder.EndRecording();\n                        \n                        zindex.Value.Canvas.Dispose();\n                        \n                        return new DocumentPageSnapshot.LayerSnapshot\n                        {\n                            ZIndex = zindex.Key,\n                            Picture = picture\n                        };\n                    })\n                    .ToList()\n            };\n        }\n\n        public void DrawSnapshot(DocumentPageSnapshot snapshot)\n        {\n            foreach (var snapshotLayer in snapshot.Layers.OrderBy(x => x.ZIndex))\n            {\n                var canvas = GetCanvasForZIndex(snapshotLayer.ZIndex);\n\n                canvas.Save();\n                canvas.SetCurrentMatrix(SkCanvasMatrix.Identity);\n                canvas.DrawPicture(snapshotLayer.Picture);\n                canvas.Restore();\n            }\n        }\n\n        public void Save()\n        {\n            CurrentCanvas.Save();\n        }\n\n        public void Restore()\n        {\n            CurrentCanvas.Restore();\n        }\n        \n        public void SetZIndex(int index)\n        {\n            var currentMatrix = CurrentCanvas?.GetCurrentMatrix() ?? SkCanvasMatrix.Identity;\n            \n            CurrentZIndex = index;\n            CurrentCanvas = GetCanvasForZIndex(CurrentZIndex);\n            \n            CurrentCanvas.SetCurrentMatrix(currentMatrix);\n        }\n\n        public int GetZIndex()\n        {\n            return CurrentZIndex;\n        }\n\n        public SkCanvasMatrix GetCurrentMatrix()\n        {\n            return CurrentCanvas.GetCurrentMatrix();\n        }\n\n        public void SetMatrix(SkCanvasMatrix matrix)\n        {\n            CurrentCanvas.SetCurrentMatrix(matrix);\n        }\n        \n        public void Translate(Position vector)\n        {\n            CurrentCanvas.Translate(vector.X, vector.Y);\n        }\n        \n        public void Scale(float scaleX, float scaleY)\n        {\n            CurrentCanvas.Scale(scaleX, scaleY);\n        }\n        \n        public void Rotate(float angle)\n        {\n            CurrentCanvas.Rotate(angle);\n        }\n        \n        public void DrawLine(Position start, Position end, SkPaint paint)\n        {\n            var startPoint = new SkPoint(start.X, start.Y);\n            var endPoint = new SkPoint(end.X, end.Y);\n            \n            CurrentCanvas.DrawLine(startPoint, endPoint, paint);\n        }\n\n        public void DrawRectangle(Position vector, Size size, SkPaint paint)\n        {\n            var position = new SkRect(vector.X, vector.Y, vector.X + size.Width, vector.Y + size.Height);\n            CurrentCanvas.DrawRectangle(position, paint);\n        }\n        \n        public void DrawComplexBorder(SkRoundedRect innerRect, SkRoundedRect outerRect, SkPaint paint)\n        {\n            CurrentCanvas.DrawComplexBorder(innerRect, outerRect, paint);\n        }\n        \n        public void DrawShadow(SkRoundedRect shadowRect, SkBoxShadow shadow)\n        {\n            CurrentCanvas.DrawShadow(shadowRect, shadow);\n        }\n\n        public void DrawParagraph(SkParagraph paragraph, int lineFrom, int lineTo)\n        {\n            CurrentCanvas.DrawParagraph(paragraph, lineFrom, lineTo);\n        }\n\n        public void DrawImage(SkImage image, Size size)\n        {\n            CurrentCanvas.DrawImage(image, size.Width, size.Height);\n        }\n\n        public void DrawPicture(SkPicture picture)\n        {\n            CurrentCanvas.DrawPicture(picture);\n        }\n\n        public void DrawSvgPath(string path, Color color)\n        {\n            CurrentCanvas.DrawSvgPath(path, color);\n        }\n\n        public void DrawSvg(SkSvgImage svgImage, Size size)\n        {\n            CurrentCanvas.DrawSvg(svgImage, size.Width, size.Height);\n        }\n        \n        public void DrawOverflowArea(SkRect area)\n        {\n            CurrentCanvas.DrawOverflowArea(area);\n        }\n    \n        public void ClipOverflowArea(SkRect availableSpace, SkRect requiredSpace)\n        {\n            CurrentCanvas.ClipOverflowArea(availableSpace, requiredSpace);\n        }\n    \n        public void ClipRectangle(SkRect clipArea)\n        {\n            CurrentCanvas.ClipRectangle(clipArea);\n        }\n        \n        public void ClipRoundedRectangle(SkRoundedRect clipArea)\n        {\n            CurrentCanvas.ClipRoundedRectangle(clipArea);\n        }\n        \n        public void DrawHyperlink(Size size, string url, string? description)\n        {\n            CurrentCanvas.AnnotateUrl(size.Width, size.Height, url, description);\n        }\n        \n        public void DrawSectionLink(Size size, string sectionName, string? description)\n        {\n            CurrentCanvas.AnnotateDestinationLink(size.Width, size.Height, sectionName, description);\n        }\n\n        public void DrawSection(string sectionName)\n        {\n            CurrentCanvas.AnnotateDestination(sectionName);\n        }\n\n        private int CurrentSemanticNodeId { get; set; } = 0;\n\n        public int GetSemanticNodeId()\n        {\n            return CurrentSemanticNodeId;\n        }\n        \n        public void SetSemanticNodeId(int nodeId)\n        {\n            CurrentSemanticNodeId = nodeId;\n            \n            foreach (var canvas in ZIndexCanvases)\n                canvas.Value.Canvas.SetSemanticNodeId(nodeId);\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Exceptions/DocumentComposeException.cs",
    "content": "﻿using System;\n\nnamespace QuestPDF.Drawing.Exceptions\n{\n    public sealed class DocumentComposeException : Exception\n    {\n        internal DocumentComposeException(string message) : base(message)\n        {\n            \n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Exceptions/DocumentDrawingException.cs",
    "content": "﻿using System;\n\nnamespace QuestPDF.Drawing.Exceptions\n{\n    public sealed class DocumentDrawingException : Exception\n    {\n        internal DocumentDrawingException(string message) : base(message)\n        {\n            \n        }\n        \n        internal DocumentDrawingException(string message, Exception inner) : base(message, inner)\n        {\n            \n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Exceptions/DocumentLayoutException.cs",
    "content": "﻿using System;\n\nnamespace QuestPDF.Drawing.Exceptions\n{\n    public sealed class DocumentLayoutException : Exception\n    {\n        internal DocumentLayoutException(string message) : base(message)\n        {\n            \n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Exceptions/InitializationException.cs",
    "content": "﻿using System;\n\nnamespace QuestPDF.Drawing.Exceptions\n{\n    public sealed class InitializationException : Exception\n    {\n        internal InitializationException(string message) : base(message)\n        {\n            \n        }\n        \n        internal InitializationException(string message, Exception inner) : base(message, inner)\n        {\n            \n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/FontManager.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Drawing\n{\n    /// <summary>\n    /// <para>By default, the library searches all fonts available in the runtime environment.</para>\n    /// <para>This may work well on the development environment but may fail in the cloud where fonts are usually not installed.</para>\n    /// <para>It is safest deploy font files along with the application and then register them using this class.</para>\n    /// </summary>\n    public static class FontManager\n    {\n        internal static SkTypefaceProvider TypefaceProvider { get; } = new();\n        internal static SkFontManager CurrentFontManager => Settings.UseEnvironmentFonts ? SkFontManager.Global : SkFontManager.Local;\n\n        static FontManager()\n        {\n            SkNativeDependencyCompatibilityChecker.Test();\n            RegisterLibraryDefaultFonts();\n        }\n        \n        [Obsolete(\"Since version 2022.8 this method has been renamed. Please use the RegisterFontWithCustomName method.\")]\n        [ExcludeFromCodeCoverage]\n        public static void RegisterFontType(string fontName, Stream stream)\n        {\n            RegisterFontWithCustomName(fontName, stream);\n        }\n        \n        /// <summary>\n        /// Registers a TrueType font from a stream under the provided custom <paramref name=\"fontName\"/>.\n        /// Refer to this font by using the same name as a font family in the <see cref=\"TextStyle\"/> API later on.\n        /// <a href=\"https://www.questpdf.com/api-reference/text/font-management.html#manual-font-registration\">Learn more</a>\n        /// </summary>\n        public static void RegisterFontWithCustomName(string fontName, Stream stream)\n        {\n            using var fontData = SkData.FromStream(stream);\n            TypefaceProvider.AddTypefaceFromData(fontData);\n            TypefaceProvider.AddTypefaceFromData(fontData, fontName);\n        }\n\n        /// <summary>\n        /// Registers a TrueType font from a stream. The font family name and all related attributes are detected automatically.\n        /// <a href=\"https://www.questpdf.com/api-reference/text/font-management.html#manual-font-registration\">Learn more</a>\n        /// </summary>\n        public static void RegisterFont(Stream stream)\n        {\n            using var fontData = SkData.FromStream(stream);\n            TypefaceProvider.AddTypefaceFromData(fontData);\n        }\n        \n        /// <summary>\n        /// Registers a TrueType font from an embedded resource. The font family name and all related attributes are detected automatically.\n        /// <a href=\"https://www.questpdf.com/api-reference/text/font-management.html#manual-font-registration\">Learn more</a>\n        /// </summary>\n        /// <param name=\"pathName\">Path to the embedded resource (the case-sensitive name of the manifest resource being requested).</param>\n        public static void RegisterFontFromEmbeddedResource(string pathName)\n        {\n            using var stream = Assembly.GetCallingAssembly().GetManifestResourceStream(pathName);\n\n            if (stream == null)\n                throw new ArgumentException($\"Cannot load font file from an embedded resource. Please make sure that the resource is available or the path is correct: {pathName}\");\n            \n            RegisterFont(stream);\n        }\n        \n        private static void RegisterLibraryDefaultFonts()\n        {\n            var fontFilePaths = SearchFontFiles();\n            \n            foreach (var fileName in fontFilePaths)\n            {\n                try\n                {\n                    using var fontFileStream = File.OpenRead(fileName);\n                    RegisterFont(fontFileStream);\n                }\n                catch\n                {\n                    \n                }\n            }\n\n            ICollection<string> SearchFontFiles()\n            {\n                const int maxFilesToScan = 100_000;\n                \n                var applicationFiles = Settings\n                    .FontDiscoveryPaths\n                    .Where(Directory.Exists)\n                    .Select(TryEnumerateFiles)\n                    .SelectMany(file => file)\n                    .Take(maxFilesToScan)\n                    .ToList();\n                \n                if (applicationFiles.Count == maxFilesToScan)\n                    throw new InvalidOperationException($\"The library has reached the limit of {maxFilesToScan} files to scan for font files. Please adjust the {nameof(Settings.FontDiscoveryPaths)} collection to include only the necessary directories. The reason of this exception is to prevent scanning too many files and avoid performance issues on the application startup.\");\n                \n                var supportedFontExtensions = new[] { \".ttf\", \".otf\", \".ttc\", \".pfb\" };\n                \n                return applicationFiles\n                    .Where(x => supportedFontExtensions.Contains(Path.GetExtension(x).ToLowerInvariant()))\n                    .ToList();\n                \n                ICollection<string> TryEnumerateFiles(string path)\n                {\n                    try\n                    {\n                        return Directory\n                            .EnumerateFiles(path, \"*.*\", SearchOption.AllDirectories)\n                            .Take(maxFilesToScan)\n                            .ToArray();\n                    }\n                    catch\n                    {\n                        return Array.Empty<string>();\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Proxy/ElementProxy.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Drawing.Proxy\n{\n    internal class ElementProxy : ContainerElement\n    {\n        \n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Proxy/LayoutDebugging.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing QuestPDF.Elements;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Drawing.Proxy;\n\ninternal static class LayoutDebugging\n{\n    internal static SpacePlan TryMeasureWithOverflow(this Element element, Size availableSpace)\n    {\n        return TryVerticalOverflow()\n               ?? TryHorizontalOverflow() \n               ?? TryUnconstrainedOverflow()\n               ?? SpacePlan.Wrap(\"Extending the available space does not allow the child to fit on the page.\");\n\n        SpacePlan? TryOverflow(Size targetSpace)\n        {\n            var contentSize = element.Measure(targetSpace);\n            return contentSize.Type == SpacePlanType.Wrap ? null : contentSize;\n        }\n    \n        SpacePlan? TryVerticalOverflow()\n        {\n            var overflowSpace = new Size(availableSpace.Width, Size.Infinity);\n            return TryOverflow(overflowSpace);\n        }\n    \n        SpacePlan? TryHorizontalOverflow()\n        {\n            var overflowSpace = new Size(Size.Infinity, availableSpace.Height);\n            return TryOverflow(overflowSpace);\n        }\n    \n        SpacePlan? TryUnconstrainedOverflow()\n        {\n            var overflowSpace = new Size(Size.Infinity, Size.Infinity);\n            return TryOverflow(overflowSpace);\n        }\n    }\n    \n    public static void ApplyLayoutOverflowDetection(this Element container)\n    {\n        container.VisitChildren(x =>\n        {\n            x.CreateProxy(y => y is ElementProxy ? y : new OverflowDebuggingProxy(y));\n        });\n    }\n    \n    public static void TryToFixTheLayoutOverflowIssue(this TreeNode<OverflowDebuggingProxy> hierarchyRoot)\n    {\n        Traverse(hierarchyRoot);\n        \n        void Traverse(TreeNode<OverflowDebuggingProxy> element)\n        {\n            if (element.Value.Child is DebugPointer or SourceCodePointer or Container)\n            {\n                Traverse(element.Children.First());\n                return;\n            }\n            \n            if (element.Value.AvailableSpace is null)\n                return;\n            \n            // element was not part of the current layout measurement,\n            // it could not impact the process\n            if (element.Value.SpacePlan is null)\n                return;\n            \n            // element is empty,\n            // it could not impact the process\n            if (element.Value.SpacePlan?.Type is SpacePlanType.Empty)\n                return;\n            \n            // element renders fully,\n            // it could not impact the process\n            if (element.Value.SpacePlan?.Type is SpacePlanType.FullRender)\n                return;\n\n            // when the current element is partially rendering, it likely has no issues,\n            // however, in certain cases, it may contain a child that is a root cause\n            if (element.Value.SpacePlan?.Type is SpacePlanType.PartialRender)\n            {\n                foreach (var child in element.Children)\n                    Traverse(child);\n                \n                return;\n            }\n            \n            // all the code below relates to element that is wrapping,\n            // it could be a root cause, or contain a child (even deeply nested) that is the root cause\n            \n            // strategy:\n            // the current element does not contain any wrapping children, no obvious root causes,\n            // if it renders at least partially with extended space, it is a layout root cause\n            if (element.Children.All(x => x.Value.SpacePlan?.Type is not SpacePlanType.Wrap) && MeasureElementWithExtendedSpace() is not SpacePlanType.Wrap)\n            {\n                element.Value.CreateProxy(x => new LayoutOverflowVisualization { Child = x });\n                return;\n            }\n\n            // strategy:\n            // the current element contains wrapping children, they are likely the root cause,\n            // traverse them and attempt to fix them\n            foreach (var child in element.Children.Where(x => x.Value.SpacePlan?.Type is SpacePlanType.Wrap).ToList())\n                Traverse(child);\n\n            // check if fixing wrapping children resolved the issue under original constraints\n            if (MeasureElementWithOriginalSpace() is not SpacePlanType.Wrap)\n                return;\n\n            // fixing wrapping children was not sufficient under original constraints;\n            // if this element fits with extended space, it is also a root cause\n            if (MeasureElementWithExtendedSpace() is not SpacePlanType.Wrap)\n            {\n                element.Value.CreateProxy(x => new LayoutOverflowVisualization { Child = x });\n                return;\n            }\n\n            // strategy:\n            // the current element has layout issues but no obvious/trivial root causes,\n            // possibly the problem is in nested children of partial rendering children\n            foreach (var child in element.Children.Where(x => x.Value.SpacePlan?.Type is SpacePlanType.PartialRender).ToList())\n                Traverse(child);\n\n            // check if fixing partial children resolved the issue under original constraints\n            if (MeasureElementWithOriginalSpace() is not SpacePlanType.Wrap)\n                return;\n\n            // none of the attempts above have fixed the layout issue,\n            // the element itself is the root cause\n            element.Value.CreateProxy(x => new LayoutOverflowVisualization { Child = x });\n\n            SpacePlanType MeasureElementWithExtendedSpace()\n            {\n                return element.Value.TryMeasureWithOverflow(element.Value.AvailableSpace!.Value).Type;\n            }\n\n            SpacePlanType MeasureElementWithOriginalSpace()\n            {\n                return element.Value.Measure(element.Value.AvailableSpace!.Value).Type;\n            }\n        }\n    }\n\n    public static void RemoveExistingProxies(this Element content)\n    {\n        content.RemoveExistingProxiesOfType<ElementProxy>();\n    }\n    \n    public static void RemoveExistingProxiesOfType<TProxy>(this Element content) where TProxy : ElementProxy\n    {\n        content.VisitChildren(x =>\n        {\n            x.CreateProxy(y =>\n            {\n                if (y is not TProxy proxy)\n                    return y;\n                \n                (proxy as IDisposable)?.Dispose();\n                return proxy.Child;\n            });\n        });\n    }\n\n    public static void StopMeasuring(this TreeNode<OverflowDebuggingProxy> parent)\n    {\n        parent.Value.StopMeasuring();\n            \n        foreach (var child in parent.Children)\n            StopMeasuring(child);\n    }\n    \n    public static IEnumerable<TreeNode<OverflowDebuggingProxy>> FindLayoutOverflowVisualizationNodes(this TreeNode<OverflowDebuggingProxy> rootNode)\n    {\n        var result = new List<TreeNode<OverflowDebuggingProxy>>();\n        Traverse(rootNode);\n        return result;\n        \n        void Traverse(TreeNode<OverflowDebuggingProxy> node)\n        {\n            if (node.Value.Child is LayoutOverflowVisualization)\n                result.Add(node);\n\n            foreach (var child in node.Children)\n                Traverse(child);\n        }\n    }\n    \n    public static string FormatAncestors(this IEnumerable<Element> ancestors)\n    {\n        var result = new StringBuilder();\n        \n        foreach (var ancestor in ancestors)\n            Format(ancestor);\n        \n        return result.ToString();\n\n        void Format(Element node)\n        {\n            if (node is DebugPointer debugPointer)\n            {\n                result.AppendLine($\"-> {debugPointer.Label}\");\n            }\n            else if (node is SourceCodePointer sourceCodePointer)\n            {\n                result.AppendLine($\"-> In method:   {sourceCodePointer.MethodName}\");\n                result.AppendLine($\"   Called from: {sourceCodePointer.CalledFrom}\");\n                result.AppendLine($\"   Source path: {sourceCodePointer.FilePath}\");\n                result.AppendLine($\"   Line number: {sourceCodePointer.LineNumber}\");\n            }\n            else\n            {\n                \n            }\n            \n            result.AppendLine();\n        }\n    }\n    \n    public static string FormatLayoutSubtree(this TreeNode<OverflowDebuggingProxy> root)\n    {\n        var indentationCache = Enumerable.Range(0, 128).Select(x => x * 3).Select(x => new string(' ', x)).ToArray();\n        \n        var indentationLevel = 0;\n        var result = new StringBuilder();\n        \n        Traverse(root);\n        \n        return result.ToString();\n\n        void Traverse(TreeNode<OverflowDebuggingProxy> parent)\n        {\n            var proxy = parent.Value;\n\n            if (proxy.Child is Container)\n            {\n                Traverse(parent.Children.First());\n                return;\n            }\n            \n            var indent = indentationCache[indentationLevel];\n            \n            foreach (var content in Format(proxy))\n                result.AppendLine($\"{indent}{content}\");\n            \n            result.AppendLine();\n            result.AppendLine();\n            \n            if (proxy.AvailableSpace is null || proxy.SpacePlan is null)\n                return;\n\n            indentationLevel++;\n            \n            foreach (var child in parent.Children)\n                Traverse(child);\n\n            indentationLevel--;\n        }\n\n        static IEnumerable<string> Format(OverflowDebuggingProxy proxy)\n        {\n            var child = proxy.Child;\n            \n            if (child is LayoutOverflowVisualization layoutOverflowVisualization)\n                child = layoutOverflowVisualization.Child;\n\n            var title = GetTitle();\n            yield return title;\n            \n            yield return new string('=', title.Length + 1);\n\n            if (proxy is { AvailableSpace: not null, SpacePlan: not null })\n            {\n                yield return $\"Available Space: {proxy.AvailableSpace}\";\n                yield return $\"Space Plan: {proxy.SpacePlan}\";\n                \n                if (proxy.SpacePlan?.Type == SpacePlanType.Wrap)\n                    yield return \"Wrap Reason: \" + (proxy.SpacePlan?.WrapReason ?? \"Unknown\");\n                \n                yield return new string('-', title.Length + 1);\n            }\n            \n            foreach (var configuration in child.GetElementConfiguration())\n                yield return $\"{configuration.Property}: {configuration.Value}\";\n            \n            string GetTitle()\n            {\n                var elementName = child.GetType().Name;\n                \n                if (proxy.Child is LayoutOverflowVisualization)\n                    return $\"🚨 {elementName} 🚨\";\n                \n                var indicator = proxy.SpacePlan?.Type switch\n                {\n                    SpacePlanType.Wrap => \"🔴\",\n                    SpacePlanType.PartialRender => \"🟡\",\n                    SpacePlanType.FullRender => \"🟢\",\n                    SpacePlanType.Empty => \"🟢\",\n                    _ => \"⚪️\"\n                };\n                \n                return $\"{indicator} {elementName}\";\n            }\n        }\n        \n    }\n    \n    public static IEnumerable<(string Property, string Value)> GetElementConfiguration(this IElement element)\n    {\n        return element\n            .GetType()\n            .GetProperties()\n            .Select(x => new\n            {\n                Property = x.Name.PrettifyName(),\n                Value = x.GetValue(element)\n            })\n            .Where(x => !(x.Value is IElement))\n            .Where(x => x.Value is string || !(x.Value is IEnumerable))\n            .Where(x => !(x.Value is TextStyle))\n            .Select(x => (x.Property, x.Value?.ToString() ?? \"-\"));\n    }\n\n    public const string LayoutVisualizationLegend =\n        \"Legend: \\n\" +\n        \"🚨 - Element that is likely the root cause of the layout issue based on library heuristics and prediction. \\n\" +\n        \"🔴 - Element that cannot be drawn due to the provided layout constraints. This element likely causes the layout issue, or one of its descendant children is responsible for the problem. \\n\" +\n        \"🟡 - Element that can be partially drawn on the page and will also be rendered on the consecutive page. In more complex layouts, this element may also cause issues or contain a child that is the actual root cause.\\n\" +\n        \"🟢 - Element that is successfully and completely drawn on the page.\\n\" +\n        \"⚪️ - Element that has not been drawn on the faulty page. Its children are omitted.\\n\";\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Proxy/LayoutOverflowVisualization.cs",
    "content": "using System;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Drawing.Proxy;\n\ninternal sealed class LayoutOverflowVisualization : ElementProxy, IContentDirectionAware\n{\n    private const float BorderThickness = 1.5f;\n    private readonly Color LineColor = Colors.Red.Medium;\n    private readonly Color AvailableAreaColor = Colors.Green.Medium;\n    private const byte AreaOpacity = 64;\n\n    public ContentDirection ContentDirection { get; set; }\n\n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        if (Size.Equal(availableSpace, Size.Zero))\n            return SpacePlan.Wrap(\"There is no available space.\");\n        \n        var childSize = base.Measure(availableSpace);\n        \n        if (childSize.Type == SpacePlanType.FullRender)\n            return childSize;\n\n        var minimalSize = Child.TryMeasureWithOverflow(availableSpace);\n\n        if (minimalSize.Type is SpacePlanType.Wrap)\n            return minimalSize;\n        \n        var width = Math.Min(availableSpace.Width, minimalSize.Width);\n        var height = Math.Min(availableSpace.Height, minimalSize.Height);\n        \n        return new SpacePlan(minimalSize.Type, width, height);\n    }\n        \n    internal override void Draw(Size availableSpace)\n    {\n        // measure content area\n        var childSize = base.Measure(availableSpace);\n        \n        if (childSize.Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n        {\n            Child?.Draw(availableSpace);\n            return;\n        }\n\n        Canvas = Child.Canvas;\n\n        // check overflow area\n        var contentArea = Child.TryMeasureWithOverflow(availableSpace);\n\n        var contentSize = contentArea.Type is SpacePlanType.Wrap\n            ? Size.Max\n            : contentArea;\n        \n        // draw content\n        var translate = ContentDirection == ContentDirection.RightToLeft\n            ? new Position(availableSpace.Width - contentSize.Width, 0)\n            : Position.Zero;\n        \n        Canvas.Translate(translate);\n        Child?.Draw(contentSize);\n        Canvas.Translate(translate.Reverse());\n        \n        // draw overflow area\n        var overflowTranslate = ContentDirection == ContentDirection.RightToLeft ? new Position(availableSpace.Width, 0) : Position.Zero;\n        var overflowScale = ContentDirection == ContentDirection.RightToLeft ? -1 : 1;\n        \n        Canvas.Translate(overflowTranslate);\n        Canvas.Scale(overflowScale, 1);\n        \n        DrawOverflowArea(availableSpace, contentSize);\n        \n        Canvas.Scale(overflowScale, 1);\n        Canvas.Translate(overflowTranslate.Reverse());\n    }\n\n    private void DrawOverflowArea(Size availableSpace, Size contentSize)\n    {\n        using var availableSpacePaint = new SkPaint();\n        availableSpacePaint.SetSolidColor(AvailableAreaColor.WithAlpha(AreaOpacity));\n        Canvas.DrawRectangle(Position.Zero, availableSpace, availableSpacePaint);\n\n        Canvas.Save();\n        Canvas.ClipOverflowArea(new SkRect(0, 0, availableSpace.Width, availableSpace.Height), new SkRect(0, 0, contentSize.Width, contentSize.Height));\n        Canvas.DrawOverflowArea(new SkRect(0, 0, contentSize.Width, contentSize.Height));\n        Canvas.Restore();\n\n        using var borderPaint = new SkPaint();\n        borderPaint.SetStroke(BorderThickness);\n        borderPaint.SetSolidColor(LineColor);\n        Canvas.DrawRectangle(Position.Zero, contentSize, borderPaint);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Proxy/LayoutProxy.cs",
    "content": "using System.Collections.Generic;\nusing QuestPDF.Companion;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Elements;\nusing QuestPDF.Elements.Text;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing Image = QuestPDF.Elements.Image;\nusing SvgImage = QuestPDF.Elements.SvgImage;\n\nnamespace QuestPDF.Drawing.Proxy;\n\ninternal sealed class LayoutProxy : ElementProxy\n{\n    public List<CompanionCommands.UpdateDocumentStructure.PageLocation> Snapshots { get; } = new();\n    public List<CompanionCommands.UpdateDocumentStructure.LayoutErrorMeasurement> LayoutErrorMeasurements { get; } = new();\n\n    public LayoutProxy(Element child)\n    {\n        Child = child;\n    }\n    \n    internal override void Draw(Size availableSpace)\n    {\n        var size = ProvideIntrinsicSize() ? Child.Measure(availableSpace) : availableSpace;\n        \n        base.Draw(availableSpace);\n\n        if (!Canvas.Is<SkiaDrawingCanvas>())\n            return;\n        \n        var matrix = Canvas.GetCurrentMatrix();\n        \n        Snapshots.Add(new CompanionCommands.UpdateDocumentStructure.PageLocation\n        {\n            PageNumber = PageContext.CurrentPage,\n            Left = matrix.TranslateX,\n            Top = matrix.TranslateY,\n            Right = matrix.TranslateX + size.Width,\n            Bottom = matrix.TranslateY + size.Height\n        });\n\n        bool ProvideIntrinsicSize()\n        {\n            // Image or DynamicImage or SvgImage or DynamicSvgImage should be excluded\n            // They rely on the AspectRation component to provide true intrinsic size\n            \n            return Child is TextBlock or AspectRatio or Unconstrained or SemanticTag or ArtifactTag;\n        }\n    }\n\n    internal void CaptureLayoutErrorMeasurement()\n    {\n        var child = Child;\n        \n        while (true)\n        {\n            if (child is OverflowDebuggingProxy overflowDebuggingProxy)\n            {\n                if (overflowDebuggingProxy.AvailableSpace == null || overflowDebuggingProxy.SpacePlan == null)\n                    break;\n                \n                LayoutErrorMeasurements.Add(new CompanionCommands.UpdateDocumentStructure.LayoutErrorMeasurement\n                {\n                    PageNumber = PageContext.CurrentPage,\n                    AvailableSpace = new CompanionCommands.ElementSize\n                    {\n                        Width = overflowDebuggingProxy.AvailableSpace.Value.Width,\n                        Height = overflowDebuggingProxy.AvailableSpace.Value.Height\n                    },\n                    MeasurementSize = new CompanionCommands.ElementSize\n                    {\n                        Width = overflowDebuggingProxy.SpacePlan.Value.Width,\n                        Height = overflowDebuggingProxy.SpacePlan.Value.Height\n                    },\n                    SpacePlanType = overflowDebuggingProxy.SpacePlan?.Type,\n                    WrapReason = overflowDebuggingProxy.SpacePlan?.WrapReason,\n                    IsLayoutErrorRootCause = overflowDebuggingProxy.Child.GetType() == typeof(LayoutOverflowVisualization)\n                });\n            }\n\n            if (child is not ElementProxy proxy)\n                break;\n            \n            child = proxy.Child;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Proxy/OverflowDebuggingProxy.cs",
    "content": "using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Drawing.Proxy;\n\ninternal sealed class OverflowDebuggingProxy : ElementProxy\n{\n    public bool IsMeasuring { get; private set; } = true;\n    \n    public Size? AvailableSpace { get; private set; }\n    public SpacePlan? SpacePlan { get; private set; }\n\n    public OverflowDebuggingProxy(Element child)\n    {\n        Child = child;\n    }\n\n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        var spacePlan = Child.Measure(availableSpace);\n\n        if (IsMeasuring && !Size.Equal(availableSpace, Size.Zero))\n        {\n            AvailableSpace = availableSpace;\n            SpacePlan = spacePlan;\n        }\n        \n        return spacePlan;\n    }\n    \n    public void StopMeasuring()\n    {\n        IsMeasuring = false;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/Proxy/SnapshotCacheRecorderProxy.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Drawing.Proxy;\n\ninternal sealed class SnapshotCacheRecorderProxy : ElementProxy, IDisposable\n{\n    private ProxyDrawingCanvas RecorderCanvas { get; } = new();\n    private Dictionary<(int pageNumber, float availableWidth, float availableHeight), SpacePlan> MeasureCache { get; } = new();\n    private Dictionary<int, DocumentPageSnapshot> DrawCache { get; } = new();\n\n    ~SnapshotCacheRecorderProxy()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n\n    public void Dispose()\n    {\n        RecorderCanvas?.Dispose();\n        \n        foreach (var cacheValue in DrawCache.Values)\n            cacheValue.Dispose();\n        \n        GC.SuppressFinalize(this);\n    }\n    \n    public SnapshotCacheRecorderProxy(Element child)\n    {\n        Child = child;\n    }\n    \n    private void Initialize()\n    {\n        if (Child.Canvas == RecorderCanvas)\n            return;\n        \n        Child.VisitChildren(x => x.Canvas = RecorderCanvas);\n    }\n    \n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        Initialize();\n\n        var cacheItem = (PageContext.CurrentPage, availableSpace.Width, availableSpace.Height);\n        \n        if (MeasureCache.TryGetValue(cacheItem, out var measurement))\n            return measurement;\n\n        RecorderCanvas.Target = new DiscardDrawingCanvas();\n        var result = base.Measure(availableSpace);\n        RecorderCanvas.Target = null;\n        \n        MeasureCache[cacheItem] = result;\n        return result;\n    }\n        \n    internal override void Draw(Size availableSpace)\n    {\n        if (DrawCache.TryGetValue(PageContext.CurrentPage, out var snapshot))\n        {\n            Canvas.DrawSnapshot(snapshot);\n            \n            snapshot.Dispose();\n            DrawCache.Remove(PageContext.CurrentPage);\n            return;\n        }\n        \n        using var skiaCanvas = new SkiaDrawingCanvas(Size.Max.Width, Size.Max.Height);\n        RecorderCanvas.Target = skiaCanvas;\n        RecorderCanvas.SetZIndex(Canvas.GetZIndex());\n        RecorderCanvas.SetMatrix(Canvas.GetCurrentMatrix());\n        \n        base.Draw(availableSpace);\n        \n        DrawCache[PageContext.CurrentPage] = skiaCanvas.GetSnapshot();\n        RecorderCanvas.Target = null;\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Drawing/Proxy/TreeTraversal.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Drawing.Proxy;\n\ninternal sealed class TreeNode<T>\n{\n    public T Value { get; }\n    public TreeNode<T>? Parent { get; set; }\n    public ICollection<TreeNode<T>> Children { get; } = new List<TreeNode<T>>();\n    \n    public TreeNode(T Value)\n    {\n        this.Value = Value;\n    }\n}\n\ninternal static class TreeTraversal\n{\n    public static IEnumerable<TreeNode<T>> ExtractElementsOfType<T>(this Element element) where T : Element\n    {\n        if (element is T proxy)\n        {\n            var result = new TreeNode<T>(proxy);\n\n            foreach (var treeNode in proxy.GetChildren().SelectMany(ExtractElementsOfType<T>))\n            {\n                result.Children.Add(treeNode);\n                treeNode.Parent = result;\n            }\n                \n            yield return result;\n        }\n        else\n        {\n            foreach (var treeNode in element.GetChildren().SelectMany(ExtractElementsOfType<T>))\n                yield return treeNode;\n        }\n    }\n    \n    public static IEnumerable<TreeNode<T>> Flatten<T>(this TreeNode<T> element) where T : Element\n    {\n        yield return element;\n\n        foreach (var child in element.Children)\n            foreach (var innerChild in Flatten(child))\n                yield return innerChild;\n    }\n    \n    public static IEnumerable<TreeNode<T>> ExtractAncestors<T>(this TreeNode<T> node)\n    {\n        while (true)\n        {\n            node = node.Parent;\n            \n            if (node is null)\n                yield break;\n\n            yield return node;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/SemanticTreeManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Drawing;\n\ninternal class SemanticTreeNode\n{\n    public int NodeId { get; set; }\n    public string Type { get; set; } = \"\";\n    public string? Alt { get; set; }\n    public string? Lang { get; set; }\n    public IList<SemanticTreeNode> Children { get; } = [];\n    public ICollection<Attribute> Attributes { get; } = [];\n\n    public class Attribute\n    {\n        public string Owner { get; set; }\n        public string Name { get; set; }\n        public object Value { get; set; }\n    }\n}\n\nclass SemanticTreeManager\n{\n    private int CurrentNodeId { get; set; }\n    private SemanticTreeNode? Root { get; set; }\n    private Stack<SemanticTreeNode> Stack { get; set; } = [];\n\n    public SemanticTreeManager()\n    {\n        PopulateWithTopLevelNode();\n    }\n\n    private void PopulateWithTopLevelNode()\n    {\n        AddNode(new SemanticTreeNode\n        {\n            NodeId = GetNextNodeId(),\n            Type = \"Document\"\n        });\n    }\n    \n    public int GetNextNodeId()\n    {\n        CurrentNodeId++;\n        return CurrentNodeId;\n    }\n    \n    public void AddNode(SemanticTreeNode node)\n    {\n        if (Root == null)\n        {\n            Root = node;\n            Stack.Push(node);\n            return;\n        }\n        \n        Stack.Peek()?.Children.Add(node);\n    }\n    \n    public void PushOnStack(SemanticTreeNode node)\n    {\n        Stack.Push(node);\n    }\n    \n    public void PopStack()\n    {\n        Stack.Pop();\n    }\n    \n    public SemanticTreeNode PeekStack()\n    {\n        return Stack.Peek();\n    }\n    \n    public void Reset()\n    {\n        CurrentNodeId = 0;\n        Root = null;\n        Stack.Clear();\n    }\n\n    public SemanticTreeNode? GetSemanticTree()\n    {\n        return Root;\n    }\n    \n    #region Artifacts\n    \n    private int ArtifactNestingLevel { get; set; } = 0;\n    \n    public void BeginArtifactContent()\n    {\n        ArtifactNestingLevel++;\n    }\n    \n    public void EndArtifactContent()\n    {\n        ArtifactNestingLevel--;\n    }\n    \n    public bool IsCurrentContentArtifact()\n    {\n        return ArtifactNestingLevel > 0;\n    }\n    \n    #endregion\n    \n    #region State\n\n    public class StateSnapshot\n    {\n        internal int CurrentNodeId { get; init; }\n    }\n    \n    public StateSnapshot GetState()\n    {\n        return new StateSnapshot\n        {\n            CurrentNodeId = CurrentNodeId\n        };\n    }\n    \n    public void SetState(StateSnapshot state)\n    {\n        CurrentNodeId = state.CurrentNodeId;\n    }\n    \n    #endregion\n}\n\nclass SemanticTreeSnapshots(SemanticTreeManager? semanticTreeManager, IPageContext pageContext)\n{\n    private IList<SemanticTreeManager.StateSnapshot> Snapshots { get; } = [];\n\n    public SemanticTreeSnapshotScope? StartSemanticStateScope(int index)\n    {\n        if (semanticTreeManager == null)\n            return null;\n        \n        var originalSemanticState = semanticTreeManager.GetState();\n        \n        if (index >= Snapshots.Count)\n        {\n            Snapshots.Add(originalSemanticState);\n        }\n        else\n        {\n            var snapshot = Snapshots[index];\n            semanticTreeManager.SetState(snapshot);\n        }\n        \n        return new SemanticTreeSnapshotScope(() =>\n        {\n            if (pageContext.IsInitialRenderingPhase)\n                return;\n                \n            semanticTreeManager.SetState(originalSemanticState);\n        });\n    }\n\n    public class SemanticTreeSnapshotScope(Action resetState) : IDisposable\n    {\n        public void Dispose()\n        {\n            resetState();\n            GC.SuppressFinalize(this);\n        }\n    }\n}\n\ninternal readonly ref struct SemanticScope : IDisposable\n{\n    private IDrawingCanvas DrawingCanvas { get; }\n    private int OriginalSemanticNodeId { get; }\n\n    public SemanticScope(IDrawingCanvas drawingCanvas, int nodeId)\n    {\n        DrawingCanvas = drawingCanvas;\n        OriginalSemanticNodeId = drawingCanvas.GetSemanticNodeId();\n        DrawingCanvas.SetSemanticNodeId(nodeId);\n    }\n    \n    public void Dispose()\n    {\n        DrawingCanvas.SetSemanticNodeId(OriginalSemanticNodeId);\n    }\n}\n\ninternal static class SemanticCanvasExtensions\n{\n    public static SemanticScope StartSemanticScopeWithNodeId(this IDrawingCanvas canvas, int nodeId)\n    {\n        return new SemanticScope(canvas, nodeId);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/SpacePlan.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Drawing\n{\n    internal readonly struct SpacePlan\n    {\n        public readonly SpacePlanType Type;\n        public readonly float Width;\n        public readonly float Height;\n        public readonly string? WrapReason;\n\n        internal SpacePlan(SpacePlanType type, float width, float height, string? wrapReason = null)\n        {\n            Type = type;\n            Width = width;\n            Height = height;\n            WrapReason = wrapReason;\n        }\n\n        internal static SpacePlan Empty() => new(SpacePlanType.Empty, 0, 0);\n        \n        internal static SpacePlan Wrap(string reason) => new(SpacePlanType.Wrap, 0, 0, reason);\n        \n        internal static SpacePlan PartialRender(float width, float height) => new(SpacePlanType.PartialRender, width, height);\n\n        internal static SpacePlan PartialRender(Size size) => PartialRender(size.Width, size.Height);\n        \n        internal static SpacePlan FullRender(float width, float height) => new(SpacePlanType.FullRender, width, height);\n\n        internal static SpacePlan FullRender(Size size) => FullRender(size.Width, size.Height);\n        \n        public override string ToString()\n        {\n            if (Type == SpacePlanType.Wrap)\n                return Type.ToString();\n            \n            return $\"{Type} (Width: {Width:N3}, Height: {Height:N3})\";\n        }\n\n        public static implicit operator Size(SpacePlan spacePlan)\n        {\n            return new Size(spacePlan.Width, spacePlan.Height);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Drawing/SpacePlanType.cs",
    "content": "﻿namespace QuestPDF.Drawing\n{\n    internal enum SpacePlanType\n    {\n        Empty,\n        Wrap,\n        PartialRender,\n        FullRender\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Alignment.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Alignment : ContainerElement\n    {\n        public VerticalAlignment? Vertical { get; set; }\n        public HorizontalAlignment? Horizontal { get; set; }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            var childMeasurement = base.Measure(availableSpace);\n            \n            if (childMeasurement.Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return;\n\n            var childSize = new Size(\n                Horizontal.HasValue ? childMeasurement.Width : availableSpace.Width,\n                Vertical.HasValue ? childMeasurement.Height : availableSpace.Height);\n\n            var top = GetTopOffset(availableSpace, childSize);\n            var left = GetLeftOffset(availableSpace, childSize);\n            \n            Canvas.Translate(new Position(left, top));\n            base.Draw(childSize);\n            Canvas.Translate(new Position(-left, -top));\n        }\n        \n        private float GetTopOffset(Size availableSpace, Size childSize)\n        {\n            var difference = availableSpace.Height - childSize.Height;\n\n            return Vertical switch\n            {\n                VerticalAlignment.Top => 0,\n                VerticalAlignment.Middle => difference / 2,\n                VerticalAlignment.Bottom => difference,\n                _ => 0\n            };\n        }\n        \n        private float GetLeftOffset(Size availableSpace, Size childSize)\n        {\n            var difference = availableSpace.Width - childSize.Width;\n\n            return Horizontal switch\n            {\n                HorizontalAlignment.Left => 0,\n                HorizontalAlignment.Center => difference / 2,\n                HorizontalAlignment.Right => difference,\n                _ => 0\n            };\n        }\n        \n        internal override string? GetCompanionHint() => $\"{Vertical} {Horizontal}\";\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/ArtifactTag.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements;\n\ninternal class ArtifactTag : ContainerElement, ISemanticAware\n{\n    public SemanticTreeManager? SemanticTreeManager { get; set; }\n    \n    public int Id { get; set; }\n    \n    internal override void Draw(Size availableSpace)\n    {\n        if (SemanticTreeManager == null)\n        {\n            base.Draw(availableSpace);\n            return;       \n        }\n        \n        using var semanticScope = Canvas.StartSemanticScopeWithNodeId(Id);\n        \n        SemanticTreeManager.BeginArtifactContent();\n        Child?.Draw(availableSpace);\n        SemanticTreeManager.EndArtifactContent();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/AspectRatio.cs",
    "content": "using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class AspectRatio : ContainerElement, IContentDirectionAware\n    {\n        public ContentDirection ContentDirection { get; set; }\n        \n        public float Ratio { get; set; }\n        public AspectRatioOption Option { get; set; } = AspectRatioOption.FitWidth;\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (Ratio == 0)\n                return SpacePlan.FullRender(0, 0);\n \n            if (Child.IsEmpty())\n                return SpacePlan.Empty();\n            \n            if (availableSpace.IsCloseToZero())\n                return SpacePlan.Wrap(\"The available space is zero.\");\n            \n            var targetSize = GetTargetSize(availableSpace);\n            \n            if (targetSize.Height > availableSpace.Height + Size.Epsilon)\n                return SpacePlan.Wrap(\"To preserve the target aspect ratio, the content requires more vertical space than available.\");\n            \n            if (targetSize.Width > availableSpace.Width + Size.Epsilon)\n                return SpacePlan.Wrap(\"To preserve the target aspect ratio, the content requires more horizontal space than available.\");\n\n            var childSize = base.Measure(targetSize);\n\n            if (childSize.Type == SpacePlanType.Wrap)\n                return childSize;\n\n            if (childSize.Type == SpacePlanType.PartialRender)\n                return SpacePlan.PartialRender(targetSize);\n\n            if (childSize.Type == SpacePlanType.FullRender)\n                return SpacePlan.FullRender(targetSize);\n            \n            throw new NotSupportedException();\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            var size = GetTargetSize(availableSpace);\n            \n            var offset = ContentDirection == ContentDirection.LeftToRight\n                ? Position.Zero\n                : new Position(availableSpace.Width - size.Width, 0);\n            \n            Canvas.Translate(offset);\n            base.Draw(size);\n            Canvas.Translate(offset.Reverse());\n        }\n        \n        private Size GetTargetSize(Size availableSpace)\n        {\n            if (Ratio == 0)\n                return availableSpace;\n            \n            var spaceRatio = availableSpace.Width / availableSpace.Height;\n\n            var fitHeight = new Size(availableSpace.Height * Ratio, availableSpace.Height) ;\n            var fitWidth = new Size(availableSpace.Width, availableSpace.Width / Ratio);\n\n            return Option switch\n            {\n                AspectRatioOption.FitWidth => fitWidth,\n                AspectRatioOption.FitHeight => fitHeight,\n                AspectRatioOption.FitArea => Ratio < spaceRatio ? fitHeight : fitWidth,\n                _ => throw new ArgumentOutOfRangeException()\n            };\n        }\n\n        internal override string? GetCompanionHint() => $\"{Option.ToString()} with ratio {Ratio:F1}\";\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Column.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class ColumnItemRenderingCommand\n    {\n        public Element Element { get; set; }\n        public SpacePlan Measurement { get; set; }\n        public Position Offset { get; set; }\n    }\n\n    internal sealed class Column : Element, IStateful\n    {\n        internal List<Element> Items { get; } = new();\n        internal float Spacing { get; set; }\n        \n        internal override IEnumerable<Element?> GetChildren()\n        {\n            return Items;\n        }\n        \n        internal override void CreateProxy(Func<Element?, Element?> create)\n        {\n            for (var i = 0; i < Items.Count; i++)\n                Items[i] = create(Items[i]);\n        }\n\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (!Items.Any())\n                return SpacePlan.Empty();\n            \n            if (CurrentRenderingIndex == Items.Count)\n                return SpacePlan.Empty();\n            \n            if (availableSpace.IsNegative())\n                return SpacePlan.Wrap(\"The available space is negative.\");\n            \n            var renderingCommands = PlanLayout(availableSpace);\n\n            if (!renderingCommands.Any())\n                return SpacePlan.Wrap(\"The available space is not sufficient for even partially rendering a single item.\");\n\n            var width = renderingCommands.Max(x => x.Measurement.Width);\n            var height = renderingCommands.Last().Offset.Y + renderingCommands.Last().Measurement.Height;\n            var size = new Size(width, height);\n            \n            if (width > availableSpace.Width + Size.Epsilon)\n                return SpacePlan.Wrap(\"The content requires more horizontal space than available.\");\n            \n            if (height > availableSpace.Height + Size.Epsilon)\n                return SpacePlan.Wrap(\"The content requires more vertical space than available.\");\n            \n            var totalRenderedItems = CurrentRenderingIndex + renderingCommands.Count(x => x.Measurement.Type is SpacePlanType.Empty or SpacePlanType.FullRender);\n            var willBeFullyRendered = totalRenderedItems == Items.Count;\n\n            return willBeFullyRendered\n                ? SpacePlan.FullRender(size)\n                : SpacePlan.PartialRender(size);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            var renderingCommands = PlanLayout(availableSpace);\n\n            foreach (var command in renderingCommands)\n            {\n                var targetSize = new Size(availableSpace.Width, command.Measurement.Height);\n\n                Canvas.Translate(command.Offset);\n                command.Element.Draw(targetSize);\n                Canvas.Translate(command.Offset.Reverse());\n            }\n            \n            var fullyRenderedItems = renderingCommands.Count(x => x.Measurement.Type is SpacePlanType.Empty or SpacePlanType.FullRender);\n            CurrentRenderingIndex += fullyRenderedItems;\n        }\n\n        private List<ColumnItemRenderingCommand> PlanLayout(Size availableSpace)\n        {\n            var topOffset = 0f;\n            var commands = new List<ColumnItemRenderingCommand>();\n\n            foreach (var item in Items.Skip(CurrentRenderingIndex))\n            {\n                var isFirstItem = commands.Count == 0;\n\n                var availableHeight = availableSpace.Height - topOffset;\n                \n                if (availableHeight < -Size.Epsilon)\n                    break;\n\n                availableHeight = Math.Max(0, availableHeight);\n                \n                if (!isFirstItem)\n                    availableHeight -= Spacing;\n\n                var allowOnlyZeroSpaceItems = availableHeight < Size.Epsilon;\n                \n                var itemSpace = allowOnlyZeroSpaceItems\n                    ? Size.Zero\n                    : new Size(availableSpace.Width, availableHeight);\n                \n                var measurement = item.Measure(itemSpace);\n                \n                if (measurement.Type == SpacePlanType.Wrap)\n                    break;\n\n                var currentItemTookSpace = !Size.Equal(measurement, Size.Zero);\n                \n                if (allowOnlyZeroSpaceItems && currentItemTookSpace)\n                    break;\n\n                if (!isFirstItem && currentItemTookSpace)\n                    topOffset += Spacing;\n                \n                commands.Add(new ColumnItemRenderingCommand\n                {\n                    Element = item,\n                    Measurement = measurement,\n                    Offset = new Position(0, topOffset)\n                });\n\n                if (measurement.Type == SpacePlanType.PartialRender)\n                    break;\n\n                topOffset += measurement.Height;\n            }\n\n            return commands;\n        }\n        \n        #region IStateful\n        \n        internal int CurrentRenderingIndex { get; set; }\n    \n        public void ResetState(bool hardReset = false) => CurrentRenderingIndex = 0;\n        public object GetState() => CurrentRenderingIndex;\n        public void SetState(object state) => CurrentRenderingIndex = (int) state;\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Constrained.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Constrained : ContainerElement, IContentDirectionAware\n    {\n        public ContentDirection ContentDirection { get; set; }\n        \n        public float? MinWidth { get; set; }\n        public float? MaxWidth { get; set; }\n\n        public float? MinHeight { get; set; }\n        public float? MaxHeight { get; set; }\n\n        public bool EnforceSizeWhenEmpty { get; set; }\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (MinWidth > MaxWidth)\n                return SpacePlan.Wrap($\"The minimum width {MinWidth} is greater than the maximum width {MaxWidth}.\");\n            \n            if (MinHeight > MaxHeight)\n                return SpacePlan.Wrap($\"The minimum height {MinHeight} is greater than the maximum height {MaxHeight}.\");\n            \n            if (!EnforceSizeWhenEmpty && Child.IsEmpty())\n                return SpacePlan.Empty();\n            \n            if (MinWidth > availableSpace.Width + Size.Epsilon)\n                return SpacePlan.Wrap(\"The available horizontal space is less than the minimum width.\");\n            \n            if (MinHeight > availableSpace.Height + Size.Epsilon)\n                return SpacePlan.Wrap(\"The available vertical space is less than the minimum height.\");\n            \n            var available = new Size(\n                Min(MaxWidth, availableSpace.Width),\n                Min(MaxHeight, availableSpace.Height));\n\n            var measurement = base.Measure(available);\n\n            if (measurement.Type == SpacePlanType.Wrap)\n                return measurement;\n            \n            var actualSize = new Size(\n                Max(MinWidth, measurement.Width),\n                Max(MinHeight, measurement.Height));\n            \n            if (measurement.Type == SpacePlanType.Empty)\n                return EnforceSizeWhenEmpty ? SpacePlan.FullRender(actualSize) : SpacePlan.Empty();\n            \n            if (measurement.Type == SpacePlanType.FullRender)\n                return SpacePlan.FullRender(actualSize);\n            \n            if (measurement.Type == SpacePlanType.PartialRender)\n                return SpacePlan.PartialRender(actualSize);\n            \n            throw new NotSupportedException();\n        }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            var size = new Size(\n                Min(MaxWidth, availableSpace.Width),\n                Min(MaxHeight, availableSpace.Height));\n            \n            var offset = ContentDirection == ContentDirection.LeftToRight\n                ? Position.Zero\n                : new Position(availableSpace.Width - size.Width, 0);\n            \n            Canvas.Translate(offset);\n            base.Draw(size);\n            Canvas.Translate(offset.Reverse());\n        }\n        \n        private static float Min(float? x, float y)\n        {\n            return x.HasValue ? Math.Min(x.Value, y) : y; \n        }\n        \n        private static float Max(float? x, float y)\n        {\n            return x.HasValue ? Math.Max(x.Value, y) : y;\n        }\n        \n        internal override string? GetCompanionHint()\n        {\n            var width = FormatRange(\"W\", MinWidth, MaxWidth);\n            var height = FormatRange(\"H\", MinHeight, MaxHeight);\n            \n            return string.Join(\"   \", width.Concat(height));\n\n            static IEnumerable<string> FormatRange(string prefix, float? min, float? max)\n            {\n                if (!min.HasValue && !max.HasValue)\n                    yield break;\n                \n                if (min == max)\n                {\n                    yield return $\"{prefix}={min:F1}\";\n                    yield break;\n                }\n\n                if (min.HasValue)\n                    yield return $\"{prefix}≥{min:F1}\";\n\n                if (max.HasValue)\n                    yield return $\"{prefix}≤{max:F1}\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Container.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal class Container : ContainerElement\n    {\n        internal Container()\n        {\n            \n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/ContentDirectionSetter.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class ContentDirectionSetter : ContainerElement\n    {\n        public ContentDirection ContentDirection { get; set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/DebugArea.cs",
    "content": "﻿using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class DebugArea : IComponent\n    {\n        public IElement? Child { get; set; }\n        \n        public string Text { get; set; }\n        public Color Color { get; set; } = Colors.Red.Medium;\n        public void Compose(IContainer container)\n        {\n            var backgroundColor = Color.WithAlpha(64);\n            \n            container\n                .Border(1)\n                .BorderColor(Color)\n                .Layers(layers =>\n                {\n                    layers.PrimaryLayer().Element(Child);\n                    layers.Layer().Background(backgroundColor);\n                    \n                    layers\n                        .Layer()\n                        .ShowIf(!string.IsNullOrWhiteSpace(Text))\n                        .AlignCenter()\n                        .Shrink()\n                        .Background(Colors.White)\n                        .Padding(2)\n                        .Text(Text)\n                        .FontColor(Color)\n                        .FontFamily(Fonts.Consolas)\n                        .FontSize(8);\n                });\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/DebugPointer.cs",
    "content": "﻿using System.Collections.Generic;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal enum DocumentStructureTypes\n    {\n        Document,\n        Page,\n        Background,\n        Foreground,\n        Header,\n        Content,\n        Footer\n    }\n    \n    internal enum DebugPointerType\n    {\n        DocumentStructure,\n        ElementStructure,\n        Component,\n        Section,\n        Dynamic,\n        UserDefined\n    }\n    \n    internal sealed class DebugPointer : ContainerElement\n    {\n        public DebugPointerType Type { get; set; }\n        public string Label { get; set; }\n        \n        internal override string? GetCompanionSearchableContent() => Label;\n\n        public DebugPointer()\n        {\n            \n        }\n        \n        public DebugPointer(DebugPointerType type, string label)\n        {\n            Type = type;\n            Label = label;\n        }\n        \n        internal override IEnumerable<KeyValuePair<string, string>>? GetCompanionProperties()\n        {\n            yield return new(\"Type\", Type.ToString());\n            yield return new(\"Label\", Label);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Decoration.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class DecorationElementLayout\n    {\n        public ItemCommand Before { get; set; }\n        public ItemCommand Content { get; set; }\n        public ItemCommand After { get; set; }\n        \n        public struct ItemCommand\n        {\n            public Element Element;\n            public SpacePlan Measurement;\n            public Position Offset;\n        }\n    }\n\n    internal sealed class Decoration : Element, IContentDirectionAware\n    {\n        public ContentDirection ContentDirection { get; set; }\n        \n        internal Element Before { get; set; } = new DebugPointer(DebugPointerType.ElementStructure, \"Before\");\n        internal Element Content { get; set; } = new DebugPointer(DebugPointerType.ElementStructure, \"Content\");\n        internal Element After { get; set; } = new DebugPointer(DebugPointerType.ElementStructure, \"After\");\n\n        internal override IEnumerable<Element?> GetChildren()\n        {\n            yield return Before;\n            yield return Content;\n            yield return After;\n        }\n        \n        internal override void CreateProxy(Func<Element?, Element?> create)\n        {\n            Before = create(Before);\n            Content = create(Content);\n            After = create(After);\n        }\n\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var layout = PlanLayout(availableSpace);\n\n            if (layout.Content.Measurement.Type == SpacePlanType.Empty)\n                return SpacePlan.Empty();\n            \n            if (layout.Content.Measurement.Type == SpacePlanType.Wrap)\n                return SpacePlan.Wrap(\"The primary content does not fit on the page.\");\n\n            if (layout.Before.Measurement.Type == SpacePlanType.Wrap)\n                return layout.Before.Measurement;\n            \n            if (layout.After.Measurement.Type == SpacePlanType.Wrap)\n                return layout.After.Measurement;\n            \n            var itemMeasurements = new[]\n            {\n                layout.Before.Measurement,\n                layout.Content.Measurement,\n                layout.After.Measurement\n            };\n            \n            var width = itemMeasurements.Max(x => x.Width);\n            var height = itemMeasurements.Sum(x => x.Height);\n            var size = new Size(width, height);\n            \n            if (width > availableSpace.Width + Size.Epsilon)\n                return SpacePlan.Wrap(\"The content slot requires more horizontal space than available.\");\n            \n            if (height > availableSpace.Height + Size.Epsilon)\n                return SpacePlan.Wrap(\"The content slot requires more vertical space than available.\");\n            \n            var willBeFullyRendered = itemMeasurements.All(x => x.Type is SpacePlanType.Empty or SpacePlanType.FullRender);\n\n            return willBeFullyRendered\n                ? SpacePlan.FullRender(size)\n                : SpacePlan.PartialRender(size);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            var layout = PlanLayout(availableSpace);\n            \n            var drawingCommands = new[]\n            {\n                layout.Before,\n                layout.Content,\n                layout.After\n            };\n            \n            var width = drawingCommands.Max(x => x.Measurement.Width);\n            \n            foreach (var command in drawingCommands)\n            {\n                var elementSize = new Size(width, command.Measurement.Height);\n                \n                var offset = ContentDirection == ContentDirection.LeftToRight\n                    ? command.Offset\n                    : new Position(availableSpace.Width - width, command.Offset.Y);\n                \n                Canvas.Translate(offset);\n                command.Element.Draw(elementSize);\n                Canvas.Translate(offset.Reverse());\n            }\n        }\n\n        private DecorationElementLayout PlanLayout(Size availableSpace)\n        {\n            SpacePlan GetDecorationMeasurement(Element element)\n            {\n                var measurement = element.Measure(availableSpace);\n\n                if (measurement.Type is SpacePlanType.PartialRender or SpacePlanType.Wrap)\n                    return SpacePlan.Wrap(\"Decoration slot (before or after) does not fit fully on the page.\");\n\n                return measurement;\n            }\n            \n            var beforeMeasurement = GetDecorationMeasurement(Before);\n            var afterMeasurement = GetDecorationMeasurement(After);\n            \n            var contentSpace = new Size(availableSpace.Width, availableSpace.Height - beforeMeasurement.Height - afterMeasurement.Height);\n            var contentMeasurement = Content.Measure(contentSpace);\n\n            return new DecorationElementLayout\n            {\n                Before = new DecorationElementLayout.ItemCommand\n                {\n                    Element = Before,\n                    Measurement = beforeMeasurement,\n                    Offset = Position.Zero\n                },\n                Content = new DecorationElementLayout.ItemCommand\n                {\n                    Element = Content,\n                    Measurement = contentMeasurement,\n                    Offset = new Position(0, beforeMeasurement.Height)\n                },\n                After = new DecorationElementLayout.ItemCommand\n                {\n                    Element = After,\n                    Measurement = afterMeasurement,\n                    Offset = new Position(0, beforeMeasurement.Height + contentMeasurement.Height)\n                },\n            };\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/DefaultTextStyle.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class DefaultTextStyle : ContainerElement\n    {\n        public TextStyle TextStyle { get; set; } = TextStyle.Default;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Dynamic.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class DynamicHost : Element, IStateful, IContentDirectionAware, ISemanticAware\n    {\n        public SemanticTreeManager? SemanticTreeManager { get; set; }\n        private SemanticTreeSnapshots? SemanticTreeSnapshots { get; set; }\n        \n        private DynamicComponentProxy Child { get; }\n        private object InitialComponentState { get; set; }\n\n        internal TextStyle TextStyle { get; set; } = TextStyle.Default;\n        public ContentDirection ContentDirection { get; set; }\n        \n        internal int? ImageTargetDpi { get; set; }\n        internal ImageCompressionQuality? ImageCompressionQuality { get; set; }\n        internal bool UseOriginalImage { get; set; }\n        \n        public DynamicHost(DynamicComponentProxy child)\n        {\n            Child = child;\n            InitialComponentState = Child.GetState();\n        }\n \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (IsRendered)\n                return SpacePlan.Empty();\n            \n            if (availableSpace.IsCloseToZero())\n                return SpacePlan.PartialRender(Size.Zero);\n\n            var context = CreateContext(availableSpace);\n            var result = ComposeContent(context, acceptNewState: false);\n            var content = result.Content as Element ?? Empty.Instance;\n            var measurement = content.Measure(availableSpace);\n            \n            context.DisposeCreatedElements();\n            content.ReleaseDisposableChildren();\n            \n            if (measurement.Type is SpacePlanType.PartialRender or SpacePlanType.Wrap)\n                throw new DocumentLayoutException(\"Dynamic component generated content that does not fit on a single page.\");\n            \n            return result.HasMoreContent \n                ? SpacePlan.PartialRender(measurement) \n                : SpacePlan.FullRender(measurement);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            SemanticTreeSnapshots ??= new SemanticTreeSnapshots(SemanticTreeManager, PageContext);\n            using var scope = SemanticTreeSnapshots.StartSemanticStateScope(RenderCount);\n            \n            var context = CreateContext(availableSpace);\n            var composeResult = ComposeContent(context, acceptNewState: true);\n            var content = composeResult.Content as Element; \n            content?.Draw(availableSpace);\n            \n            context.DisposeCreatedElements();\n            content.ReleaseDisposableChildren();\n            \n            if (!composeResult.HasMoreContent)\n                IsRendered = true;\n            \n            RenderCount++;\n        }\n\n        private DynamicContext CreateContext(Size availableSize)\n        {\n            return new DynamicContext\n            {\n                PageContext = PageContext,\n                Canvas = Canvas,\n                SemanticTreeManager = SemanticTreeManager,\n                \n                TextStyle = TextStyle,\n                ContentDirection = ContentDirection,\n                \n                ImageTargetDpi = ImageTargetDpi.Value,\n                ImageCompressionQuality = ImageCompressionQuality.Value,\n                UseOriginalImage = UseOriginalImage,\n                \n                PageNumber = PageContext.CurrentPage,\n                TotalPages = PageContext.IsInitialRenderingPhase ? int.MaxValue : PageContext.DocumentLength,\n                AvailableSize = availableSize\n            };\n        }\n        \n        private DynamicComponentComposeResult ComposeContent(DynamicContext context, bool acceptNewState)\n        {\n            var componentState = Child.GetState();\n            \n            var result = Child.Compose(context);\n\n            if (!acceptNewState)\n                Child.SetState(componentState);\n\n            return result;\n        }\n        \n        #region IStateful\n\n        public struct DynamicState\n        {\n            public int RenderCount;\n            public bool IsRendered;\n            public object ChildState;\n        }\n\n        private int RenderCount { get; set; } \n        private bool IsRendered { get; set; }\n    \n        public void ResetState(bool hardReset = false)\n        {\n            RenderCount = 0;\n            IsRendered = false;\n            Child.SetState(InitialComponentState);\n        }\n\n        public object GetState()\n        {\n            return new DynamicState  \n            {\n                RenderCount = RenderCount,\n                IsRendered = IsRendered,\n                ChildState = Child.GetState()\n            };\n        }\n\n        public void SetState(object state)\n        {\n            var dynamicState = (DynamicState) state;\n            \n            RenderCount = dynamicState.RenderCount;\n            IsRendered = dynamicState.IsRendered;\n            Child.SetState(dynamicState.ChildState);\n        }\n    \n        #endregion\n    }\n\n    /// <summary>\n    /// Stores all contextual information available for the dynamic component.\n    /// </summary>\n    public sealed class DynamicContext\n    {\n        internal IPageContext PageContext { get; set; }\n        internal IDrawingCanvas Canvas { get; set; }\n        internal SemanticTreeManager? SemanticTreeManager { get; set; }\n        \n        internal TextStyle TextStyle { get; set; }\n        internal ContentDirection ContentDirection { get; set; }\n\n        internal int ImageTargetDpi { get; set; }\n        internal ImageCompressionQuality ImageCompressionQuality { get; set; }\n        internal bool UseOriginalImage { get; set; }\n        \n        internal List<Element> CreatedElements { get; } = new();\n        \n        /// <summary>\n        /// Returns the number of the page being rendered at the moment.\n        /// </summary>\n        public int PageNumber { get; internal set; }\n        \n        /// <summary>\n        /// Returns the total count of pages in the document.\n        /// </summary>\n        /// <remarks>\n        /// <para>\n        /// Document rendering process is performed in two phases.\n        /// During the first phase, the value of this property is equal to <c>int.MaxValue</c> to indicate its unavailability.\n        /// </para>\n        /// <para>Please note that using this property may result with unstable layouts and unpredicted behaviors, especially when generating conditional content of various sizes.</para>\n        /// </remarks>\n        public int TotalPages { get; internal set; }\n        \n        /// <summary>\n        /// Returns the vertical and horizontal space, in points, available to the dynamic component.\n        /// </summary>\n        public Size AvailableSize { get; internal set; }\n        \n        /// <summary>\n        /// Returns all page locations of the captured element.\n        /// </summary>\n        public ICollection<PageElementLocation> GetContentCapturedPositions(string id)\n        {\n            return PageContext.GetContentCapturedPositions(id);\n        }\n\n        /// <summary>\n        /// Enables the creation of unattached layout structures and provides their size measurements.\n        /// </summary>\n        /// <param name=\"content\">The handler responsible for constructing the new layout structure.</param>\n        /// <returns>A newly created content, with its physical size.</returns>\n        public IDynamicElement CreateElement(Action<IContainer> content)\n        {\n            var container = new DynamicElement();\n            CreatedElements.Add(container);\n            content(container);\n            \n            if (SemanticTreeManager != null)\n            {\n                container.ApplySemanticParagraphs();\n                container.InjectSemanticTreeManager(SemanticTreeManager);\n            }\n            \n            container.ApplyInheritedAndGlobalTexStyle(TextStyle);\n            container.ApplyContentDirection(ContentDirection);\n            container.ApplyDefaultImageConfiguration(ImageTargetDpi, ImageCompressionQuality, UseOriginalImage);\n            container.InjectDependencies(PageContext, Canvas);\n            container.VisitChildren(x => (x as IStateful)?.ResetState());\n\n            container.Size = container.Measure(Size.Max);\n            \n            return container;\n        }\n        \n        internal void DisposeCreatedElements()\n        {\n            foreach (var element in CreatedElements)\n                element.ReleaseDisposableChildren();\n            \n            CreatedElements.Clear();\n        }\n    }\n\n    /// <summary>\n    /// Represents any unattached content element, created by the dynamic component.\n    /// </summary>\n    public interface IDynamicElement : IElement\n    {\n        /// <summary>\n        /// Specifies the vertical and horizontal size, measured in points, required by the element to be drawn completely, assuming infinite canvas.\n        /// </summary>\n        Size Size { get; }\n    }\n\n    internal sealed class DynamicElement : ContainerElement, IDynamicElement\n    {\n        public Size Size { get; internal set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/DynamicImage.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements\n{\n    public sealed class GenerateDynamicImageDelegatePayload\n    {\n        public Size AvailableSpace { get; set; }\n        public ImageSize ImageSize { get; set; }\n        public int Dpi { get; set; }\n    }\n    \n    /// <summary>\n    /// Generates an image based on the given resolution.\n    /// </summary>\n    /// <param name=\"size\">Desired resolution of the image in pixels.</param>\n    /// <param name=\"dpi\">Desired resolution of the image in dots per inch.</param>\n    /// <returns>An image in PNG, JPEG, or WEBP image format returned as byte array.</returns>\n    public delegate byte[]? GenerateDynamicImageDelegate(GenerateDynamicImageDelegatePayload payload);\n    \n    internal sealed class DynamicImage : Element, IStateful, IDisposable\n    {\n        internal int? TargetDpi { get; set; }\n        internal ImageCompressionQuality? CompressionQuality { get; set; }\n        internal bool UseOriginalImage { get; set; }\n        public GenerateDynamicImageDelegate? Source { get; set; }\n        \n        private List<(Size Size, SkImage? Image)> Cache { get; } = new(1);\n\n        private float GenerationTime { get; set; }\n        private int DrawnImageSize { get; set; }\n        \n        ~DynamicImage()\n        {\n            this.WarnThatFinalizerIsReached();\n            Dispose();\n        }\n\n        public void Dispose()\n        {\n            foreach (var cacheItem in Cache)\n                cacheItem.Image?.Dispose();\n            \n            Cache.Clear();\n            GC.SuppressFinalize(this);\n        }\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (IsRendered)\n                return SpacePlan.Empty();\n\n            if (availableSpace.IsNegative())\n                return SpacePlan.Wrap(\"The available space is negative.\");\n        \n            return SpacePlan.FullRender(availableSpace);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            var stopWatch = Stopwatch.StartNew();\n            \n            var targetImage = Cache.FirstOrDefault(x => Size.Equal(x.Size, availableSpace)).Image;\n            \n            if (targetImage == null)\n            {\n                targetImage = GetImage(availableSpace);\n                Cache.Add((availableSpace, targetImage));\n            }\n       \n            if (targetImage != null)\n                Canvas.DrawImage(targetImage, availableSpace);\n            \n            GenerationTime += (float) stopWatch.Elapsed.TotalMilliseconds;\n            DrawnImageSize += targetImage?.EncodedDataSize ?? 0;\n            \n            IsRendered = true;\n        }\n\n        private SkImage? GetImage(Size availableSpace)\n        {\n            var dpi = TargetDpi ?? DocumentSettings.DefaultRasterDpi;\n            \n            var sourcePayload = new GenerateDynamicImageDelegatePayload\n            {\n                AvailableSpace = availableSpace,\n                ImageSize = GetTargetResolution(availableSpace, dpi),\n                Dpi = dpi\n            };\n            \n            var imageBytes = Source?.Invoke(sourcePayload);\n            \n            if (imageBytes == null)\n                return null;\n\n            using var imageData = SkData.FromBinary(imageBytes);\n            var originalImage = SkImage.FromData(imageData);\n\n            if (UseOriginalImage)\n                return originalImage;\n            \n            var compressedImage = originalImage.CompressImage(CompressionQuality.Value);\n\n            if (originalImage.EncodedDataSize > compressedImage.EncodedDataSize)\n            {\n                originalImage.Dispose();\n                return compressedImage;\n            }\n            else\n            {\n                compressedImage.Dispose();\n                return originalImage;\n            }\n        }\n\n        private static ImageSize GetTargetResolution(Size availableSize, int targetDpi)\n        {\n            var scalingFactor = targetDpi / (float)DocumentSettings.DefaultRasterDpi;\n\n            return new ImageSize(\n                (int)(availableSize.Width * scalingFactor),\n                (int)(availableSize.Height * scalingFactor)\n            );\n        }\n        \n        #region IStateful\n        \n        private bool IsRendered { get; set; }\n    \n        public void ResetState(bool hardReset = false) => IsRendered = false;\n        public object GetState() => IsRendered;\n        public void SetState(object state) => IsRendered = (bool) state;\n    \n        #endregion\n        \n        internal override string? GetCompanionHint()\n        {\n            var sizeKB = Math.Max(1, DrawnImageSize / 1024);\n            return $\"{sizeKB}KB, generated in {GenerationTime:0.00}ms\";\n        }\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Elements/DynamicSvgImage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements;\n\ninternal sealed class DynamicSvgImage : Element, IStateful, IDisposable\n{\n    public GenerateDynamicSvgDelegate SvgSource { get; set; }\n\n    private List<(Size Size, SkSvgImage? Image)> Cache { get; } = new(1);\n    \n    ~DynamicSvgImage()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        foreach (var cacheItem in Cache)\n            cacheItem.Image?.Dispose();\n            \n        Cache.Clear();\n        GC.SuppressFinalize(this);\n    }\n    \n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        if (IsRendered)\n            return SpacePlan.Empty();\n\n        if (availableSpace.IsNegative())\n            return SpacePlan.Wrap(\"The available space is negative.\");\n        \n        return SpacePlan.FullRender(availableSpace);\n    }\n\n    internal override void Draw(Size availableSpace)\n    {\n        var targetImage = Cache.FirstOrDefault(x => Size.Equal(x.Size, availableSpace)).Image;\n            \n        if (targetImage == null)\n        {\n            targetImage = GetImage(availableSpace);\n            Cache.Add((availableSpace, targetImage));\n        }\n\n        if (targetImage != null)\n        {\n            var (widthScale, heightScale) = targetImage.CalculateSpaceScale(availableSpace);\n            \n            Canvas.Save();\n            Canvas.Scale(widthScale,  heightScale);\n            Canvas.DrawSvg(targetImage, availableSpace);\n            Canvas.Restore();\n        }\n            \n        IsRendered = true;\n    }\n    \n    private SkSvgImage? GetImage(Size availableSpace)\n    {\n        var svg = SvgSource?.Invoke(availableSpace);\n     \n        if (svg == null)\n            return null;\n\n        return new SkSvgImage(svg, SkResourceProvider.CurrentResourceProvider, FontManager.CurrentFontManager);\n    }\n    \n    #region IStateful\n    \n    private bool IsRendered { get; set; }\n    \n    public void ResetState(bool hardReset = false) => IsRendered = false;\n    public object GetState() => IsRendered;\n    public void SetState(object state) => IsRendered = (bool) state;\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/ElementPositionLocator.cs",
    "content": "using System.Numerics;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal class ElementPositionLocator : ContainerElement\n    {\n        public string Id { get; set; }\n\n        internal override void Draw(Size availableSpace)\n        {\n            base.Draw(availableSpace);\n\n            var transform = Canvas.GetCurrentMatrix().ToMatrix4x4();\n\n            var scaleX = new Vector2(transform.M11, transform.M12).Length();\n            var scaleY = new Vector2(transform.M21, transform.M22).Length();\n\n            var actualPosition = Vector2.Transform(Vector2.Zero, transform);\n\n            var position = new PageElementLocation\n            {\n                Id = Id,\n\n                PageNumber = PageContext.CurrentPage,\n\n                Width = availableSpace.Width * scaleX,\n                Height = availableSpace.Height * scaleY,\n\n                X = actualPosition.X,\n                Y = actualPosition.Y,\n                \n                Transform = transform\n            };\n\n            PageContext.CaptureContentPosition(position);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Empty.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Empty : Element\n    {\n        internal static Empty Instance { get; } = new();\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            return availableSpace.IsNegative() \n                ? SpacePlan.Wrap(\"The available space is negative.\") \n                : SpacePlan.FullRender(0, 0);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            \n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/EnsureSpace.cs",
    "content": "﻿using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class EnsureSpace : ContainerElement, IStateful\n    {\n        public const float DefaultMinHeight = 150;\n        public float MinHeight { get; set; } = DefaultMinHeight;\n\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var measurement = base.Measure(availableSpace);\n\n            if (IsFirstPageRendered)\n                return measurement;\n            \n            if (measurement.Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n                return measurement;\n\n            if (measurement.Type == SpacePlanType.PartialRender && MinHeight <= measurement.Height)\n                return measurement;\n            \n            return SpacePlan.PartialRender(Size.Zero);\n        }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            if (IsFirstPageRendered)\n            {\n                base.Draw(availableSpace);\n                return;\n            }\n\n            var measurement = base.Measure(availableSpace);\n            \n            if (measurement.Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n                base.Draw(availableSpace);\n            \n            if (measurement.Type is SpacePlanType.PartialRender && MinHeight <= measurement.Height)\n                base.Draw(availableSpace);\n            \n            IsFirstPageRendered = true;\n        }\n\n        internal override string? GetCompanionHint() => $\"at least {MinHeight}\";\n        \n        #region IStateful\n        \n        private bool IsFirstPageRendered { get; set; }\n\n        public void ResetState(bool hardReset = false)\n        {\n            if (hardReset)\n                IsFirstPageRendered = false;\n        }\n        \n        public object GetState() => IsFirstPageRendered;\n        public void SetState(object state) => IsFirstPageRendered = (bool) state;\n    \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Extend.cs",
    "content": "using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Extend : ContainerElement\n    {\n        public bool ExtendVertical { get; set; }\n        public bool ExtendHorizontal { get; set; }\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var childSize = base.Measure(availableSpace);\n\n            if (childSize.Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return childSize;\n            \n            var targetSize = GetTargetSize(availableSpace, childSize);\n            \n            if (childSize.Type == SpacePlanType.PartialRender)\n                return SpacePlan.PartialRender(targetSize);\n            \n            if (childSize.Type == SpacePlanType.FullRender)\n                return SpacePlan.FullRender(targetSize);\n            \n            throw new NotSupportedException();\n        }\n\n        private Size GetTargetSize(Size availableSpace, Size childSize)\n        {\n            return new Size(\n                ExtendHorizontal ? availableSpace.Width : childSize.Width, \n                ExtendVertical ? availableSpace.Height : childSize.Height);\n        }\n        \n        internal override string? GetCompanionHint()\n        {\n            return (ExtendVertical, ExtendHorizontal) switch\n            {\n                (true, true) => \"Both axes\",\n                (true, false) => \"Vertical axis\",\n                (false, true) => \"Horizontal axis\",\n                (false, false) => null\n            };\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Grid.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class GridElement\n    {\n        public int Columns { get; set; } = 1;\n        public Element? Child { get; set; }\n    }\n\n    internal sealed class Grid : IComponent\n    {\n        public const int DefaultColumnsCount = 12;\n        \n        public List<GridElement> Children { get; } = new List<GridElement>();\n        public Queue<GridElement> ChildrenQueue { get; set; } = new Queue<GridElement>();\n        public int ColumnsCount { get; set; } = DefaultColumnsCount;\n\n        public HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;\n        public float VerticalSpacing { get; set; } = 0;\n        public float HorizontalSpacing { get; set; } = 0;\n        \n        public void Compose(IContainer container)\n        {\n            ChildrenQueue = new Queue<GridElement>(Children);\n            \n            container.Column(column =>\n            {\n                column.Spacing(VerticalSpacing);\n                \n                while (ChildrenQueue.Any())\n                    column.Item().Row(BuildRow);\n            });\n        }\n        \n        IEnumerable<GridElement> GetRowElements()\n        {\n            var rowLength = 0;\n                \n            while (ChildrenQueue.Any())\n            {\n                var element = ChildrenQueue.Peek();\n                            \n                if (rowLength + element.Columns > ColumnsCount)\n                    break;\n\n                rowLength += element.Columns;\n                yield return ChildrenQueue.Dequeue();\n            }\n        }\n            \n        void BuildRow(RowDescriptor row)\n        {\n            row.Spacing(HorizontalSpacing);\n                \n            var elements = GetRowElements().ToList();\n            var columnsWidth = elements.Sum(x => x.Columns);\n            var emptySpace = ColumnsCount - columnsWidth;\n            var hasEmptySpace = emptySpace >= Size.Epsilon;\n\n            if (Alignment == HorizontalAlignment.Center)\n                emptySpace /= 2;\n            \n            if (hasEmptySpace && Alignment != HorizontalAlignment.Left)\n                row.RelativeItem(emptySpace);\n                \n            elements.ForEach(x => row.RelativeItem(x.Columns).Element(x.Child));\n\n            if (hasEmptySpace && Alignment != HorizontalAlignment.Right)\n                row.RelativeItem(emptySpace);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Hyperlink.cs",
    "content": "﻿using System.Collections.Generic;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Hyperlink : ContainerElement, IContentDirectionAware, ISemanticAware\n    {\n        public SemanticTreeManager? SemanticTreeManager { get; set; }\n        \n        public ContentDirection ContentDirection { get; set; }\n        public string Url { get; set; } = \"https://www.questpdf.com\";\n        public string? Description { get; set; }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            if (SemanticTreeManager?.IsCurrentContentArtifact() ?? false)\n            {\n                base.Draw(availableSpace);\n                return;\n            }\n            \n            var targetSize = base.Measure(availableSpace);\n\n            if (targetSize.Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return;\n            \n            var horizontalOffset = ContentDirection == ContentDirection.LeftToRight\n                ? Position.Zero\n                : new Position(availableSpace.Width - targetSize.Width, 0);\n\n            Canvas.Translate(horizontalOffset);\n            Canvas.DrawHyperlink(availableSpace, Url, Description);\n            Canvas.Translate(horizontalOffset.Reverse());\n            \n            base.Draw(availableSpace);\n        }\n\n        internal override string? GetCompanionHint() => Url;\n        \n        internal override IEnumerable<KeyValuePair<string, string>>? GetCompanionProperties()\n        {\n            yield return new(\"Url\", Url);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Image.cs",
    "content": "using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Image : Element, IStateful, IDisposable\n    {\n        public Infrastructure.Image? DocumentImage { get; set; }\n\n        internal bool UseOriginalImage { get; set; }\n        internal int? TargetDpi { get; set; }\n        internal ImageCompressionQuality? CompressionQuality { get; set; }\n \n        private int DrawnImageSize { get; set; }\n\n        ~Image()\n        {\n            this.WarnThatFinalizerIsReached();\n            Dispose();\n        }\n        \n        public void Dispose()\n        {\n            if (DocumentImage != null && !DocumentImage.IsShared) \n                DocumentImage?.Dispose();\n            \n            GC.SuppressFinalize(this);\n        }\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (IsRendered)\n                return SpacePlan.Empty();\n\n            if (availableSpace.IsNegative())\n                return SpacePlan.Wrap(\"The available space is negative.\");\n        \n            return SpacePlan.FullRender(Size.Zero);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            if (DocumentImage == null)\n                return;\n            \n            if (IsRendered)\n                return;\n\n            var image = GetImageToDraw(availableSpace);\n            Canvas.DrawImage(image, availableSpace);\n\n            DrawnImageSize = Math.Max(DrawnImageSize, image.EncodedDataSize);\n            \n            IsRendered = true;\n        }\n\n        private SkImage GetImageToDraw(Size availableSpace)\n        {\n            var originalImage = DocumentImage.SkImage;\n            \n            if (UseOriginalImage)\n                return originalImage;\n            \n            var request = new GetImageVersionRequest\n            {\n                Resolution = GetTargetResolution(DocumentImage.Size, availableSpace, TargetDpi.Value),\n                CompressionQuality = CompressionQuality.Value\n            };\n            \n            var targetImage = DocumentImage.GetVersionOfSize(request);\n            return Helpers.Helpers.GetImageWithSmallerSize(originalImage, targetImage);\n        }\n        \n        private static ImageSize GetTargetResolution(ImageSize imageResolution, Size availableAreaSize, int targetDpi)\n        {\n            var scalingFactor = targetDpi / (float)DocumentSettings.DefaultRasterDpi;\n            \n            var targetResolution = new ImageSize(\n                (int)(availableAreaSize.Width * scalingFactor), \n                (int)(availableAreaSize.Height * scalingFactor));\n            \n            var isImageResolutionSmallerThanTarget = imageResolution.Width < targetResolution.Width || imageResolution.Height < targetResolution.Height;\n\n            if (isImageResolutionSmallerThanTarget)\n                return imageResolution;\n\n            return targetResolution;\n        }\n        \n        #region IStateful\n        \n        private bool IsRendered { get; set; }\n    \n        public void ResetState(bool hardReset = false) => IsRendered = false;\n        public object GetState() => IsRendered;\n        public void SetState(object state) => IsRendered = (bool) state;\n    \n        #endregion\n\n        internal override string? GetCompanionHint()\n        {\n            var sizeKB = Math.Max(1, DrawnImageSize / 1024);\n            return $\"{sizeKB}KB\";\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Inlined.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal enum InlinedAlignment\n    {\n        Left,\n        Center,\n        Right,\n        Justify,\n        SpaceAround\n    }\n\n    internal struct InlinedMeasurement\n    {\n        public Element Element { get; set; }\n        public SpacePlan Size { get; set; }\n    }\n\n    internal sealed class Inlined : Element, IContentDirectionAware, IStateful\n    {\n        public List<Element> Elements { get; internal set; } = new();\n\n        public ContentDirection ContentDirection { get; set; }\n        \n        internal float VerticalSpacing { get; set; }\n        internal float HorizontalSpacing { get; set; }\n        \n        internal InlinedAlignment? ElementsAlignment { get; set; }\n        internal VerticalAlignment BaselineAlignment { get; set; }\n        \n        internal override IEnumerable<Element?> GetChildren()\n        {\n            return Elements;\n        }\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            SetDefaultAlignment();   \n            \n            if (CurrentRenderingIndex == Elements.Count)\n                return SpacePlan.Empty();\n            \n            var lines = Compose(availableSpace);\n\n            if (!lines.Any())\n                return SpacePlan.Wrap(\"The available space is not sufficient to fully render even a single item.\");\n\n            var lineSizes = lines\n                .Select(line =>\n                {\n                    var size = GetLineSize(line);\n\n                    var widthWithSpacing = size.Width + (line.Count - 1) * HorizontalSpacing;\n                    return new Size(widthWithSpacing, size.Height);\n                })\n                .ToList();\n            \n            var width = lineSizes.Max(x => x.Width);\n            var height = lineSizes.Sum(x => x.Height) + (lines.Count - 1) * VerticalSpacing;\n            var targetSize = new Size(width, height);\n\n            var totalRenderedItems = CurrentRenderingIndex + lines.Sum(x => x.Count);\n            var willBeFullyRendered = totalRenderedItems == Elements.Count;\n\n            return willBeFullyRendered\n                ? SpacePlan.FullRender(targetSize)\n                : SpacePlan.PartialRender(targetSize);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            // TODO: empty elements should not introduce spacing?\n            \n            SetDefaultAlignment();\n            \n            var lines = Compose(availableSpace);\n            var topOffset = 0f;\n            \n            foreach (var line in lines)\n            {\n                var height = line.Max(x => x.Size.Height);\n                \n                DrawLine(line);\n\n                topOffset += height + VerticalSpacing;\n                Canvas.Translate(new Position(0, height + VerticalSpacing));\n            }\n            \n            Canvas.Translate(new Position(0, -topOffset));\n            \n            var fullyRenderedItems = lines.Sum(x => x.Count);\n            CurrentRenderingIndex += fullyRenderedItems;\n\n            void DrawLine(ICollection<InlinedMeasurement> lineMeasurements)\n            {\n                var lineSize = GetLineSize(lineMeasurements);\n\n                var elementOffset = ElementOffset();\n                var leftOffset = AlignOffset();\n                \n                foreach (var measurement in lineMeasurements)\n                {\n                    var size = (Size)measurement.Size;\n                    var baselineOffset = BaselineOffset(size, lineSize.Height);\n\n                    if (size.Height == 0)\n                        size = new Size(size.Width, lineSize.Height);\n                    \n                    var offset = ContentDirection == ContentDirection.LeftToRight\n                        ? new Position(leftOffset, baselineOffset)\n                        : new Position(availableSpace.Width - size.Width - leftOffset, baselineOffset);\n                    \n                    Canvas.Translate(offset);\n                    measurement.Element.Draw(size);\n                    Canvas.Translate(offset.Reverse());\n\n                    leftOffset += size.Width + elementOffset;\n                }\n\n                float ElementOffset()\n                {\n                    var difference = availableSpace.Width - lineSize.Width;\n\n                    if (lineMeasurements.Count == 1)\n                        return 0;\n\n                    return ElementsAlignment switch\n                    {\n                        InlinedAlignment.Justify => difference / (lineMeasurements.Count - 1),\n                        InlinedAlignment.SpaceAround => difference / (lineMeasurements.Count + 1),\n                        _ => HorizontalSpacing\n                    };\n                }\n\n                float AlignOffset()\n                {\n                    var emptySpace = availableSpace.Width - lineSize.Width - (lineMeasurements.Count - 1) * HorizontalSpacing;\n\n                    return ElementsAlignment switch\n                    {\n                        InlinedAlignment.Left => ContentDirection == ContentDirection.LeftToRight ? 0 : emptySpace,\n                        InlinedAlignment.Justify => 0,\n                        InlinedAlignment.SpaceAround => elementOffset,\n                        InlinedAlignment.Center => emptySpace / 2,\n                        InlinedAlignment.Right => ContentDirection == ContentDirection.LeftToRight ? emptySpace : 0,\n                        _ => 0\n                    };\n                }\n                \n                float BaselineOffset(Size elementSize, float lineHeight)\n                {\n                    var difference = lineHeight - elementSize.Height;\n\n                    return BaselineAlignment switch\n                    {\n                        VerticalAlignment.Top => 0,\n                        VerticalAlignment.Middle => difference / 2,\n                        _ => difference\n                    };\n                }\n            }\n        }\n\n        void SetDefaultAlignment()\n        {\n            if (ElementsAlignment.HasValue)\n                return;\n\n            ElementsAlignment = ContentDirection == ContentDirection.LeftToRight\n                ? InlinedAlignment.Left\n                : InlinedAlignment.Right;\n        }\n\n        static Size GetLineSize(ICollection<InlinedMeasurement> measurements)\n        {\n            var width = measurements.Sum(x => x.Size.Width);\n            var height = measurements.Max(x => x.Size.Height);\n\n            return new Size(width, height);\n        }\n        \n        // list of lines, each line is a list of elements\n        private ICollection<ICollection<InlinedMeasurement>> Compose(Size availableSize)\n        {\n            var localRenderingIndex = CurrentRenderingIndex;\n            var result = new List<ICollection<InlinedMeasurement>>();\n\n            var topOffset = 0f;\n            \n            while (true)\n            {\n                var line = GetNextLine();\n                \n                if (!line.Any())\n                    break;\n\n                var height = line.Max(x => x.Size.Height);\n                \n                if (topOffset + height > availableSize.Height + Size.Epsilon)\n                    break;\n\n                topOffset += height + VerticalSpacing;\n                result.Add(line);\n            }\n\n            return result;\n\n            ICollection<InlinedMeasurement> GetNextLine()\n            {\n                var result = new List<InlinedMeasurement>();\n                var leftOffset = GetInitialAlignmentOffset();\n                \n                while (true)\n                {\n                    if (localRenderingIndex == Elements.Count)\n                        break;\n                    \n                    var element = Elements[localRenderingIndex];\n                    var size = element.Measure(new Size(availableSize.Width, Size.Max.Height));\n                    \n                    if (size.Type == SpacePlanType.Wrap)\n                        break;\n                    \n                    if (leftOffset + size.Width > availableSize.Width + Size.Epsilon)\n                        break;\n\n                    localRenderingIndex++;\n                    leftOffset += size.Width + HorizontalSpacing;\n                    \n                    result.Add(new InlinedMeasurement\n                    {\n                        Element = element,\n                        Size = size\n                    });    \n                }\n\n                return result;\n            }\n\n            float GetInitialAlignmentOffset()\n            {\n                // this method makes sure that the spacing between elements is no lesser than configured\n\n                return ElementsAlignment switch\n                {\n                    InlinedAlignment.SpaceAround => HorizontalSpacing * 2,\n                    _ => 0\n                };\n            }\n        }\n        \n        #region IStateful\n        \n        private int CurrentRenderingIndex { get; set; }\n    \n        public void ResetState(bool hardReset = false) => CurrentRenderingIndex = 0;\n        public object GetState() => CurrentRenderingIndex;\n        public void SetState(object state) => CurrentRenderingIndex = (int) state;\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Layers.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Layer : ContainerElement\n    {\n        public bool IsPrimary { get; set; }\n    }\n\n    internal sealed class Layers : Element\n    {\n        public List<Layer> Children { get; set; } = new();\n        \n        internal override IEnumerable<Element?> GetChildren()\n        {\n            return Children;\n        }\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var measurement = Children\n                .Single(x => x.IsPrimary)\n                .Measure(availableSpace);\n\n            if (measurement.Type == SpacePlanType.Wrap)\n                return SpacePlan.Wrap(\"The content of the primary layer does not fit (even partially) the available space.\");\n\n            return measurement;\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            Children\n                .Where(x => x.Measure(availableSpace).Type != SpacePlanType.Wrap)\n                .ToList()\n                .ForEach(x => x.Draw(availableSpace));\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Lazy.cs",
    "content": "using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements;\n\ninternal sealed class Lazy : ContainerElement, ISemanticAware, IContentDirectionAware, IStateful\n{\n    public SemanticTreeManager? SemanticTreeManager { get; set; }\n    private SemanticTreeSnapshots? SemanticTreeSnapshots { get; set; }\n    \n    public Action<IContainer> ContentSource { get; set; }\n    public bool IsCacheable { get; set; }\n\n    internal TextStyle TextStyle { get; set; } = TextStyle.Default;\n    public ContentDirection ContentDirection { get; set; }\n        \n    internal int? ImageTargetDpi { get; set; }\n    internal ImageCompressionQuality? ImageCompressionQuality { get; set; }\n    internal bool UseOriginalImage { get; set; }\n\n    internal bool ClearCacheAfterFullRender { get; set; } = true;\n    \n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        if (IsRendered)\n            return SpacePlan.Empty();\n        \n        PopulateContent();\n        return Child.Measure(availableSpace);\n    }\n        \n    internal override void Draw(Size availableSpace)\n    {\n        if (IsRendered)\n            return;\n        \n        SemanticTreeSnapshots ??= new SemanticTreeSnapshots(SemanticTreeManager, PageContext);\n        using var scope = SemanticTreeSnapshots.StartSemanticStateScope(RenderCount);\n        \n        PopulateContent();\n        \n        var isFullyRendered = Child?.Measure(availableSpace).Type == SpacePlanType.FullRender;\n        Child?.Draw(availableSpace);\n        RenderCount++;\n        \n        if (isFullyRendered && ClearCacheAfterFullRender)\n        {\n            IsRendered = true;\n            Child.ReleaseDisposableChildren();\n            Child = Empty.Instance;\n        }\n    }\n    \n    private void PopulateContent()\n    {\n        if (Child is not Empty)\n            return;\n        \n        var container = new Container();\n        Child = container;\n        ContentSource(container);\n        \n        if (SemanticTreeManager != null)\n        {\n            container.ApplySemanticParagraphs();\n            container.InjectSemanticTreeManager(SemanticTreeManager);\n        }\n        \n        container.ApplyInheritedAndGlobalTexStyle(TextStyle);\n        container.ApplyContentDirection(ContentDirection);\n        container.ApplyDefaultImageConfiguration(ImageTargetDpi.Value, ImageCompressionQuality.Value, UseOriginalImage);\n        container.InjectDependencies(PageContext, Canvas);\n        container.VisitChildren(x => (x as IStateful)?.ResetState());\n    }\n    \n    #region IStateful\n        \n    public struct LazyState\n    {\n        public int RenderCount;\n        public bool IsRendered;\n    }\n\n    private int RenderCount { get; set; } \n    private bool IsRendered { get; set; }\n\n    public void ResetState(bool hardReset = false)\n    {\n        if (hardReset)\n        {\n            IsRendered = false;\n            RenderCount = 0;\n        }\n    }\n\n    public object GetState()\n    {\n        return new LazyState\n        {\n            RenderCount = RenderCount,\n            IsRendered = IsRendered\n        };\n    }\n\n    public void SetState(object state)\n    {\n        var lazyState = (LazyState) state;\n        \n        RenderCount = lazyState.RenderCount;\n        IsRendered = lazyState.IsRendered;\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Line.cs",
    "content": "﻿using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements\n{\n    internal enum LineType\n    {\n        Vertical,\n        Horizontal\n    }\n\n    internal sealed class Line : Element, IStateful\n    {\n        public LineType Type { get; set; } = LineType.Vertical;\n        public Color Color { get; set; } = Colors.Black;\n        public float Thickness { get; set; } = 1;\n        public float[] DashPattern { get; set; } = [];\n        public Color[] GradientColors { get; set; } = [];\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (IsRendered)\n                return SpacePlan.Empty();\n            \n            // TODO: this code is defensive, taking into account conditions below, it is not needed\n            if (availableSpace.IsNegative())\n                return SpacePlan.Wrap(\"The available space is negative.\");\n\n            if (Type == LineType.Vertical)\n            {\n                if (Thickness.IsGreaterThan(availableSpace.Width))\n                    return SpacePlan.Wrap(\"The line thickness is greater than the available horizontal space.\");\n\n                return SpacePlan.FullRender(Thickness, 0);\n            }\n            \n            if (Type == LineType.Horizontal)\n            {\n                if (Thickness.IsGreaterThan(availableSpace.Height))\n                    return SpacePlan.Wrap(\"The line thickness is greater than the available vertical space.\");\n\n                return SpacePlan.FullRender(0, Thickness);\n            }\n\n            // Stryker disable once: unreachable code\n            throw new NotSupportedException();\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            if (IsRendered)\n                return;\n            \n            var start = Position.Zero;\n            \n            var end = Type == LineType.Vertical\n                ? new Position(0, availableSpace.Height)\n                : new Position(availableSpace.Width, 0);\n\n            using var paint = new SkPaint();\n            paint.SetStroke(Thickness);\n            paint.SetSolidColor(Color);\n            \n            if (GradientColors.Length > 0)\n                paint.SetLinearGradient(start, end, GradientColors);\n\n            if (DashPattern.Length > 0)\n                paint.SetDashedPathEffect(DashPattern);\n\n            var offset = Type == LineType.Vertical\n                ? new Position(Thickness / 2, 0)\n                : new Position(0, Thickness / 2);\n\n            using var semanticScope = Canvas.StartSemanticScopeWithNodeId(SkSemanticNodeSpecialId.LayoutArtifact);\n            \n            Canvas.Translate(offset);\n            Canvas.DrawLine(start, end, paint);\n            Canvas.Translate(offset.Reverse());\n            \n            IsRendered = true;\n        }\n        \n        #region IStateful\n        \n        private bool IsRendered { get; set; }\n    \n        public void ResetState(bool hardReset = false) => IsRendered = false;\n        public object GetState() => IsRendered;\n        public void SetState(object state) => IsRendered = (bool) state;\n    \n        #endregion\n        \n        internal override string? GetCompanionHint()\n        {\n            return $\"{Type} {Thickness.FormatAsCompanionNumber()}\";\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/MultiColumn.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Drawing.Proxy;\nusing QuestPDF.Elements.Text;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements;\n\ninternal sealed class MultiColumnChildDrawingObserver : ElementProxy\n{\n    public bool HasBeenDrawn => ChildStateBeforeDrawingOperation != null;\n    public object? ChildStateBeforeDrawingOperation { get; private set; }\n\n    internal override void Draw(Size availableSpace)\n    {\n        ChildStateBeforeDrawingOperation ??= (GetFirstElementChild() as IStateful).GetState();\n        Child.Draw(availableSpace);\n    }\n    \n    internal void ResetDrawingState()\n    {\n        ChildStateBeforeDrawingOperation = null;\n    }\n\n    internal void RestoreState()\n    {\n        (GetFirstElementChild() as IStateful)?.SetState(ChildStateBeforeDrawingOperation);\n    }\n\n    private Element GetFirstElementChild()\n    {\n        var child = Child;\n        \n        while (child is ElementProxy proxy)\n            child = proxy.Child;\n\n        return child;\n    }\n}\n\ninternal sealed class MultiColumn : Element, IContentDirectionAware, IDisposable\n{\n    // items\n    internal Element Content { get; set; } = Empty.Instance;\n    internal Element Spacer { get; set; } = Empty.Instance;\n    \n    // configuration\n    public int ColumnCount { get; set; } = 2;\n    public bool BalanceHeight { get; set; } = false;\n    public float Spacing { get; set; }\n    \n    public ContentDirection ContentDirection { get; set; }\n\n    // cache\n    private ProxyDrawingCanvas ChildrenCanvas { get; } = new();\n    private TreeNode<MultiColumnChildDrawingObserver>[] State { get; set; }\n\n    ~MultiColumn()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        ChildrenCanvas?.Dispose();\n        GC.SuppressFinalize(this);\n    }\n    \n    internal override void CreateProxy(Func<Element?, Element?> create)\n    {\n        Content = create(Content);\n        Spacer = create(Spacer);\n    }\n    \n    internal override IEnumerable<Element?> GetChildren()\n    {\n        yield return Content;\n        yield return Spacer;\n    }\n    \n    private void BuildState()\n    {\n        if (State != null)\n            return;\n        \n        this.VisitChildren(child =>\n        {\n            child.CreateProxy(x => x is IStateful ? new MultiColumnChildDrawingObserver { Child = x } : x);\n        });\n        \n        State = this.ExtractElementsOfType<MultiColumnChildDrawingObserver>().ToArray();\n    }\n\n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        BuildState();\n        OptimizeTextCacheBehavior();\n        \n        if (Content.Canvas != ChildrenCanvas)\n            Content.InjectDependencies(PageContext, ChildrenCanvas);\n        \n        ChildrenCanvas.Target = new DiscardDrawingCanvas();\n        \n        return FindPerfectSpace();\n\n        IEnumerable<SpacePlan> MeasureColumns(Size availableSpace)\n        {\n            var columnAvailableSpace = GetAvailableSpaceForColumn(availableSpace);\n            \n            foreach (var _ in Enumerable.Range(0, ColumnCount))\n            {\n                yield return Content.Measure(columnAvailableSpace);\n                Content.Draw(columnAvailableSpace);\n            }\n            \n            ResetObserverState(restoreChildState: true);\n        }\n        \n        SpacePlan FindPerfectSpace()\n        {\n            var defaultMeasurement = MeasureColumns(availableSpace).ToArray();\n\n            if (defaultMeasurement.First().Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return defaultMeasurement.First();\n            \n            var maxHeight = defaultMeasurement.Max(x => x.Height);\n            \n            if (defaultMeasurement.Last().Type is SpacePlanType.PartialRender or SpacePlanType.Wrap)\n                return SpacePlan.PartialRender(availableSpace.Width, maxHeight);\n            \n            if (!BalanceHeight)\n                return SpacePlan.FullRender(availableSpace.Width, maxHeight);\n\n            var minHeight = 0f;\n            maxHeight = availableSpace.Height;\n            \n            foreach (var _ in Enumerable.Range(0, 8))\n            {\n                var middleHeight = (minHeight + maxHeight) / 2;\n                var middleMeasurement = MeasureColumns(new Size(availableSpace.Width, middleHeight));\n                \n                if (middleMeasurement.Last().Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n                    maxHeight = middleHeight;\n                \n                else\n                    minHeight = middleHeight;\n            }\n            \n            return SpacePlan.FullRender(new Size(availableSpace.Width, maxHeight));\n        }\n    }\n\n    Size GetAvailableSpaceForColumn(Size totalSpace)\n    {\n        var columnWidth = (totalSpace.Width - Spacing * (ColumnCount - 1)) / ColumnCount;\n        return new Size(columnWidth, totalSpace.Height);\n    }\n    \n    internal override void Draw(Size availableSpace)\n    {\n        var contentAvailableSpace = GetAvailableSpaceForColumn(availableSpace);\n        var spacerAvailableSpace = new Size(Spacing, availableSpace.Height);\n\n        var horizontalOffset = 0f;\n        ChildrenCanvas.Target = Canvas;\n\n        foreach (var i in Enumerable.Range(1, ColumnCount))\n        {\n            var contentMeasurement = Content.Measure(contentAvailableSpace);\n            var targetColumnSize = new Size(contentAvailableSpace.Width, contentMeasurement.Height);\n\n            var contentOffset = GetTargetOffset(targetColumnSize.Width);\n            \n            Canvas.Translate(contentOffset);\n            Content.Draw(targetColumnSize);\n            Canvas.Translate(contentOffset.Reverse());\n            \n            horizontalOffset += contentAvailableSpace.Width;\n            \n            if (contentMeasurement.Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n                break;\n            \n            var spacerMeasurement = Spacer.Measure(spacerAvailableSpace);\n\n            if (i == ColumnCount || spacerMeasurement.Type is SpacePlanType.Wrap) \n                continue;\n            \n            var spacerOffset = GetTargetOffset(Spacing);\n            \n            Canvas.Translate(spacerOffset);\n            Spacer.Draw(spacerAvailableSpace);\n            Canvas.Translate(spacerOffset.Reverse());\n                \n            horizontalOffset += Spacing;\n        }\n        \n        ResetObserverState(restoreChildState: false);\n\n        Position GetTargetOffset(float contentWidth)\n        {\n            return ContentDirection == ContentDirection.LeftToRight\n                ? new Position(horizontalOffset, 0)\n                : new Position(availableSpace.Width - horizontalOffset - contentWidth, 0);\n        }\n    }\n    \n    void ResetObserverState(bool restoreChildState)\n    {\n        foreach (var node in State)\n            Traverse(node);\n            \n        void Traverse(TreeNode<MultiColumnChildDrawingObserver> node)\n        {\n            var observer = node.Value;\n\n            if (!observer.HasBeenDrawn)\n                return;\n\n            if (restoreChildState)\n                observer.RestoreState();\n            \n            observer.ResetDrawingState();\n                \n            foreach (var child in node.Children)\n                Traverse(child);\n        }\n    }\n    \n    #region Text Optimization\n\n    private bool IsTextOptimizationExecuted { get; set; } = false;\n    \n    /// <summary>\n    /// The TextBlock element uses SkParagraph cache to enhance rendering speed.\n    /// This cache uses a significant amount of memory and is cleared after FullRender.\n    /// However, the MultiColumn element uses a sophisticated measuring algorithm,\n    /// and may force the Text element to measure/render multiple times per page.\n    /// To avoid performance issues, the TextBlock element should keep its cache.\n    /// </summary>\n    private void OptimizeTextCacheBehavior()\n    {\n        if (IsTextOptimizationExecuted)\n            return;\n        \n        IsTextOptimizationExecuted = true;\n        \n        Content.VisitChildren(x =>\n        {\n            if (x is TextBlock text)\n                text.ClearInternalCacheAfterFullRender = false;\n        });\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Padding.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Padding : ContainerElement\n    {\n        public float Top { get; set; }\n        public float Right { get; set; }\n        public float Bottom { get; set; }\n        public float Left { get; set; }\n\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var internalSpace = InternalSpace(availableSpace);\n\n            if (internalSpace.IsNegative())\n                return Child.IsEmpty() ? SpacePlan.Empty() : SpacePlan.Wrap(\"The available space is negative.\");\n            \n            var measure = base.Measure(internalSpace);\n\n            if (measure.Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return measure;\n\n            var newWidth = Math.Max(0, measure.Width + Left + Right);\n            var newHeight = Math.Max(0, measure.Height + Top + Bottom);\n            \n            var newSize = new Size(\n                newWidth,\n                newHeight);\n            \n            if (measure.Type == SpacePlanType.PartialRender)\n                return SpacePlan.PartialRender(newSize);\n            \n            return SpacePlan.FullRender(newSize);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            var internalSpace = InternalSpace(availableSpace);\n            \n            Canvas.Translate(new Position(Left, Top));\n            base.Draw(internalSpace);\n            Canvas.Translate(new Position(-Left, -Top));\n        }\n\n        private Size InternalSpace(Size availableSpace)\n        {\n            return new Size(\n                availableSpace.Width - Left - Right,\n                availableSpace.Height - Top - Bottom);\n        }\n        \n        internal override string? GetCompanionHint()\n        {\n            return string.Join(\"   \", GetOptions().Where(x => x.value != 0).Select(x => $\"{x.Label}={x.value.FormatAsCompanionNumber()}\"));\n            \n            IEnumerable<(string Label, float value)> GetOptions()\n            {\n                if (Top == Bottom && Right == Left && Top == Right)\n                {\n                    yield return (\"A\", Top);\n                    yield break;\n                }\n\n                if (Top == Bottom && Right == Left)\n                {\n                    yield return (\"V\", Top);\n                    yield return (\"H\", Left);\n                    yield break;\n                }\n                \n                yield return (\"L\", Left);\n                yield return (\"T\", Top);\n                yield return (\"R\", Right);\n                yield return (\"B\", Bottom);\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Page.cs",
    "content": "using System;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Page : IComponent\n    {\n        public ContentDirection ContentDirection { get; set; }\n        public TextStyle DefaultTextStyle { get; set; } = TextStyle.Default;\n        \n        public Size? MinSize { get; set; }\n        public Size? MaxSize { get; set; }\n\n        public float MarginLeft { get; set; }\n        public float MarginRight { get; set; }\n        public float MarginTop { get; set; }\n        public float MarginBottom { get; set; }\n\n        public Color BackgroundColor { get; set; } = Colors.Transparent;\n        \n        public Element Background { get; set; } = Empty.Instance;\n        public Element Foreground { get; set; } = Empty.Instance;\n        \n        public Element Header { get; set; } = Empty.Instance;\n        public Element Content { get; set; } = Empty.Instance;\n        public Element Footer { get; set; } = Empty.Instance;\n\n        public void Compose(IContainer container)\n        {\n            SetDefaultPageSizeIfNotSpecified();\n            \n            container\n                .DebugPointer(DebugPointerType.DocumentStructure, DocumentStructureTypes.Page.ToString())\n                .ContentDirection(ContentDirection)\n                .DefaultTextStyle(DefaultTextStyle.DisableFontFeature(FontFeatures.StandardLigatures))\n                .Layers(layers =>\n                {\n                    layers.Layer()\n                        .ZIndex(int.MinValue)\n                        .Background(BackgroundColor);\n                    \n                    layers\n                        .Layer()\n                        .Repeat()\n                        .DebugPointer(DebugPointerType.DocumentStructure, DocumentStructureTypes.Background.ToString())\n                        .Artifact(SkSemanticNodeSpecialId.BackgroundArtifact)\n                        .Element(Background);\n                    \n                    layers\n                        .PrimaryLayer()\n                        \n                        .MinWidth(MinSize?.Width ?? 0)\n                        .MinHeight(MinSize?.Height ?? 0)\n                        .MaxWidth(MaxSize?.Width ?? Size.Max.Width)\n                        .MaxHeight(MaxSize?.Height ?? Size.Max.Height)\n                        .EnforceSizeWhenEmpty()\n                        \n                        .PaddingLeft(MarginLeft)\n                        .PaddingRight(MarginRight)\n                        .PaddingTop(MarginTop)\n                        .PaddingBottom(MarginBottom)\n                \n                        .Decoration(decoration =>\n                        {\n                            decoration\n                                .Before()\n                                .DebugPointer(DebugPointerType.DocumentStructure, DocumentStructureTypes.Header.ToString())\n                                .Element(Header);\n\n                            decoration\n                                .Content()\n                                .NonTrackingElement(x => (MinSize?.Width == MaxSize?.Width) ? x.ExtendHorizontal() : x)\n                                .NonTrackingElement(x => (MinSize?.Height == MaxSize?.Height) ? x.ExtendVertical() : x)\n                                .DebugPointer(DebugPointerType.DocumentStructure, DocumentStructureTypes.Content.ToString())\n                                .Element(Content);\n\n                            decoration\n                                .After()\n                                .DebugPointer(DebugPointerType.DocumentStructure, DocumentStructureTypes.Footer.ToString())\n                                .Element(Footer);\n                        });\n                    \n                    layers\n                        .Layer()\n                        .Repeat()\n                        .Artifact(SkSemanticNodeSpecialId.PaginationWatermarkArtifact)\n                        .DebugPointer(DebugPointerType.DocumentStructure, DocumentStructureTypes.Foreground.ToString())\n                        .Element(Foreground);\n                });\n        }\n\n        private void SetDefaultPageSizeIfNotSpecified()\n        {\n            if (MinSize.HasValue || MaxSize.HasValue)\n                return;\n\n            MinSize = PageSizes.A4;\n            MaxSize = PageSizes.A4;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/PageBreak.cs",
    "content": "﻿using QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class PageBreak : Element, IStateful\n    {\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (availableSpace.IsNegative())\n                return SpacePlan.Wrap(\"The available space is negative.\");\n\n            if (IsRendered)\n                return SpacePlan.Empty();\n\n            return SpacePlan.PartialRender(Size.Zero);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            IsRendered = true;\n        }\n        \n        #region IStateful\n        \n        private bool IsRendered { get; set; }\n    \n        public void ResetState(bool hardReset = false) => IsRendered = false;\n        public object GetState() => IsRendered;\n        public void SetState(object state) => IsRendered = (bool) state;\n    \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Placeholder.cs",
    "content": "﻿using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Placeholder : IComponent\n    {\n        public string Text { get; set; }\n\n        public void Compose(IContainer container)\n        {\n            const float imageSvgSize = 24f;\n            const string imageSvgPath = \"M19,19H5V5H19M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M13.96,12.29L11.21,15.83L9.25,13.47L6.5,17H17.5L13.96,12.29Z\";\n            \n            container\n                .Background(Colors.Grey.Lighten2)\n                .Padding(5)\n                .AlignMiddle()\n                .AlignCenter()\n                .Element(x =>\n                {\n                    if (string.IsNullOrWhiteSpace(Text))\n                        x.Height(imageSvgSize).Width(imageSvgSize).SvgPath(imageSvgPath, Colors.Black);\n                    \n                    else\n                        x.Text(Text).FontSize(14);\n                });\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/PreventPageBreak.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class PreventPageBreak : ContainerElement, IStateful\n    {\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var measurement = base.Measure(availableSpace);\n\n            if (IsFirstPageRendered)\n                return measurement;\n\n            if (measurement.Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n                return measurement;\n\n            return SpacePlan.PartialRender(Size.Zero);\n        }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            if (IsFirstPageRendered)\n            {\n                base.Draw(availableSpace);\n                return;\n            }\n\n            var measurement = base.Measure(availableSpace);\n            \n            if (measurement.Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n                base.Draw(availableSpace);\n        \n            IsFirstPageRendered = true;\n        }\n        \n        #region IStateful\n        \n        private bool IsFirstPageRendered { get; set; }\n\n        public void ResetState(bool hardReset = false)\n        {\n            if (hardReset)\n                IsFirstPageRendered = false;\n        }\n        \n        public object GetState() => IsFirstPageRendered;\n        public void SetState(object state) => IsFirstPageRendered = (bool) state;\n    \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/RepeatContent.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Elements.Text;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements;\n\ninternal sealed class RepeatContent : ContainerElement, IStateful, ISemanticAware\n{\n    public SemanticTreeManager? SemanticTreeManager { get; set; }\n    \n    public enum RepeatContextType\n    {\n        PageHeader,\n        PageFooter,\n        Other\n    }\n    \n    public RepeatContextType RepeatContext { get; set; } = RepeatContextType.Other;\n    \n    internal override void Draw(Size availableSpace)\n    {\n        OptimizeContentCacheBehavior();\n        \n        var childMeasurement = Child.Measure(availableSpace);\n\n        if (SemanticTreeManager == null)\n        {\n            base.Draw(availableSpace);\n            ResetChildrenIfNecessary();\n            return;      \n        }\n        \n        if (IsFullyRendered)\n        {\n            var paginationNodeId = RepeatContext switch\n            {\n                RepeatContextType.PageHeader => SkSemanticNodeSpecialId.PaginationHeaderArtifact,\n                RepeatContextType.PageFooter => SkSemanticNodeSpecialId.PaginationFooterArtifact,\n                _ => SkSemanticNodeSpecialId.PaginationArtifact\n            };\n        \n            using var semanticScope = Canvas.StartSemanticScopeWithNodeId(paginationNodeId);\n            \n            SemanticTreeManager.BeginArtifactContent();\n            base.Draw(availableSpace);\n            SemanticTreeManager.EndArtifactContent();\n        }\n        else\n        {\n            base.Draw(availableSpace);\n        }\n\n        ResetChildrenIfNecessary();\n\n        void ResetChildrenIfNecessary()\n        {\n            if (childMeasurement.Type != SpacePlanType.FullRender) \n                return;\n            \n            Child.VisitChildren(x => (x as IStateful)?.ResetState(false));\n            IsFullyRendered = true;\n        }\n    }\n    \n    #region Text Optimization\n\n    private bool IsContentOptimizationExecuted { get; set; } = false;\n    \n    /// <summary>\n    /// <para>\n    /// The TextBlock element uses SkParagraph cache to enhance rendering speed.\n    /// This cache uses a significant amount of memory and is cleared after FullRender.\n    /// However, when using the RepeatContent element, the cache is cleared after each repetition.\n    /// To avoid performance issues, the default behavior is disabled.\n    /// </para>\n    ///\n    /// <para>\n    /// Similarly, the Lazy element builds entire content on demand, waits to fully render it and then removes it.\n    /// This aims to optimize managed memory usage.\n    /// However, it may not be the most optimal solution in repeating context.\n    /// </para>\n    /// </summary>\n    private void OptimizeContentCacheBehavior()\n    {\n        if (IsContentOptimizationExecuted)\n            return;\n        \n        IsContentOptimizationExecuted = true;\n        \n        Child.VisitChildren(x =>\n        {\n            if (x is TextBlock text)\n                text.ClearInternalCacheAfterFullRender = false;\n            \n            if (x is Lazy lazy)\n                lazy.ClearCacheAfterFullRender = false;\n        });\n    }\n    \n    #endregion\n    \n    #region IStateful\n        \n    private bool IsFullyRendered { get; set; }\n\n    public void ResetState(bool hardReset = false)\n    {\n        if (hardReset)\n            IsFullyRendered = false;\n    }\n    \n    public object GetState() => IsFullyRendered;\n    public void SetState(object state) => IsFullyRendered = (bool) state;\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Rotate.cs",
    "content": "﻿using System;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Rotate : ContainerElement\n    {\n        public float Angle { get; set; } = 0;\n\n        internal override void Draw(Size availableSpace)\n        {\n            Canvas.Rotate(Angle);\n            Child?.Draw(availableSpace);\n            Canvas.Rotate(-Angle);\n        }\n\n        internal override string? GetCompanionHint()\n        {\n            if (Angle == 0)\n                return \"No rotation\";\n\n            var degrees = Math.Abs(Angle);\n            \n            // Stryker disable once equality: TurnCount = 0 is handled above\n            var direction = Angle > 0 ? \"clockwise\" : \"counter-clockwise\"; \n            \n            return $\"{degrees.FormatAsCompanionNumber()} deg {direction}\";\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Row.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal enum RowItemType\n    {\n        Auto,\n        Constant,\n        Relative\n    }\n\n    internal sealed class RowItem : ContainerElement\n    {\n        public bool IsRendered { get; set; }\n        public float Width { get; set; }\n        \n        public RowItemType Type { get; set; }\n        public float Size { get; set; }\n\n        internal override string? GetCompanionHint()\n        {\n            if (Type == RowItemType.Auto)\n                return \"Auto\";\n            \n            return $\"{Type} {Size.FormatAsCompanionNumber()}\";\n        }\n    }\n\n    internal sealed class RowItemRenderingCommand\n    {\n        public RowItem RowItem { get; set; }\n        public SpacePlan Measurement { get; set; }\n        public Size Size { get; set; }\n        public Position Offset { get; set; }\n    }\n\n    internal sealed class Row : Element, IStateful, IContentDirectionAware\n    {\n        public ContentDirection ContentDirection { get; set; }\n        \n        internal List<RowItem> Items { get; } = new();\n        internal float Spacing { get; set; }\n        \n        internal override IEnumerable<Element?> GetChildren()\n        {\n            return Items;\n        }\n\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (!Items.Any())\n                return SpacePlan.Empty();\n\n            if (Items.All(x => x.IsRendered))\n                return SpacePlan.Empty();\n            \n            UpdateItemsWidth(availableSpace.Width);\n            \n            if (Items.Any(x => x.Width.IsLessThan(0)))\n                return SpacePlan.Wrap(\"One of the items has a negative size, indicating insufficient horizontal space. Usually, constant items require more space than is available, potentially causing other content to overflow.\");\n            \n            var renderingCommands = PlanLayout(availableSpace);\n\n            if (renderingCommands.Any(x => !x.RowItem.IsRendered && x.Measurement.Type == SpacePlanType.Wrap))\n                return SpacePlan.Wrap(\"One of the items does not fit (even partially) in the available space.\");\n\n            var width = renderingCommands.Last().Offset.X + renderingCommands.Last().Size.Width;\n            var height = renderingCommands.Max(x => x.Size.Height);\n            var size = new Size(width, height);\n\n            if (width.IsGreaterThan(availableSpace.Width))\n                return SpacePlan.Wrap(\"The content requires more horizontal space than available.\");\n            \n            if (height.IsGreaterThan(availableSpace.Height))\n                return SpacePlan.Wrap(\"The content requires more vertical space than available.\");\n            \n            if (renderingCommands.Any(x => !x.RowItem.IsRendered && x.Measurement.Type == SpacePlanType.PartialRender))\n                return SpacePlan.PartialRender(size);\n\n            return SpacePlan.FullRender(size);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            if (!Items.Any())\n                return;\n\n            if (Items.All(x => x.IsRendered))\n                return;\n\n            UpdateItemsWidth(availableSpace.Width);\n            var renderingCommands = PlanLayout(availableSpace);\n\n            foreach (var command in renderingCommands)\n            {\n                if (command.Measurement.Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n                    command.RowItem.IsRendered = true;\n                \n                // TODO: investigate, as the final targetSize is still changed to use available vertical space\n                if (command.Measurement.Type is SpacePlanType.Wrap)\n                    continue;\n\n                var offset = ContentDirection == ContentDirection.LeftToRight\n                    ? command.Offset\n                    : new Position(availableSpace.Width - command.Offset.X - command.Size.Width, 0);\n\n                var targetSize = new Size(command.Size.Width, availableSpace.Height);\n                    \n                if (targetSize.Width.IsLessThan(0))\n                    continue;\n                \n                Canvas.Translate(offset);\n                command.RowItem.Draw(targetSize);\n                Canvas.Translate(offset.Reverse());\n            }\n        }\n\n        private void UpdateItemsWidth(float availableWidth)\n        {\n            foreach (var rowItem in Items.Where(x => x.Type == RowItemType.Auto && x.Size == 0))\n                rowItem.Size = rowItem.Measure(Size.Max).Width;\n            \n            var constantWidth = Items.Where(x => x.Type != RowItemType.Relative).Sum(x => x.Size);\n            var relativeWidth = Items.Where(x => x.Type == RowItemType.Relative).Sum(x => x.Size);\n            var spacingWidth = (Items.Count - 1) * Spacing;\n\n            foreach (var item in Items.Where(x => x.Type != RowItemType.Relative))\n                item.Width = item.Size;\n            \n            if (relativeWidth <= 0)\n                return;\n\n            var widthPerRelativeUnit = (availableWidth - constantWidth - spacingWidth) / relativeWidth;\n            \n            foreach (var item in Items.Where(x => x.Type == RowItemType.Relative))\n                item.Width = item.Size * widthPerRelativeUnit;\n        }\n        \n        private ICollection<RowItemRenderingCommand> PlanLayout(Size availableSpace)\n        {\n            var leftOffset = 0f;\n            var renderingCommands = new List<RowItemRenderingCommand>();\n\n            foreach (var item in Items)\n            {\n                var itemSpace = new Size(item.Width, availableSpace.Height);\n                \n                var command = new RowItemRenderingCommand\n                {\n                    RowItem = item,\n                    Size = itemSpace,\n                    Measurement = item.Measure(itemSpace),\n                    Offset = new Position(leftOffset, 0)\n                };\n                \n                renderingCommands.Add(command);\n                leftOffset += item.Width + Spacing;\n            }\n\n            // TODO: investigate\n            if (renderingCommands.Any(x => x.Measurement.Type == SpacePlanType.Wrap))\n                return renderingCommands;\n            \n            var rowHeight = renderingCommands\n                .Where(x => !x.RowItem.IsRendered)\n                .Select(x => x.Measurement.Height)\n                .DefaultIfEmpty(0)\n                .Max();\n            \n            foreach (var command in renderingCommands)\n            {\n                command.Size = new Size(command.Size.Width, rowHeight);\n                command.Measurement = command.RowItem.Measure(command.Size);\n            }\n            \n            return renderingCommands;\n        }\n        \n        #region IStateful\n        \n        // State is stored in the RowItem instances\n    \n        public void ResetState(bool hardReset = false)\n        {\n            foreach (var rowItem in Items)\n            {\n                rowItem.IsRendered = false;\n                \n                // required when the row contains items with text representing page numbers\n                if (rowItem.Type == RowItemType.Auto)\n                    rowItem.Size = 0;\n            }\n        }\n\n        public object GetState()\n        {\n            var result = new bool[Items.Count];\n            \n            for (var i = 0; i < Items.Count; i++)\n                result[i] = Items[i].IsRendered;\n            \n            return result;\n        }\n\n        public void SetState(object state)\n        {\n            var states = (bool[]) state;\n            \n            for (var i = 0; i < Items.Count; i++)\n                Items[i].IsRendered = states[i];\n        }\n    \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Scale.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Scale : ContainerElement\n    {\n        public float ScaleX { get; set; } = 1;\n        public float ScaleY { get; set; } = 1;\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var targetSpace = new Size(\n                Math.Abs(availableSpace.Width / ScaleX), \n                Math.Abs(availableSpace.Height / ScaleY));\n            \n            var measure = base.Measure(targetSpace);\n\n            if (measure.Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return measure;\n\n            var targetSize = new Size(\n                Math.Abs(measure.Width * ScaleX), \n                Math.Abs(measure.Height * ScaleY));\n\n            if (measure.Type == SpacePlanType.PartialRender)\n                return SpacePlan.PartialRender(targetSize);\n            \n            if (measure.Type == SpacePlanType.FullRender)\n                return SpacePlan.FullRender(targetSize);\n            \n            // Stryker disable once: unreachable code\n            throw new ArgumentException();\n        }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            var targetSpace = new Size(\n                Math.Abs(availableSpace.Width / ScaleX), \n                Math.Abs(availableSpace.Height / ScaleY));\n\n            var translate = new Position(\n                ScaleX < 0 ? availableSpace.Width : 0,\n                ScaleY < 0 ? availableSpace.Height : 0);\n            \n            Canvas.Translate(translate);\n            Canvas.Scale(ScaleX, ScaleY);\n            \n            Child?.Draw(targetSpace);\n             \n            Canvas.Scale(1/ScaleX, 1/ScaleY);\n            Canvas.Translate(translate.Reverse());\n        }\n        \n        internal override string? GetCompanionHint()\n        {\n            return string.Join(\"   \", GetOptions().Where(x => x.value != 1).Select(x => $\"{x.Label}={x.value.FormatAsCompanionNumber()}\"));\n            \n            IEnumerable<(string Label, float value)> GetOptions()\n            {\n                if (ScaleX == ScaleY)\n                {\n                    yield return (\"A\", ScaleX);\n                    yield break;\n                }\n                \n                yield return (\"H\", ScaleX);\n                yield return (\"V\", ScaleY);\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/ScaleToFit.cs",
    "content": "﻿using System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class ScaleToFit : ContainerElement\n    {\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var perfectScale = FindPerfectScale(availableSpace);\n\n            if (perfectScale == null)\n                return SpacePlan.Wrap(\"Cannot find the perfect scale to fit the child element in the available space.\");\n\n            var scaledSpace = ScaleSize(availableSpace, 1 / perfectScale.Value);\n            var childSizeInScale = base.Measure(scaledSpace);\n            var childSizeInOriginalScale = ScaleSize(childSizeInScale, perfectScale.Value);\n            return SpacePlan.FullRender(childSizeInOriginalScale);\n        }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            var perfectScale = FindPerfectScale(availableSpace);\n            \n            if (!perfectScale.HasValue)\n                return;\n\n            var targetScale = perfectScale.Value;\n            var targetSpace = ScaleSize(availableSpace, 1 / targetScale);\n            \n            Canvas.Scale(targetScale, targetScale);\n            Child?.Draw(targetSpace);\n            Canvas.Scale(1 / targetScale, 1 / targetScale);\n        }\n\n        private static Size ScaleSize(Size size, float factor)\n        {\n            return new Size(size.Width * factor, size.Height * factor);\n        }\n        \n        private float? FindPerfectScale(Size availableSpace)\n        {\n            if (ChildFits(1))\n                return 1;\n            \n            var maxScale = 1f;\n            var minScale = Size.Epsilon;\n\n            var lastWorkingScale = (float?)null;\n            \n            foreach (var _ in Enumerable.Range(0, 8))\n            {\n                var halfScale = (maxScale + minScale) / 2;\n\n                if (ChildFits(halfScale))\n                {\n                    minScale = halfScale;\n                    lastWorkingScale = halfScale;\n                }\n                else\n                {\n                    maxScale = halfScale;\n                }\n            }\n            \n            return lastWorkingScale;\n            \n            bool ChildFits(float scale)\n            {\n                var scaledSpace = ScaleSize(availableSpace, 1 / scale);\n                return base.Measure(scaledSpace).Type is SpacePlanType.Empty or SpacePlanType.FullRender;\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Section.cs",
    "content": "﻿using System.Collections.Generic;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Section : ContainerElement, IStateful\n    {\n        public string SectionName { get; set; }\n\n        internal override void Draw(Size availableSpace)\n        {\n            if (!IsRendered)\n            {\n                var targetName = PageContext.GetDocumentLocationName(SectionName);\n                Canvas.DrawSection(targetName);\n                IsRendered = true;\n            }\n            \n            PageContext.SetSectionPage(SectionName);\n            base.Draw(availableSpace);\n        }\n        \n        #region IStateful\n        \n        private bool IsRendered { get; set; }\n    \n        public void ResetState(bool hardReset = false) => IsRendered = false;\n        public object GetState() => IsRendered;\n        public void SetState(object state) => IsRendered = (bool) state;\n    \n        #endregion\n        \n        internal override string? GetCompanionHint() => SectionName;\n        internal override string? GetCompanionSearchableContent() => SectionName;\n        \n        internal override IEnumerable<KeyValuePair<string, string>>? GetCompanionProperties()\n        {\n            yield return new(\"SectionName\", SectionName);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/SectionLink.cs",
    "content": "﻿using System.Collections.Generic;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class SectionLink : ContainerElement\n    {\n        public string SectionName { get; set; }\n        public string? Description { get; set; }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            var targetSize = base.Measure(availableSpace);\n\n            if (targetSize.Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return;\n\n            var targetName = PageContext.GetDocumentLocationName(SectionName);\n            Canvas.DrawSectionLink(targetSize, targetName, Description);\n            base.Draw(availableSpace);\n        }\n\n        internal override string? GetCompanionHint() => SectionName;\n        internal override string? GetCompanionSearchableContent() => SectionName;\n        \n        internal override IEnumerable<KeyValuePair<string, string>>? GetCompanionProperties()\n        {\n            yield return new(\"SectionName\", SectionName);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/SemanticTag.cs",
    "content": "using System;\nusing System.Text;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Elements.Text;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements;\n\ninternal class SemanticTag : ContainerElement, ISemanticAware\n{\n    public SemanticTreeManager? SemanticTreeManager { get; set; }\n    public SemanticTreeNode? SemanticTreeNode { get; private set; }\n\n    public string TagType { get; set; }\n    public string? Alt { get; set; }\n    public string? Lang { get; set; }\n\n    internal override void Draw(Size availableSpace)\n    {\n        var shouldIgnoreSemanticMeaning =\n            Canvas.Is<DiscardDrawingCanvas>() ||\n            SemanticTreeManager == null ||\n            SemanticTreeManager.IsCurrentContentArtifact();\n        \n        if (shouldIgnoreSemanticMeaning)\n        {\n            Child?.Draw(availableSpace);\n            return;       \n        }\n        \n        RegisterCurrentSemanticNode();\n        \n        using var semanticScope = Canvas.StartSemanticScopeWithNodeId(SemanticTreeNode.NodeId);\n        \n        SemanticTreeManager.PushOnStack(SemanticTreeNode);\n        Child?.Draw(availableSpace);\n        SemanticTreeManager.PopStack();\n    }\n\n    internal void RegisterCurrentSemanticNode()\n    {\n        if (SemanticTreeNode != null)\n            return;\n        \n        if (TagType is \"H\" or \"H1\" or \"H2\" or \"H3\" or \"H4\" or \"H5\" or \"H6\")\n            UpdateHeaderText();\n        \n        if (TagType is \"Link\")\n            UpdateDescriptionOfInnerLink();\n        \n        var id = SemanticTreeManager.GetNextNodeId();\n            \n        SemanticTreeNode = new SemanticTreeNode\n        {\n            NodeId = id,\n            Type = TagType,\n            Alt = Alt,\n            Lang = Lang\n        };\n            \n        SemanticTreeManager.AddNode(SemanticTreeNode);\n    }\n\n    private void UpdateHeaderText()\n    {\n        if (!string.IsNullOrWhiteSpace(Alt))\n            return;\n        \n        var builder = new StringBuilder();\n        Traverse(builder, Child);\n        Alt = builder.ToString();\n        \n        static void Traverse(StringBuilder builder, Element element)\n        {\n            if (element is TextBlock textBlock)\n            {\n                if (builder.Length > 0)\n                    builder.Append(' ');\n                \n                builder.Append(textBlock.Text);\n            }\n            else if (element is ContainerElement container)\n            {\n                Traverse(builder, container.Child);\n            }\n            else\n            {\n                foreach (var child in element.GetChildren())\n                    Traverse(builder, child);\n            }\n        }\n    }\n    \n    private void UpdateDescriptionOfInnerLink()\n    {\n        if (string.IsNullOrWhiteSpace(Alt))\n            return;\n        \n        var currentChild = Child;\n        \n        while (currentChild != null)\n        {\n            if (currentChild is Hyperlink hyperlink)\n            {\n                hyperlink.Description = Alt;\n                return;\n            }\n            \n            if (currentChild is SectionLink sectionLink)\n            {\n                sectionLink.Description = Alt;\n                return;\n            }\n            \n            currentChild = (currentChild as ContainerElement)?.Child;\n        }\n    }\n\n    internal override string? GetCompanionHint()\n    {\n        var result = TagType;\n        \n        if (!string.IsNullOrWhiteSpace(Alt))\n            result += $\" ({Alt})\";\n        \n        return result;\n    }\n    \n    internal override string? GetCompanionSearchableContent() => TagType;\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/ShowEntire.cs",
    "content": "﻿using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class ShowEntire : ContainerElement\n    {\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var childMeasurement = base.Measure(availableSpace);\n            \n            if (childMeasurement.Type is SpacePlanType.Wrap)\n                return SpacePlan.Wrap(\"Child element does not fit (even partially) on the page.\");\n            \n            if (childMeasurement.Type is SpacePlanType.PartialRender)\n                return SpacePlan.Wrap(\"Child element fits only partially on the page.\");\n            \n            return childMeasurement;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/ShowIf.cs",
    "content": "using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements;\n\npublic sealed class ShowIfContext\n{\n    public int PageNumber { get; internal set; }\n    \n    /// <summary>\n    /// Returns the total count of pages in the document.\n    /// </summary>\n    /// <remarks>\n    /// <para>\n    /// Document rendering process is performed in two phases.\n    /// During the first phase, the value of this property is equal to <c>null</c> to indicate its unavailability.\n    /// </para>\n    /// <para>Please note that using this property may result with unstable layouts and unpredicted behaviors, especially when generating conditional content of various sizes.</para>\n    /// </remarks>\n    public int? TotalPages { get; internal set; }\n}\n\ninternal sealed class ShowIf : ContainerElement\n{\n    public Predicate<ShowIfContext> VisibilityPredicate { get; set; }\n    \n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        if (!CheckVisibility())\n            return SpacePlan.Empty();\n\n        return base.Measure(availableSpace);\n    }\n    \n    internal override void Draw(Size availableSpace)\n    {\n        if (CheckVisibility())\n            base.Draw(availableSpace);\n    }\n\n    private bool CheckVisibility()\n    {\n        var context = new ShowIfContext\n        {\n            PageNumber = PageContext.CurrentPage,\n            TotalPages = PageContext.IsInitialRenderingPhase ? null : PageContext.DocumentLength\n        };\n\n        return VisibilityPredicate(context);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/ShowOnce.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class ShowOnce : ContainerElement, IStateful\n    {\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (IsRendered)\n                return SpacePlan.Empty();\n            \n            return base.Measure(availableSpace);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            if (IsRendered)\n                return;\n            \n            if (base.Measure(availableSpace).Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n                IsRendered = true;\n            \n            base.Draw(availableSpace);\n        }\n        \n        #region IStateful\n        \n        private bool IsRendered { get; set; }\n\n        public void ResetState(bool hardReset = false)\n        {\n            if (hardReset)\n                IsRendered = false;\n        }\n        \n        public object GetState() => IsRendered;\n        public void SetState(object state) => IsRendered = (bool) state;\n    \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Shrink.cs",
    "content": "using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Shrink : ContainerElement, IContentDirectionAware\n    {\n        public bool Vertical { get; set; }\n        public bool Horizontal { get; set; }\n        \n        public ContentDirection ContentDirection { get; set; }\n\n        internal override void Draw(Size availableSpace)\n        {\n            var childSize = base.Measure(availableSpace);\n\n            if (childSize.Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return;\n            \n            var targetSize = new Size(\n                Horizontal ? childSize.Width : availableSpace.Width,\n                Vertical ? childSize.Height : availableSpace.Height);\n\n            var translate = ContentDirection == ContentDirection.RightToLeft\n                ? new Position(availableSpace.Width - targetSize.Width, 0)\n                : Position.Zero;\n\n            Canvas.Translate(translate);\n            base.Draw(targetSize);\n            Canvas.Translate(translate.Reverse());\n        }\n\n        internal override string? GetCompanionHint()\n        {\n            return (Vertical, Horizontal) switch\n            {\n                (true, true) => \"Both axes\",\n                (true, false) => \"Vertical axis\",\n                (false, true) => \"Horizontal axis\",\n                (false, false) => null,\n            };\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/SimpleRotate.cs",
    "content": "﻿using System;\nusing System.Text;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class SimpleRotate : ContainerElement\n    {\n        public int TurnCount { get; set; }\n        public int NormalizedTurnCount => (TurnCount % 4 + 4) % 4;\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (NormalizedTurnCount == 0 || NormalizedTurnCount == 2)\n                return base.Measure(availableSpace);\n            \n            availableSpace = new Size(availableSpace.Height, availableSpace.Width);\n            var childSpace = base.Measure(availableSpace);\n\n            if (childSpace.Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return childSpace;\n\n            var targetSpace = new Size(childSpace.Height, childSpace.Width);\n\n            if (childSpace.Type == SpacePlanType.FullRender)\n                return SpacePlan.FullRender(targetSpace);\n            \n            if (childSpace.Type == SpacePlanType.PartialRender)\n                return SpacePlan.PartialRender(targetSpace);\n\n            // Stryker disable once: unreachable code\n            throw new ArgumentException();\n        }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            var translate = new Position(\n                (NormalizedTurnCount == 1 || NormalizedTurnCount == 2) ? availableSpace.Width : 0,\n                (NormalizedTurnCount == 2 || NormalizedTurnCount == 3) ? availableSpace.Height : 0);\n\n            var rotate = NormalizedTurnCount * 90;\n            \n            Canvas.Translate(translate);\n            Canvas.Rotate(rotate);\n            \n            if (NormalizedTurnCount == 1 || NormalizedTurnCount == 3)\n                availableSpace = new Size(availableSpace.Height, availableSpace.Width);\n            \n            Child?.Draw(availableSpace);\n            \n            Canvas.Rotate(-rotate);\n            Canvas.Translate(translate.Reverse());\n        }\n\n        internal override string? GetCompanionHint()\n        {\n            if (TurnCount == 0)\n                return \"No rotation\";\n\n            var degrees = Math.Abs(TurnCount) * 90;\n            \n            // Stryker disable once equality: TurnCount = 0 is handled above\n            var direction = TurnCount > 0 ? \"clockwise\" : \"counter-clockwise\"; \n            \n            return $\"{degrees} deg {direction}\";\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/SkipOnce.cs",
    "content": "﻿using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class SkipOnce : ContainerElement, IStateful\n    {\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (!FirstPageWasSkipped)\n                return SpacePlan.Empty();\n\n            return base.Measure(availableSpace);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            if (FirstPageWasSkipped)\n                Child.Draw(availableSpace);\n\n            FirstPageWasSkipped = true;\n        }\n        \n        #region IStateful\n        \n        private bool FirstPageWasSkipped { get; set; }\n    \n        public void ResetState(bool hardReset = false)\n        {\n            if (hardReset)\n                FirstPageWasSkipped = false;\n        }\n\n        public object GetState() => FirstPageWasSkipped;\n        public void SetState(object state) => FirstPageWasSkipped = (bool) state;\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/SourceCodePointer.cs",
    "content": "using System.Collections.Generic;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements;\n\ninternal sealed class SourceCodePointer : ContainerElement\n{\n    public string MethodName { get; set; }\n    public string CalledFrom { get; set; }\n    public string FilePath { get; set; }\n    public int LineNumber { get; set; }\n    \n    internal override string? GetCompanionSearchableContent() => $\"{MethodName} {CalledFrom} {FilePath}\";\n\n    internal override IEnumerable<KeyValuePair<string, string>>? GetCompanionProperties()\n    {\n        yield return new(\"MethodName\", MethodName);\n        yield return new(\"CalledFrom\", CalledFrom);\n        yield return new(\"FilePath\", FilePath);\n        yield return new(\"LineNumber\", LineNumber.ToString());\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Elements/StopPaging.cs",
    "content": "﻿using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class StopPaging : ContainerElement\n    {\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var measurement = base.Measure(availableSpace);\n\n            return measurement.Type switch\n            {\n                SpacePlanType.Wrap => SpacePlan.FullRender(Size.Zero),\n                SpacePlanType.PartialRender => SpacePlan.FullRender(measurement),\n                SpacePlanType.FullRender => measurement,\n                SpacePlanType.Empty => measurement,\n                _ => throw new ArgumentOutOfRangeException()\n            };\n        }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            var measurement = base.Measure(availableSpace);\n            \n            if (measurement.Type is SpacePlanType.Wrap)\n                return;\n                \n            base.Draw(availableSpace);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/StyledBox.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class StyledBox : ContainerElement\n    {\n        public float BorderLeft { get; set; }\n        public float BorderTop { get; set; }\n        public float BorderRight { get; set; }\n        public float BorderBottom { get; set; }\n\n        private bool HasBorder =>\n            BorderLeft > 0 || \n            BorderTop > 0 || \n            BorderRight > 0 || \n            BorderBottom > 0;\n        \n        private bool HasFullBorder =>\n            BorderLeft > 0 && \n            BorderTop > 0 && \n            BorderRight > 0 && \n            BorderBottom > 0;\n\n        private bool HasUniformBorder =>\n            BorderLeft == BorderRight && \n            BorderTop == BorderBottom && \n            BorderLeft == BorderTop;\n    \n        public float BorderRadiusTopLeft { get; set; }\n        public float BorderRadiusTopRight { get; set; }\n        public float BorderRadiusBottomLeft { get; set; }\n        public float BorderRadiusBottomRight { get; set; }\n\n        private bool HasRoundedCorners =>\n            BorderRadiusTopLeft > 0 || \n            BorderRadiusTopRight > 0 || \n            BorderRadiusBottomLeft > 0 || \n            BorderRadiusBottomRight > 0;\n        \n        private bool HasUniformRoundedCorners =>\n            BorderRadiusTopLeft == BorderRadiusTopRight && \n            BorderRadiusBottomLeft == BorderRadiusBottomRight && \n            BorderRadiusTopLeft == BorderRadiusBottomLeft;\n  \n        public float? BorderAlignment { get; set; } // 0 = inset, 1 = outset\n    \n        public Color BackgroundColor { get; set; } = Colors.Transparent;\n        public Color[] BackgroundGradientColors { get; set; } = [];\n        public float? BackgroundGradientAngle { get; set; }\n\n        public Color BorderColor { get; set; } = Colors.Transparent;\n        public Color[] BorderGradientColors { get; set; } = [];\n        public float? BorderGradientAngle { get; set; }\n\n        private bool HasSimpleStyle => BackgroundGradientColors.Length == 0 && BorderGradientColors.Length == 0;\n        \n        public BoxShadowStyle? Shadow { get; set; }\n        \n        internal void AdjustBorderAlignment()\n        {\n            if (BorderAlignment != null) \n                return;\n\n            var shouldHaveInsetBorder = HasRoundedCorners;\n            BorderAlignment = shouldHaveInsetBorder ? 0f : 0.5f;\n        }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            AdjustBorderAlignment();\n\n            // optimization: do not perform expensive calls\n            if (Canvas is DiscardDrawingCanvas)\n            {\n                base.Draw(availableSpace);\n                return;\n            }\n            \n            using var backgroundPaint = GetBackgroundPaint(availableSpace);\n            using var borderPaint = GetBorderPaint(availableSpace);\n            \n            if (HasFullBorder && HasUniformBorder && !HasRoundedCorners && HasSimpleStyle && BorderAlignment == 0.5f && Shadow == null)\n            {\n                // optimization: draw a simple rectangle with border\n                if (backgroundPaint != null)\n                {\n                    using var semanticScope = Canvas.StartSemanticScopeWithNodeId(SkSemanticNodeSpecialId.BackgroundArtifact);\n                    Canvas.DrawRectangle(Position.Zero, availableSpace, backgroundPaint);\n                }\n                \n                base.Draw(availableSpace);\n                \n                if (borderPaint != null)\n                {\n                    borderPaint.SetStroke(BorderLeft);\n                    \n                    using var semanticScope = Canvas.StartSemanticScopeWithNodeId(SkSemanticNodeSpecialId.LayoutArtifact);\n                    Canvas.DrawRectangle(Position.Zero, availableSpace, borderPaint);\n                }\n                \n                return;\n            }\n            \n            var contentRect = GetPrimaryBorderRect(availableSpace);\n            var borderOuterRect = GetOuterRect(availableSpace);\n            var borderInnerRect = GetInnerRect(availableSpace);\n\n            if (Shadow != null)\n            {\n                var shadowRect = ExpandRoundedRect(contentRect, Shadow.Spread);\n\n                var canvasShadow = new SkBoxShadow\n                {\n                    OffsetX = Shadow.OffsetX,\n                    OffsetY = Shadow.OffsetY,\n                    Blur = Shadow.Blur,\n                    Color = Shadow.Color\n                };\n                \n                using var semanticScope = Canvas.StartSemanticScopeWithNodeId(SkSemanticNodeSpecialId.BackgroundArtifact);\n                Canvas.DrawShadow(shadowRect, canvasShadow);\n            }\n\n            if (HasRoundedCorners)\n            {\n                Canvas.Save();\n                Canvas.ClipRoundedRectangle(contentRect);\n            }\n\n            if (backgroundPaint != null)\n            {\n                using var semanticScope = Canvas.StartSemanticScopeWithNodeId(SkSemanticNodeSpecialId.BackgroundArtifact);\n                Canvas.DrawRectangle(Position.Zero, availableSpace, backgroundPaint);\n            }\n            \n            base.Draw(availableSpace);\n            \n            if (HasRoundedCorners)\n                Canvas.Restore();\n\n            if (borderPaint != null)\n            {\n                using var semanticScope = Canvas.StartSemanticScopeWithNodeId(SkSemanticNodeSpecialId.LayoutArtifact);\n                Canvas.DrawComplexBorder(borderInnerRect, borderOuterRect, borderPaint);\n            }\n        }\n\n        private (Position start, Position end) GetLinearGradientPositions(Size availableSpace, float angle)\n        {\n            if (angle == 0f)\n                return (Position.Zero, new Position(availableSpace.Width, 0));\n            \n            if (angle == 90f)\n                return (Position.Zero, new Position(0, availableSpace.Height));\n            \n            if (angle == 180f)\n                return (new Position(availableSpace.Width, 0), new Position(0, 0));\n            \n            if (angle == 270f)\n                return (new Position(0, availableSpace.Height), new Position(availableSpace.Width, availableSpace.Height));\n            \n            // other angles?\n            var rectanglePoints = new[]\n            {\n                Position.Zero,\n                new Position(availableSpace.Width, 0),\n                new Position(availableSpace.Width, availableSpace.Height),\n                new Position(0, availableSpace.Height)\n            };\n            \n            var angleInRadians = Math.PI * angle / 180f;\n            var linePoint = new Position(availableSpace.Width / 2f, availableSpace.Height / 2f);\n            \n            var projectedPoints = rectanglePoints\n                .Select(point => ProjectPointOntoLine(linePoint, (float)angleInRadians, point))\n                .ToArray();\n\n            var start = projectedPoints.OrderBy(p => p.X).First();\n            var end = projectedPoints.OrderByDescending(p => p.X).First();\n            \n            return (start, end);\n            \n            static Position ProjectPointOntoLine(Position linePoint, float lineAngleRadians, Position projectionPoint)\n            {\n                var dx = (float)Math.Cos(lineAngleRadians);\n                var dy = (float)Math.Sin(lineAngleRadians);\n        \n                var vx = projectionPoint.X - linePoint.X;\n                var vy = projectionPoint.Y - linePoint.Y;\n        \n                var t = vx * dx + vy * dy;\n        \n                return new Position(\n                    linePoint.X + dx * t,\n                    linePoint.Y + dy * t\n                );\n            }\n        }\n        \n        private SkPaint? GetBorderPaint(Size availableSpace)\n        {\n            if (BorderGradientColors.Length > 0)\n            {\n                var paint = new SkPaint();\n                var gradientPoints = GetLinearGradientPositions(availableSpace, BorderGradientAngle ?? 0);\n                paint.SetLinearGradient(gradientPoints.start, gradientPoints.end, BorderGradientColors);\n                return paint;\n            }\n            \n            if (BorderColor.Hex != Colors.Transparent.Hex)\n            {\n                var paint = new SkPaint();\n                paint.SetSolidColor(BorderColor);\n                return paint;\n            }\n\n            return null;\n        }\n        \n        private SkPaint? GetBackgroundPaint(Size availableSpace)\n        {\n            if (BackgroundGradientColors.Length > 0)\n            {\n                var paint = new SkPaint();\n                var gradientPoints = GetLinearGradientPositions(availableSpace, BackgroundGradientAngle ?? 0);\n                paint.SetLinearGradient(gradientPoints.start, gradientPoints.end, BackgroundGradientColors);\n                return paint;\n            }\n            \n            if (BackgroundColor.Hex != Colors.Transparent.Hex)\n            {\n                var paint = new SkPaint();\n                paint.SetSolidColor(BackgroundColor);\n                return paint;\n            }\n\n            return null;\n        }\n        \n        private SkRoundedRect GetPrimaryBorderRect(Size availableSpace)\n        {\n            return new SkRoundedRect\n            {\n                Rect = new SkRect\n                {\n                    Left = 0,\n                    Top = 0,\n                    Right = availableSpace.Width,\n                    Bottom = availableSpace.Height\n                },\n                TopLeftRadius = new SkPoint(BorderRadiusTopLeft, BorderRadiusTopLeft),\n                TopRightRadius = new SkPoint(BorderRadiusTopRight, BorderRadiusTopRight),\n                BottomLeftRadius = new SkPoint(BorderRadiusBottomLeft, BorderRadiusBottomLeft),\n                BottomRightRadius = new SkPoint(BorderRadiusBottomRight, BorderRadiusBottomRight)\n            };\n        }\n        \n        private SkRoundedRect GetBorderRectExpandedWithBorderThickness(Size availableSpace, float borderThicknessExpansionFactor)\n        {\n            var primaryRect = GetPrimaryBorderRect(availableSpace);\n            \n            return ExpandRoundedRect(\n                primaryRect, \n                borderThicknessExpansionFactor * BorderLeft,\n                borderThicknessExpansionFactor * BorderTop,\n                borderThicknessExpansionFactor * BorderRight,\n                borderThicknessExpansionFactor * BorderBottom);\n        }\n        \n        private SkRoundedRect GetOuterRect(Size availableSpace)\n        {\n            return GetBorderRectExpandedWithBorderThickness(availableSpace, BorderAlignment!.Value);\n        }\n        \n        private SkRoundedRect GetInnerRect(Size availableSpace)\n        {\n            return GetBorderRectExpandedWithBorderThickness(availableSpace, BorderAlignment!.Value - 1f);\n        }\n\n        private SkRoundedRect ExpandRoundedRect(SkRoundedRect rect, float all)\n        {\n            return ExpandRoundedRect(rect, all, all, all, all);\n        }\n        \n        private SkRoundedRect ExpandRoundedRect(SkRoundedRect input, float left, float top, float right, float bottom)\n        {\n            var rect = new SkRect\n            {\n                Left = input.Rect.Left - left,\n                Top = input.Rect.Top - top,\n                Right = input.Rect.Right + right,\n                Bottom = input.Rect.Bottom + bottom\n            };\n            \n            var hasRoundedCorners = \n                input.TopLeftRadius.X > 0 || \n                input.TopRightRadius.X > 0 || \n                input.BottomLeftRadius.X > 0 || \n                input.BottomRightRadius.X > 0;\n            \n            if (!hasRoundedCorners)\n                return new SkRoundedRect { Rect = rect };\n            \n            return new SkRoundedRect\n            {\n                Rect = rect,\n                TopLeftRadius = new SkPoint\n                {\n                    X = Math.Max(0, input.TopLeftRadius.X + left),\n                    Y = Math.Max(0, input.TopLeftRadius.Y + top)\n                },\n                TopRightRadius = new SkPoint\n                {\n                    X = Math.Max(0, input.TopRightRadius.X + right),\n                    Y = Math.Max(0, input.TopRightRadius.Y + top)\n                },\n                BottomLeftRadius = new SkPoint\n                {\n                    X = Math.Max(0, input.BottomLeftRadius.X + left),\n                    Y = Math.Max(0, input.BottomLeftRadius.Y + bottom)\n                },\n                BottomRightRadius = new SkPoint\n                {\n                    X = Math.Max(0, input.BottomRightRadius.X + right),\n                    Y = Math.Max(0, input.BottomRightRadius.Y + bottom)\n                }\n            };\n        }\n\n        internal IEnumerable<(string Type, string? Hint)> GetCompanionCustomContent()\n        {\n            // shadow\n            if (Shadow != null)\n                yield return (\"Shadow\", null);\n\n            // rounded corners\n            if (HasRoundedCorners)\n            {\n                if (HasUniformRoundedCorners)\n                    yield return (\"Border\", $\"R={BorderRadiusTopLeft}\");\n                else\n                    yield return (\"Border\", $\"TL={BorderRadiusTopLeft}   TR={BorderRadiusTopRight}   BL={BorderRadiusBottomLeft}   BR={BorderRadiusBottomRight}\");\n            }\n\n            // border\n            if (HasBorder)\n            {\n                var color = BorderGradientColors.Any() ? \"gradient\" : BorderColor.ToString();\n                \n                if (HasUniformBorder)\n                    yield return (\"Border\", $\"A={BorderLeft}   C={color}\");\n                else\n                    yield return (\"Border\", $\"L={BorderLeft}   T={BorderTop}   R={BorderRight}   B={BorderBottom}   C={color}\");\n            }\n\n            // background\n            if (BackgroundGradientColors.Length > 0)\n                yield return (\"Background\", $\"Gradient with {BackgroundGradientColors.Length} colors\");\n\n            else if (BackgroundColor.Hex != Colors.Transparent.Hex)\n                yield return (\"Background\", BackgroundColor);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/SvgImage.cs",
    "content": "using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements;\n\ninternal sealed class SvgImage : Element, IStateful, IDisposable\n{\n    public Infrastructure.SvgImage Image { get; set; }\n    \n    ~SvgImage()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Image != null && !Image.IsShared)\n            Image?.Dispose();\n        \n        GC.SuppressFinalize(this);\n    }\n    \n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        if (IsRendered)\n            return SpacePlan.Empty();\n\n        if (availableSpace.IsNegative())\n            return SpacePlan.Wrap(\"The available space is negative.\");\n        \n        return SpacePlan.FullRender(Size.Zero);\n    }\n\n    internal override void Draw(Size availableSpace)\n    {\n        if (IsRendered)\n            return;\n        \n        var (widthScale, heightScale) = Image.SkSvgImage.CalculateSpaceScale(availableSpace);\n\n        Canvas.Save();\n        Canvas.Scale(widthScale,  heightScale);\n        Canvas.DrawSvg(Image.SkSvgImage, availableSpace);\n        Canvas.Restore();\n        \n        IsRendered = true;\n    }\n    \n    #region IStateful\n    \n    private bool IsRendered { get; set; }\n    \n    public void ResetState(bool hardReset = false) => IsRendered = false;\n    public object GetState() => IsRendered;\n    public void SetState(object state) => IsRendered = (bool) state;\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/SvgPath.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Elements;\n\ninternal sealed class SvgPath : Element, IStateful\n{\n    public string Path { get; set; } = string.Empty;\n    public Color FillColor { get; set; } = Colors.Black;\n\n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        if (IsRendered)\n            return SpacePlan.Empty();\n\n        if (availableSpace.IsNegative())\n            return SpacePlan.Wrap(\"The available space is negative.\");\n        \n        return SpacePlan.FullRender(Size.Zero);\n    }\n\n    internal override void Draw(Size availableSpace)\n    {\n        if (IsRendered)\n            return;\n        \n        Canvas.DrawSvgPath(Path, FillColor);\n        IsRendered = true;\n    }\n    \n    #region IStateful\n    \n    private bool IsRendered { get; set; }\n    \n    public void ResetState(bool hardReset = false) => IsRendered = false;\n    public object GetState() => IsRendered;\n    public void SetState(object state) => IsRendered = (bool) state;\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Table/DynamicDictionary.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\n\nnamespace QuestPDF.Elements.Table\n{\n    /// <summary>\n    /// This dictionary allows to access key that does not exist.\n    /// Instead of throwing an exception, it returns a default value.\n    /// </summary>\n    internal sealed class DynamicDictionary<TKey, TValue>\n    {\n        private TValue Default { get; }\n        private IDictionary<TKey, TValue> Dictionary { get; } = new Dictionary<TKey, TValue>();\n\n        public DynamicDictionary()\n        {\n            \n        }\n        \n        public DynamicDictionary(TValue defaultValue)\n        {\n            Default = defaultValue;\n        }\n        \n        public TValue this[TKey key]\n        {\n            get => Dictionary.TryGetValue(key, out var value) ? value : Default;\n            set => Dictionary[key] = value;\n        }\n\n        public List<KeyValuePair<TKey, TValue>> Items => Dictionary.ToList();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Table/ITableCellContainer.cs",
    "content": "using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements.Table\n{\n    public interface ITableCellContainer : IContainer\n    {\n            \n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Table/Table.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements.Table\n{\n    internal sealed class Table : Element, IStateful, IContentDirectionAware, ISemanticAware\n    {\n        // configuration\n        public List<TableColumnDefinition> Columns { get; set; } = new();\n        public List<TableCell> Cells { get; set; } = new();\n        public bool ExtendLastCellsToTableBottom { get; set; }\n        \n        public ContentDirection ContentDirection { get; set; }\n        \n        // cache\n        private bool CacheInitialized { get; set; }\n        private bool HasRelativeColumns { get; set; }\n        private int LastRowIndex { get; set; }\n        private int RowsCount { get; set; }\n        private int MaxRow { get; set; }\n        private int MaxRowSpan { get; set; }\n        \n        // cache that stores all cells\n        // first index: row number\n        // inner table: list of all cells that ends at the corresponding row\n        private TableCell[][] CellsCache { get; set; }\n        \n        private bool IsRendered => CurrentRow > LastRowIndex;\n        \n        internal override IEnumerable<Element?> GetChildren()\n        {\n            return Cells;\n        }\n        \n        private void Initialize()\n        {\n            if (CacheInitialized)\n                return;\n\n            HasRelativeColumns = Columns.Any(x => x.RelativeSize > 0);\n            LastRowIndex = Cells.Select(x => x.Row + x.RowSpan - 1).DefaultIfEmpty(0).Max();\n            RowsCount = Cells.Select(x => x.Row + x.RowSpan - 1).DefaultIfEmpty(0).Max();\n            Cells = Cells.OrderBy(x => x.Row).ThenBy(x => x.Column).ToList();\n            BuildCache();\n\n            CacheInitialized = true;\n        }\n\n        private void BuildCache()\n        {\n            if (CellsCache != null)\n                return;\n\n            if (Cells.Count == 0)\n            {\n                MaxRow = 0;\n                MaxRowSpan = 1;\n                CellsCache = Array.Empty<TableCell[]>();\n                \n                return;\n            }\n            \n            var groups = Cells\n                .GroupBy(x => x.Row + x.RowSpan - 1)\n                .ToDictionary(x => x.Key, x => x.OrderBy(x => x.Column).ToArray());\n\n            MaxRow = groups.Max(x => x.Key);\n            MaxRowSpan = Cells.Max(x => x.RowSpan);\n\n            CellsCache = Enumerable\n                .Range(0, MaxRow + 1)\n                .Select(x => groups.TryGetValue(x, out var value) ? value : Array.Empty<TableCell>())\n                .ToArray();\n        }\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            Initialize();\n            \n            if (!Cells.Any())\n                return SpacePlan.Empty();\n            \n            if (IsRendered)\n                return SpacePlan.Empty();\n            \n            if (HasRelativeColumns && availableSpace.Width < Size.Epsilon)\n                return SpacePlan.Wrap(\"Insufficient space to render columns of relative size.\");\n            \n            UpdateColumnsWidth(availableSpace.Width);\n            var renderingCommands = PlanLayout(availableSpace);\n\n            if (!renderingCommands.Any())\n                return SpacePlan.Wrap(\"Insufficient space to render (even partially) a single row.\");\n            \n            var width = Columns.Sum(x => x.Width);\n            var height = renderingCommands.Max(x => x.Offset.Y + x.Size.Height);\n            var tableSize = new Size(width, height);\n\n            if (tableSize.Width > availableSpace.Width + Size.Epsilon)\n                return SpacePlan.Wrap(\"The content requires more horizontal space than available.\");\n\n            return CalculateCurrentRow(renderingCommands) > LastRowIndex \n                ? SpacePlan.FullRender(tableSize) \n                : SpacePlan.PartialRender(tableSize);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            Initialize();\n            RegisterSemanticTree();\n            \n            if (IsRendered)\n                return;\n            \n            UpdateColumnsWidth(availableSpace.Width);\n            var renderingCommands = PlanLayout(availableSpace);\n\n            foreach (var command in renderingCommands.OrderBy(x => x.Cell.ZIndex))\n            {\n                if (command.Measurement.Type is SpacePlanType.Empty or SpacePlanType.FullRender)\n                    command.Cell.IsRendered = true;\n\n                if (command.Measurement.Type == SpacePlanType.Wrap)\n                    continue;\n                \n                var offset = ContentDirection == ContentDirection.LeftToRight\n                    ? command.Offset\n                    : new Position(availableSpace.Width - command.Offset.X - command.Size.Width, command.Offset.Y);\n                \n                Canvas.Translate(offset);\n                command.Cell.Draw(command.Size);\n                Canvas.Translate(offset.Reverse());\n            }\n\n            CurrentRow = CalculateCurrentRow(renderingCommands);\n        }\n\n        private int CalculateCurrentRow(ICollection<TableCellRenderingCommand> commands)\n        {\n            if (!commands.Any())\n                return CurrentRow;\n\n            var notRenderedCells = commands\n                .Where(x => !x.Cell.IsRendered)\n                .Where(x => x.Measurement.Type is SpacePlanType.Wrap or SpacePlanType.PartialRender)\n                .ToList();\n            \n            if (notRenderedCells.Any())\n                return notRenderedCells.Min(x => x.Cell.Row + x.Cell.RowSpan - 1);\n                \n            return commands.Max(x => x.Cell.Row + x.Cell.RowSpan - 1) + 1;\n        }\n        \n        private void UpdateColumnsWidth(float availableWidth)\n        {\n            var constantWidth = Columns.Sum(x => x.ConstantSize);\n            var relativeWidth = Columns.Sum(x => x.RelativeSize);\n\n            var widthPerRelativeUnit = (relativeWidth > 0) ? (availableWidth - constantWidth) / relativeWidth : 0;\n            \n            foreach (var column in Columns)\n            {\n                column.Width = column.ConstantSize + column.RelativeSize * widthPerRelativeUnit;\n            }\n        }\n        \n        private ICollection<TableCellRenderingCommand> PlanLayout(Size availableSpace)\n        {\n            var columnOffsets = GetColumnLeftOffsets(Columns);\n            \n            var commands = GetRenderingCommands();\n\n            if (!commands.Any())\n                return commands;\n\n            if (ExtendLastCellsToTableBottom)\n            {\n                var tableHeight = commands.Max(cell => cell.Offset.Y + cell.Size.Height);\n                AdjustLastCellSizes(tableHeight, commands);\n            }\n\n            return commands;\n\n            static float[] GetColumnLeftOffsets(IList<TableColumnDefinition> columns)\n            {\n                var cellOffsets = new float[columns.Count + 1];\n                cellOffsets[0] = 0;\n\n                foreach (var column in Enumerable.Range(1, cellOffsets.Length - 1))\n                    cellOffsets[column] = columns[column - 1].Width + cellOffsets[column - 1];\n\n                return cellOffsets;\n            }\n            \n            ICollection<TableCellRenderingCommand> GetRenderingCommands()\n            {\n                var rowBottomOffsets = new DynamicDictionary<int, float>();\n                var commands = new List<TableCellRenderingCommand>();\n                \n                var cellsToTry = Enumerable\n                    .Range(CurrentRow, MaxRow - CurrentRow + 1)\n                    .SelectMany(x => CellsCache[x]);\n                \n                var currentRow = CurrentRow;\n                var maxRenderingRow = RowsCount;\n                \n                foreach (var cell in cellsToTry)\n                {\n                    // update position of previous row\n                    if (cell.Row > currentRow)\n                    {\n                        rowBottomOffsets[currentRow] = Math.Max(rowBottomOffsets[currentRow], rowBottomOffsets[currentRow - 1]);\n                            \n                        if (rowBottomOffsets[currentRow - 1] > availableSpace.Height + Size.Epsilon)\n                            break;\n\n                        foreach (var row in Enumerable.Range(currentRow + 1, cell.Row - (currentRow + 1)))\n                            rowBottomOffsets[row] = Math.Max(rowBottomOffsets[row - 1], rowBottomOffsets[row]);\n                        \n                        currentRow = cell.Row;\n                    }\n                    \n                    // cell visibility optimizations\n                    if (cell.Row > maxRenderingRow + MaxRowSpan)\n                        break;\n\n                    // calculate cell position / size\n                    var topOffset = rowBottomOffsets[cell.Row - 1];\n                    \n                    var availableWidth = GetCellWidth(cell);\n                    var availableHeight = availableSpace.Height - topOffset;\n                    var availableCellSize = new Size(availableWidth, availableHeight);\n\n                    var cellSize = cell.Measure(availableCellSize);\n\n                    // corner case: if cell within the row is not fully rendered, do not attempt to render next row\n                    if (cellSize.Type == SpacePlanType.PartialRender)\n                    {\n                        maxRenderingRow = Math.Min(maxRenderingRow, cell.Row + cell.RowSpan - 1);\n                    }\n\n                    // corner case: if cell within the row want to wrap to the next page, do not attempt to render this row\n                    if (cellSize.Type == SpacePlanType.Wrap)\n                    {\n                        maxRenderingRow = Math.Min(maxRenderingRow, cell.Row - 1);\n                        continue;\n                    }\n\n                    // update position of the last row that cell occupies\n                    var bottomRow = cell.Row + cell.RowSpan - 1;\n                    rowBottomOffsets[bottomRow] = Math.Max(rowBottomOffsets[bottomRow], topOffset + cellSize.Height);\n\n                    // accept cell to be rendered\n                    commands.Add(new TableCellRenderingCommand()\n                    {\n                        Cell = cell,\n                        Measurement = cellSize,\n                        Size = new Size(availableWidth, cellSize.Height),\n                        Offset = new Position(columnOffsets[cell.Column - 1], topOffset)\n                    });\n                }\n\n                if (!commands.Any())\n                    return commands;\n\n                var maxRow = commands.Select(x => x.Cell).Max(x => x.Row + x.RowSpan);\n\n                foreach (var row in Enumerable.Range(CurrentRow, maxRow - CurrentRow))\n                    rowBottomOffsets[row] = Math.Max(rowBottomOffsets[row - 1], rowBottomOffsets[row]);   \n\n                AdjustCellSizes(commands, rowBottomOffsets);\n                \n                // corner case: reject cell if other cells within the same row are rejected\n                return commands.Where(x => x.Cell.Row <= maxRenderingRow).ToList();\n            }\n            \n            // corner sase: if two cells end up on the same row (a.Row + a.RowSpan = b.Row + b.RowSpan),\n            // bottom edges of their bounding boxes should be at the same level\n            static void AdjustCellSizes(ICollection<TableCellRenderingCommand> commands, DynamicDictionary<int, float> rowBottomOffsets)\n            {\n                foreach (var command in commands)\n                {\n                    var lastRow = command.Cell.Row + command.Cell.RowSpan - 1;\n                    var height = rowBottomOffsets[lastRow] - command.Offset.Y;\n                    \n                    command.Size = new Size(command.Size.Width, height);\n                    command.Offset = new Position(command.Offset.X, rowBottomOffsets[command.Cell.Row - 1]);\n                }\n            }\n            \n            // corner sase: all cells, that are last ones in their respective columns, should take all remaining space\n            static void AdjustLastCellSizes(float tableHeight, ICollection<TableCellRenderingCommand> commands)\n            {\n                var columnsCount = commands.Select(x => x.Cell).Max(x => x.Column + x.ColumnSpan - 1);\n                \n                foreach (var column in Enumerable.Range(1, columnsCount))\n                {\n                    var lastCellInColumn = commands\n                        .Where(x => x.Cell.Column <= column && column < x.Cell.Column + x.Cell.ColumnSpan)\n                        .OrderByDescending(x => x.Cell.Row + x.Cell.RowSpan)\n                        .FirstOrDefault();\n                \n                    if (lastCellInColumn == null)\n                        continue;\n                \n                    lastCellInColumn.Size = new Size(lastCellInColumn.Size.Width, tableHeight - lastCellInColumn.Offset.Y);\n                }\n            }\n\n            float GetCellWidth(TableCell cell)\n            {\n                return columnOffsets[cell.Column + cell.ColumnSpan - 1] - columnOffsets[cell.Column - 1];\n            }\n        }\n        \n        #region IStateful\n        \n        private int CurrentRow { get; set; }\n        // state is also stored in TableCell instances\n    \n        public struct TableState\n        {\n            public bool[] CellsRenderingState;\n            public int CurrentRow;\n        }\n        \n        public void ResetState(bool hardReset = false)\n        {\n            foreach (var x in Cells)\n                x.IsRendered = false;\n            \n            CurrentRow = 1;\n        }\n\n        public object GetState()\n        {\n            var cellsRenderingState = new bool[Cells.Count];\n            \n            for (var i = 0; i < Cells.Count; i++)\n                cellsRenderingState[i] = Cells[i].IsRendered;\n            \n            return new TableState\n            {\n                CellsRenderingState = cellsRenderingState,\n                CurrentRow = CurrentRow\n            };\n        }\n\n        public void SetState(object state)\n        {\n            var tableState = (TableState) state;\n            \n            for (var i = 0; i < Cells.Count; i++)\n                Cells[i].IsRendered = tableState.CellsRenderingState[i];\n            \n            CurrentRow = tableState.CurrentRow;\n        }\n    \n        #endregion\n        \n        #region Semantic\n\n        internal enum TablePartType\n        {\n            Header,\n            Body,\n            Footer\n        }\n        \n        internal bool EnableAutomatedSemanticTagging { get; set; }\n        private bool IsSemanticTaggingApplied { get; set; }\n        public SemanticTreeManager? SemanticTreeManager { get; set; } = new();\n\n        internal bool TableRequiresAdvancedHeaderTagging { get; set; }\n        internal TablePartType PartType { get; set; }\n        public List<TableCell> HeaderCells { get; set; } = []; \n\n        private void RegisterSemanticTree()\n        {\n            if (SemanticTreeManager == null)\n                return;\n            \n            if (SemanticTreeManager.IsCurrentContentArtifact())\n                return;\n            \n            if (!EnableAutomatedSemanticTagging)\n                return;\n            \n            if (IsSemanticTaggingApplied)\n                return;\n            \n            IsSemanticTaggingApplied = true;\n            \n            foreach (var tableRow in Cells.GroupBy(x => x.Row))\n            {\n                var rowSemanticTreeNode = new SemanticTreeNode()\n                {\n                    NodeId = SemanticTreeManager.GetNextNodeId(), \n                    Type = \"TR\"\n                };\n                \n                SemanticTreeManager.AddNode(rowSemanticTreeNode);\n                SemanticTreeManager.PushOnStack(rowSemanticTreeNode);\n                \n                foreach (var tableCell in tableRow.OrderBy(x => x.Column))\n                {\n                    tableCell.CreateProxy(x => new SemanticTag\n                    {\n                        SemanticTreeManager = SemanticTreeManager,\n                        Canvas = Canvas,\n                        \n                        TagType = \"TD\",\n                        Child = x\n                    });\n\n                    if (tableCell.Child is not SemanticTag semanticTag)\n                        continue;\n                    \n                    if (PartType is TablePartType.Header || tableCell.IsSemanticHorizontalHeader)\n                        semanticTag.TagType = \"TH\";\n                    \n                    semanticTag.RegisterCurrentSemanticNode();\n                    tableCell.SemanticNodeId = semanticTag.SemanticTreeNode!.NodeId;\n                    \n                    AssignCellAttributesForColumnAndRowSpans(tableCell, semanticTag);\n                }\n                \n                SemanticTreeManager.PopStack();\n            }\n\n            AssignCellAttributesForHeaderCellRoles();\n            \n            static void AssignCellAttributesForColumnAndRowSpans(TableCell tableCell, SemanticTag semanticTag)\n            {\n                if (tableCell.ColumnSpan > 1)\n                {\n                    semanticTag.SemanticTreeNode.Attributes.Add(new SemanticTreeNode.Attribute\n                    {\n                        Owner = \"Table\",\n                        Name = \"ColSpan\",\n                        Value = tableCell.ColumnSpan\n                    });\n                }\n\n                if (tableCell.RowSpan > 1)\n                {\n                    semanticTag.SemanticTreeNode.Attributes.Add(new SemanticTreeNode.Attribute\n                    {\n                        Owner = \"Table\",\n                        Name = \"RowSpan\",\n                        Value = tableCell.RowSpan\n                    });\n                }\n            }\n\n            void AssignCellAttributesForHeaderCellRoles()\n            {\n                if (PartType is TablePartType.Footer)\n                    return;\n\n                if (TableRequiresAdvancedHeaderTagging)\n                {\n                    AssignCellAttributesForHeaderCellRolesOfComplexTables();\n                }\n                else\n                {\n                    AssignCellAttributesForHeaderCellRolesOfSimpleTables();\n                }\n            }\n            \n            void AssignCellAttributesForHeaderCellRolesOfSimpleTables()\n            {\n                foreach (var tableCell in Cells)\n                {\n                    if (tableCell.Child is not SemanticTag semanticTag)\n                        continue;\n\n                    if (semanticTag.TagType != \"TH\") \n                        continue;\n                    \n                    var scopeValue = (PartType is TablePartType.Header, tableCell.IsSemanticHorizontalHeader) switch\n                    {\n                        (true, true) => \"Both\",\n                        (true, false) => \"Column\",\n                        (false, true) => \"Row\",\n                        (false, false) => null\n                    };\n\n                    if (scopeValue == null)\n                        continue;\n                    \n                    semanticTag.SemanticTreeNode.Attributes.Add(new SemanticTreeNode.Attribute\n                    {\n                        Owner = \"Table\", \n                        Name = \"Scope\", \n                        Value = scopeValue\n                    });\n                }\n            }\n            \n            void AssignCellAttributesForHeaderCellRolesOfComplexTables()\n            {\n                var semanticHorizontalHeaders = Cells\n                    .Where(x => x.IsSemanticHorizontalHeader)\n                    .ToList();\n                \n                foreach (var tableCell in Cells)\n                {\n                    if (tableCell.Child is not SemanticTag semanticTag)\n                        continue;\n                    \n                    var relatedHeaders = GetRelatedHeadersFor(tableCell).ToArray();\n                    \n                    if (!relatedHeaders.Any())\n                        continue;\n                    \n                    semanticTag.SemanticTreeNode!.Attributes.Add(new SemanticTreeNode.Attribute\n                    {\n                        Owner = \"Table\",\n                        Name = \"Headers\",\n                        Value = relatedHeaders\n                    });\n                }\n\n                IEnumerable<int> GetRelatedHeadersFor(TableCell cell)\n                {\n                    var isHeader = PartType == TablePartType.Header;\n                    \n                    var headerCells = (isHeader ? Cells : HeaderCells).AsEnumerable();\n                    \n                    if (isHeader)\n                        headerCells = headerCells.Where(x => x.Row < cell.Row);\n                    \n                    var relatedVerticalHeaders = headerCells\n                        .Where(x => x.Column < cell.Column + cell.ColumnSpan && cell.Column < x.Column + x.ColumnSpan)\n                        .Select(x => x.SemanticNodeId);\n                    \n                    if (isHeader)\n                        return relatedVerticalHeaders; \n                    \n                    var relatedHorizontalHeaders = semanticHorizontalHeaders\n                        .Where(x => x.Column < cell.Column)\n                        .Where(x => x.Row < cell.Row + cell.RowSpan && cell.Row < x.Row + x.RowSpan)\n                        .Select(x => x.SemanticNodeId);\n                        \n                    return relatedVerticalHeaders.Concat(relatedHorizontalHeaders);\n                }\n            }\n        }\n        \n        public static bool DoesTableBodyRequireExtendedHeaderTagging(ICollection<TableCell> headerCells, ICollection<TableCell> bodyCells)\n        {\n            return ContainsSpanningCells(headerCells) || ContainsSpanningCells(bodyCells);\n                \n            static bool ContainsSpanningCells(IEnumerable<TableCell> cells) =>\n                cells.Any(x => x.RowSpan > 1 || x.ColumnSpan > 1);\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Table/TableCell.cs",
    "content": "using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements.Table\n{\n    internal sealed class TableCell : ContainerElement, ITableCellContainer\n    {\n        public int Row { get; set; } = 0;\n        public int RowSpan { get; set; } = 1;\n\n        public int Column { get; set; } = 0;\n        public int ColumnSpan { get; set; } = 1;\n        \n        public int ZIndex { get; set; }\n        \n        public bool IsSemanticHorizontalHeader { get; set; }\n        public int SemanticNodeId { get; set; }\n        \n        public bool IsRendered { get; set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Table/TableCellRenderingCommand.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements.Table\n{\n    internal sealed class TableCellRenderingCommand\n    {\n        public TableCell Cell { get; set; }\n        public SpacePlan Measurement { get; set; }\n        public Size Size { get; set; }\n        public Position Offset { get; set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Table/TableColumnDefinition.cs",
    "content": "namespace QuestPDF.Elements.Table\n{\n    internal sealed class TableColumnDefinition\n    {\n        public float ConstantSize { get; }\n        public float RelativeSize { get; }\n\n        internal float Width { get; set; }\n\n        public TableColumnDefinition(float constantSize, float relativeSize)\n        {\n            ConstantSize = constantSize;\n            RelativeSize = relativeSize;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Table/TableLayoutPlanner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace QuestPDF.Elements.Table\n{\n    static class TableLayoutPlanner\n    {\n        public static void PlanCellPositions(this Table table)\n        {\n            PlanCellPositions(table.Columns.Count, table.Cells);\n        }\n        \n        private static void PlanCellPositions(int columnsCount, ICollection<TableCell> cells)\n        {\n            var cellsWindow = new List<TableCell>();\n            (int x, int y) currentLocation = (1, 1);\n            var zIndex = 0;\n            \n            foreach (var cell in cells)\n            {\n                cell.ZIndex = zIndex;\n                zIndex++;\n                \n                if (cellsWindow.Count > Math.Max(columnsCount, 16))\n                {\n                    cellsWindow = cellsWindow\n                        .Where(x => x.Row + x.RowSpan > currentLocation.y)\n                        .ToList();\n                }\n\n                SetPartialLocation(cell);\n                \n                if (cell.HasLocation())\n                {\n                    cellsWindow.Add(cell);\n                    currentLocation = (cell.Column, cell.Row);\n                    continue;\n                }\n\n                foreach (var location in GenerateCoordinates(columnsCount, currentLocation))\n                {\n                    if (location.x + cell.ColumnSpan - 1 > columnsCount)\n                        continue;\n                    \n                    cell.Column = location.x;\n                    cell.Row = location.y;\n                    \n                    if (cell.CollidesWithAnyOf(cellsWindow))\n                        continue;\n\n                    cellsWindow.Add(cell);\n                    currentLocation = (cell.Column, cell.Row);\n                    break;\n                }\n            }\n        }\n        \n        private static IEnumerable<(int x, int y)> GenerateCoordinates(int columnsCount, (int x, int y) startPosition)\n        {\n            if (startPosition.x > columnsCount)\n                throw new ArgumentException();\n            \n            foreach (var x in Enumerable.Range(startPosition.x, columnsCount - startPosition.x + 1))\n                yield return (x, startPosition.y);\n\n            foreach (var y in Enumerable.Range(startPosition.y + 1, 1_000_000))\n            foreach (var x in Enumerable.Range(1, columnsCount))\n                yield return (x, y);\n        }\n\n        private static bool CollidesWith(this TableCell cell, TableCell neighbour)\n        {\n            return cell.Column < neighbour.Column + neighbour.ColumnSpan &&\n                   cell.Column + cell.ColumnSpan > neighbour.Column &&\n                   cell.Row < neighbour.Row + neighbour.RowSpan &&\n                   cell.RowSpan + cell.Row > neighbour.Row;\n        }\n        \n        private static bool CollidesWithAnyOf(this TableCell cell, ICollection<TableCell> neighbours)\n        {\n            return neighbours.Any(cell.CollidesWith);\n        }\n\n        private static void SetPartialLocation(this TableCell cell)\n        {\n            if (cell.Row == default && cell.Column == default)\n                return;\n\n            if (cell.Row == default)\n                cell.Row = 1;\n            \n            if (cell.Column == default)\n                cell.Column = 1;\n        }\n        \n        private static bool HasLocation(this TableCell cell)\n        {\n            return cell.Row != 0 && cell.Column != 0;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Table/TableLayoutValidator.cs",
    "content": "using System.Collections.Generic;\nusing QuestPDF.Drawing.Exceptions;\n\nnamespace QuestPDF.Elements.Table\n{\n    static class TableLayoutValidator\n    {\n        public static void ValidateCellPositions(this Table table)\n        {\n            ValidateCellPositions(table.Columns.Count, table.Cells);\n        }\n        \n        private static void ValidateCellPositions(int columnsCount, ICollection<TableCell> cells)\n        {\n            const string prefix = \"Detected issue in table cells configuration.\";\n            \n            foreach (var cell in cells)\n            {\n                if (cell.Column < 1)\n                    throw new DocumentComposeException($\"{prefix} A cell column position should be greater or equal to 1. Got {cell.Column}.\");\n                \n                if (cell.Row < 1)\n                    throw new DocumentComposeException($\"{prefix} A cell row position should be greater or equal to 1. Got {cell.Row}.\");\n                \n                if (cell.ColumnSpan < 1)\n                    throw new DocumentComposeException($\"{prefix} A cell must span at least one column. Got {cell.ColumnSpan}.\");\n                \n                if (cell.RowSpan < 1)\n                    throw new DocumentComposeException($\"{prefix} A cell must span at least one row. Got {cell.RowSpan}.\");\n                \n                if (cell.Column > columnsCount)\n                    throw new DocumentComposeException($\"{prefix} Cell starts at column that does not exist. Cell details: {GetCellDetails(cell)}.\");\n                \n                if (cell.Column + cell.ColumnSpan - 1 > columnsCount)\n                    throw new DocumentComposeException($\"{prefix} Table cell location is incorrect. Cell spans over columns that do not exist. Cell details: {GetCellDetails(cell)}.\");\n            }\n\n            string GetCellDetails(TableCell cell)\n            {\n                return $\"Row {cell.Row}, Column {cell.Column}, RowSpan {cell.RowSpan}, ColumnSpan {cell.ColumnSpan}\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Text/Items/ITextBlockItem.cs",
    "content": "﻿namespace QuestPDF.Elements.Text.Items\n{\n    internal interface ITextBlockItem\n    {\n        \n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Text/Items/TextBlockElement.cs",
    "content": "﻿using QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements.Text.Items\n{\n    internal sealed class TextBlockElement : ITextBlockItem\n    {\n        public Element Element { get; set; } = Empty.Instance;\n        public Size ElementSize { get; set; } = Size.Zero;\n        public TextInjectedElementAlignment Alignment { get; set; } = TextInjectedElementAlignment.AboveBaseline;\n        public int ParagraphBlockIndex { get; set; }\n\n        public void ConfigureElement(IPageContext pageContext, IDrawingCanvas canvas)\n        {\n            Element.VisitChildren(x => (x as IStateful)?.ResetState());\n            Element.InjectDependencies(pageContext, canvas);\n        }\n        \n        public void UpdateElementSize()\n        {\n            ElementSize = Element.Measure(Size.Max);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Text/Items/TextBlockHyperlink.cs",
    "content": "﻿namespace QuestPDF.Elements.Text.Items\n{\n    internal sealed class TextBlockHyperlink : TextBlockSpan\n    {\n        public string Url { get; set; }\n        public int ParagraphBeginIndex { get; set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Text/Items/TextBlockPageNumber.cs",
    "content": "﻿using System;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements.Text.Items\n{\n    internal sealed class TextBlockPageNumber : TextBlockSpan\n    {\n        public const string PageNumberPlaceholder = \"123\";\n        public Func<IPageContext, string> Source { get; set; } = _ => PageNumberPlaceholder;\n\n        public void UpdatePageNumberText(IPageContext context)\n        {\n            Text = Source(context) ?? PageNumberPlaceholder;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Text/Items/TextBlockParagraphSpacing.cs",
    "content": "namespace QuestPDF.Elements.Text.Items;\n\ninternal sealed class TextBlockParagraphSpacing : ITextBlockItem\n{\n    public float Width { get; }\n    public float Height { get; }\n\n    public TextBlockParagraphSpacing(float width, float height)\n    {\n        Width = width;\n        Height = height;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Text/Items/TextBlockSectionLink.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements.Text.Items\n{\n    internal sealed class TextBlockSectionLink : TextBlockSpan\n    {\n        public string SectionName { get; set; }\n        public int ParagraphBeginIndex { get; set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Text/Items/TextBlockSpan.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements.Text.Items\n{\n    internal class TextBlockSpan : ITextBlockItem\n    {\n        public string Text { get; set; }\n        public TextStyle Style { get; set; } = TextStyle.Default;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Text/SkParagraphBuilderPoolManager.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing QuestPDF.Drawing;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Elements.Text;\n\ninternal static class SkParagraphBuilderPoolManager\n{\n    private static ConcurrentDictionary<ParagraphStyle, ConcurrentBag<SkParagraphBuilder>> ObjectPool { get; } = new();\n\n    public static SkParagraphBuilder Get(ParagraphStyle style)\n    {\n        var specificPool = GetPool(style);\n        \n        if (specificPool.TryTake(out var builder))\n            return builder;\n        \n        var fontCollection = SkFontCollection.Create(FontManager.TypefaceProvider, FontManager.CurrentFontManager);\n        return SkParagraphBuilder.Create(style, fontCollection);\n    }\n\n    public static void Return(SkParagraphBuilder builder)\n    {\n        builder.Reset();\n        \n        var specificPool = GetPool(builder.Style);\n        specificPool.Add(builder);\n    }\n\n    private static ConcurrentBag<SkParagraphBuilder> GetPool(ParagraphStyle style)\n    {\n        return ObjectPool.GetOrAdd(style, _ => new ConcurrentBag<SkParagraphBuilder>());\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Text/TextBlock.cs",
    "content": "﻿using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements.Text.Items;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Elements.Text\n{\n    internal sealed class TextBlock : Element, IStateful, IContentDirectionAware, IDisposable\n    {\n        // content\n        public List<ITextBlockItem> Items { get; set; } = new();\n        \n        // configuration\n        public TextHorizontalAlignment? Alignment { get; set; }\n        public ContentDirection ContentDirection { get; set; }\n        \n        public int? LineClamp { get; set; }\n        public string LineClampEllipsis { get; set; }\n\n        public float ParagraphSpacing { get; set; }\n        public float ParagraphFirstLineIndentation { get; set; }\n        \n        public TextStyle DefaultTextStyle { get; set; } = TextStyle.Default;\n        \n        // cache\n        private bool RebuildParagraphForEveryPage { get; set; }\n        private bool AreParagraphMetricsValid { get; set; }\n        private bool AreParagraphItemsTransformedWithSpacingAndIndentation { get; set; }\n        \n        private SkSize[] LineMetrics { get; set; }\n        private float WidthForLineMetricsCalculation { get; set; }\n        private float MaximumWidth { get; set; }\n        private SkRect[] PlaceholderPositions { get; set; }\n        private bool? ContainsOnlyWhiteSpace { get; set; }\n        \n        // native objects\n        private SkParagraph Paragraph { get; set; }\n        internal bool ClearInternalCacheAfterFullRender { get; set; } = true;\n\n        public string Text => string.Join(\" \", Items.OfType<TextBlockSpan>().Select(x => x.Text));\n\n        ~TextBlock()\n        {\n            if (Paragraph == null)\n                return;\n            \n            this.WarnThatFinalizerIsReached();\n            Dispose();\n        }\n\n        public void Dispose()\n        {\n            Paragraph?.Dispose();\n            \n            foreach (var textBlockElement in Items.OfType<TextBlockElement>())\n                textBlockElement.Element.ReleaseDisposableChildren();\n            \n            GC.SuppressFinalize(this);\n        }\n\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            if (Items.Count == 0)\n                return SpacePlan.Empty();\n            \n            if (IsRendered)\n                return SpacePlan.Empty();\n            \n            if (availableSpace.IsNegative())\n                return SpacePlan.Wrap(\"The available space is negative.\");\n\n            // if the text block does not contain any items, or all items are null, return SpacePlan.Empty\n            // but if the text block contains only whitespace, return SpacePlan.FullRender with zero width and font-based height\n            ContainsOnlyWhiteSpace ??= CheckIfContainsOnlyWhiteSpace();\n\n            if (ContainsOnlyWhiteSpace == true)\n            {\n                var requiredHeight = MeasureHeightOfParagraphContainingOnlyWhiteSpace();\n                \n                return requiredHeight < availableSpace.Height + Size.Epsilon \n                    ? SpacePlan.FullRender(0, requiredHeight) \n                    : SpacePlan.Wrap(\"The available vertical space is not sufficient to render even a single line of text.\");\n            }\n\n            if (availableSpace.Width < Size.Epsilon || availableSpace.Height < Size.Epsilon)\n                return SpacePlan.Wrap(\"The available space is not sufficient to render even a single line of text.\");\n            \n            Initialize();\n\n            CalculateParagraphMetrics(availableSpace);\n            \n            if (availableSpace.Width < MaximumWidth - Size.Epsilon)\n                return SpacePlan.Wrap($\"The available space is not sufficient to render even a single character.\");\n\n            if (MaximumWidth == 0)\n                return SpacePlan.FullRender(Size.Zero);\n            \n            var totalHeight = 0f;\n            var totalLines = 0;\n            \n            for (var lineIndex = CurrentLineIndex; lineIndex < LineMetrics.Length; lineIndex++)\n            {\n                var lineMetric = LineMetrics[lineIndex];\n                var newTotalHeight = totalHeight + lineMetric.Height;\n                \n                if (newTotalHeight > availableSpace.Height + Size.Epsilon)\n                    break;\n                \n                totalHeight = newTotalHeight;\n                totalLines++;\n            }\n\n            if (totalLines == 0)\n                return SpacePlan.Wrap(\"The available space is not sufficient to render even a single line of text.\");\n\n            var requiredArea = new Size(\n                Math.Min(MaximumWidth, availableSpace.Width),\n                Math.Min(totalHeight, availableSpace.Height));\n            \n            if (CurrentLineIndex + totalLines < LineMetrics.Length)\n                return SpacePlan.PartialRender(requiredArea);\n\n            return SpacePlan.FullRender(requiredArea);\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            if (Items.Count == 0)\n                return;\n\n            if (IsRendered)\n                return;\n            \n            if (ContainsOnlyWhiteSpace == true)\n                return;\n            \n            CalculateParagraphMetrics(availableSpace);\n\n            if (MaximumWidth == 0)\n                return;\n            \n            var (linesToDraw, takenHeight) = DetermineLinesToDraw();\n            DrawParagraph();\n            \n            CurrentLineIndex += linesToDraw;\n            CurrentTopOffset += takenHeight;\n\n            if (CurrentLineIndex == LineMetrics.Length)\n                IsRendered = true;\n            \n            if (IsRendered && ClearInternalCacheAfterFullRender)\n            {\n                Paragraph?.Dispose();\n                Paragraph = null;\n            }\n            \n            return;\n\n            (int linesToDraw, float takenHeight) DetermineLinesToDraw()\n            {\n                var linesToDraw = 0;\n                var takenHeight = 0f;\n                \n                for (var lineIndex = CurrentLineIndex; lineIndex < LineMetrics.Length; lineIndex++)\n                {\n                    var lineMetric = LineMetrics[lineIndex];\n                \n                    var newTotalHeight = takenHeight + lineMetric.Height;\n\n                    if (newTotalHeight > availableSpace.Height + Size.Epsilon)\n                        break;\n                    \n                    takenHeight = newTotalHeight;\n                    linesToDraw++;\n                }\n\n                return (linesToDraw, takenHeight);\n            }\n            \n            void DrawParagraph()\n            {\n                var takesMultiplePages = linesToDraw != LineMetrics.Length;\n                \n                if (takesMultiplePages)\n                {\n                    Canvas.Save();\n                    Canvas.Translate(new Position(0, -CurrentTopOffset));\n                }\n\n                Canvas.DrawParagraph(Paragraph, CurrentLineIndex, CurrentLineIndex + linesToDraw - 1);\n                \n                if (takesMultiplePages)\n                    Canvas.ClipRectangle(new SkRect(0, CurrentTopOffset, availableSpace.Width, takenHeight + CurrentTopOffset));\n                \n                DrawInjectedElements();\n                DrawHyperlinks();\n                DrawSectionLinks();\n                \n                if (takesMultiplePages)\n                    Canvas.Restore();\n            }\n\n            void DrawInjectedElements()\n            {\n                foreach (var textBlockElement in Items.OfType<TextBlockElement>())\n                {\n                    var placeholder = PlaceholderPositions[textBlockElement.ParagraphBlockIndex];\n                    \n                    textBlockElement.ConfigureElement(PageContext, Canvas);\n\n                    var offset = new Position(placeholder.Left, placeholder.Top);\n                    \n                    if (!IsPositionVisible(offset))\n                        continue;\n                    \n                    Canvas.Translate(offset);\n                    textBlockElement.Element.Draw(new Size(placeholder.Width, placeholder.Height));\n                    Canvas.Translate(offset.Reverse());\n                }\n            }\n            \n            void DrawHyperlinks()\n            {\n                foreach (var hyperlink in Items.OfType<TextBlockHyperlink>())\n                {\n                    var positions = Paragraph.GetTextRangePositions(hyperlink.ParagraphBeginIndex, hyperlink.ParagraphBeginIndex + hyperlink.Text.Length);\n                    \n                    foreach (var position in positions)\n                    {\n                        var offset = new Position(position.Left, position.Top);\n                        \n                        if (!IsPositionVisible(offset))\n                            continue;\n                        \n                        Canvas.Translate(offset);\n                        Canvas.DrawHyperlink(new Size(position.Width, position.Height), hyperlink.Url, hyperlink.Text);\n                        Canvas.Translate(offset.Reverse());\n                    }\n                }\n            }\n            \n            void DrawSectionLinks()\n            {\n                foreach (var sectionLink in Items.OfType<TextBlockSectionLink>())\n                {\n                    var positions = Paragraph.GetTextRangePositions(sectionLink.ParagraphBeginIndex, sectionLink.ParagraphBeginIndex + sectionLink.Text.Length);\n                    var targetName = PageContext.GetDocumentLocationName(sectionLink.SectionName);\n                    \n                    foreach (var position in positions)\n                    {\n                        var offset = new Position(position.Left, position.Top);\n                        \n                        if (!IsPositionVisible(offset))\n                            continue;\n                        \n                        Canvas.Translate(offset);\n                        Canvas.DrawSectionLink(new Size(position.Width, position.Height), targetName, sectionLink.Text);\n                        Canvas.Translate(offset.Reverse());\n                    }\n                }\n            }\n\n            bool IsPositionVisible(Position position)\n            {\n                return CurrentTopOffset <= position.Y || position.Y <= CurrentTopOffset + takenHeight;\n            }\n        }\n        \n        private void Initialize()\n        {\n            if (Paragraph != null && !RebuildParagraphForEveryPage)\n                return;\n\n            if (!AreParagraphItemsTransformedWithSpacingAndIndentation)\n            {\n                Items = ApplyParagraphSpacingToTextBlockItems().ToList();\n                AreParagraphItemsTransformedWithSpacingAndIndentation = true;\n            }\n            \n            RebuildParagraphForEveryPage = Items.Any(x => x is TextBlockPageNumber);\n            BuildParagraph();\n            AreParagraphMetricsValid = false;\n        }\n\n        private void BuildParagraph()\n        {\n            Alignment ??= TextHorizontalAlignment.Start;\n            \n            var paragraphStyle = new ParagraphStyle\n            {\n                Alignment = MapAlignment(Alignment.Value),\n                Direction = MapDirection(ContentDirection),\n                MaxLinesVisible = LineClamp ?? 1_000_000,\n                LineClampEllipsis = LineClampEllipsis\n            };\n\n            if (Paragraph != null)\n            {\n                Paragraph.Dispose();\n                Paragraph = null;\n            }\n            \n            var builder = SkParagraphBuilderPoolManager.Get(paragraphStyle);\n\n            try\n            {\n                Paragraph = CreateParagraph(builder);\n            }\n            finally\n            {\n                SkParagraphBuilderPoolManager.Return(builder);\n            }\n\n            static ParagraphStyleConfiguration.TextAlign MapAlignment(TextHorizontalAlignment alignment)\n            {\n                return alignment switch\n                {\n                    TextHorizontalAlignment.Left => ParagraphStyleConfiguration.TextAlign.Left,\n                    TextHorizontalAlignment.Center => ParagraphStyleConfiguration.TextAlign.Center,\n                    TextHorizontalAlignment.Right => ParagraphStyleConfiguration.TextAlign.Right,\n                    TextHorizontalAlignment.Justify => ParagraphStyleConfiguration.TextAlign.Justify,\n                    TextHorizontalAlignment.Start => ParagraphStyleConfiguration.TextAlign.Start,\n                    TextHorizontalAlignment.End => ParagraphStyleConfiguration.TextAlign.End,\n                    _ => throw new Exception()\n                };\n            }\n\n            static ParagraphStyleConfiguration.TextDirection MapDirection(ContentDirection direction)\n            {\n                return direction switch\n                {\n                    ContentDirection.LeftToRight => ParagraphStyleConfiguration.TextDirection.Ltr,\n                    ContentDirection.RightToLeft => ParagraphStyleConfiguration.TextDirection.Rtl,\n                    _ => throw new Exception()\n                };\n            }\n            \n            static SkPlaceholderStyle.PlaceholderAlignment MapInjectedTextAlignment(TextInjectedElementAlignment alignment)\n            {\n                return alignment switch\n                {\n                    TextInjectedElementAlignment.AboveBaseline => SkPlaceholderStyle.PlaceholderAlignment.AboveBaseline,\n                    TextInjectedElementAlignment.BelowBaseline => SkPlaceholderStyle.PlaceholderAlignment.BelowBaseline,\n                    TextInjectedElementAlignment.Top => SkPlaceholderStyle.PlaceholderAlignment.Top,\n                    TextInjectedElementAlignment.Bottom => SkPlaceholderStyle.PlaceholderAlignment.Bottom,\n                    TextInjectedElementAlignment.Middle => SkPlaceholderStyle.PlaceholderAlignment.Middle,\n                    _ => throw new Exception()\n                };\n            }\n\n            SkParagraph CreateParagraph(SkParagraphBuilder builder)\n            {\n                var currentTextIndex = 0;\n                var currentBlockIndex = 0;\n            \n                if (!Items.Any(x => x is TextBlockSpan))\n                    builder.AddText(\"\\u200B\", DefaultTextStyle.GetSkTextStyle());\n                \n                foreach (var textBlockItem in Items)\n                {\n                    if (textBlockItem is TextBlockSpan textBlockSpan)\n                    {\n                        if (textBlockItem is TextBlockSectionLink textBlockSectionLink)\n                            textBlockSectionLink.ParagraphBeginIndex = currentTextIndex;\n            \n                        else if (textBlockItem is TextBlockHyperlink textBlockHyperlink)\n                            textBlockHyperlink.ParagraphBeginIndex = currentTextIndex;\n            \n                        else if (textBlockItem is TextBlockPageNumber textBlockPageNumber)\n                            textBlockPageNumber.UpdatePageNumberText(PageContext);\n                \n                        var textStyle = textBlockSpan.Style.GetSkTextStyle();\n                        var text = textBlockSpan.Text?.Replace(\"\\r\", \"\") ?? \"\";\n                        builder.AddText(text, textStyle);\n                        currentTextIndex += text.Length;\n                    }\n                    else if (textBlockItem is TextBlockElement textBlockElement)\n                    {\n                        textBlockElement.ConfigureElement(PageContext, Canvas);\n                        textBlockElement.UpdateElementSize();\n                        textBlockElement.ParagraphBlockIndex = currentBlockIndex;\n                    \n                        builder.AddPlaceholder(new SkPlaceholderStyle\n                        {\n                            Width = textBlockElement.ElementSize.Width,\n                            Height = textBlockElement.ElementSize.Height,\n                            Alignment = MapInjectedTextAlignment(textBlockElement.Alignment),\n                            Baseline = SkPlaceholderStyle.PlaceholderBaseline.Alphabetic,\n                            BaselineOffset = 0\n                        });\n\n                        currentTextIndex++;\n                        currentBlockIndex++;\n                    }\n                    else if (textBlockItem is TextBlockParagraphSpacing spacing)\n                    {\n                        builder.AddPlaceholder(new SkPlaceholderStyle\n                        {\n                            Width = spacing.Width,\n                            Height = spacing.Height,\n                            Alignment = SkPlaceholderStyle.PlaceholderAlignment.Middle,\n                            Baseline = SkPlaceholderStyle.PlaceholderBaseline.Alphabetic,\n                            BaselineOffset = 0\n                        });\n\n                        currentTextIndex++;\n                        currentBlockIndex++;\n                    }\n                }\n\n                return builder.CreateParagraph();\n            }\n        }\n\n        private IEnumerable<ITextBlockItem> ApplyParagraphSpacingToTextBlockItems()\n        {\n            if (ParagraphSpacing < Size.Epsilon && ParagraphFirstLineIndentation < Size.Epsilon)\n                return Items;\n            \n            var result = new List<ITextBlockItem>();\n            AddParagraphFirstLineIndentation();\n            \n            foreach (var textBlockItem in Items)\n            {\n                if (textBlockItem is not TextBlockSpan textBlockSpan)\n                {\n                    result.Add(textBlockItem);\n                    continue;\n                }\n                \n                if (textBlockItem is TextBlockPageNumber)\n                {\n                    result.Add(textBlockItem);\n                    continue;\n                }\n                \n                if (textBlockSpan.Text == \"\\n\")\n                {\n                    AddParagraphSpacing();\n                    AddParagraphFirstLineIndentation();\n                    continue;\n                }\n                \n                var textFragments = textBlockSpan.Text.Split('\\n');\n                    \n                foreach (var textFragment in textFragments)\n                {\n                    AddClonedTextBlockSpanWithTextFragment(textBlockSpan, textFragment);\n                        \n                    if (textFragment == textFragments.Last())\n                        continue;\n\n                    AddParagraphSpacing();\n                    AddParagraphFirstLineIndentation();\n                }\n            }\n\n            return result;\n\n            void AddClonedTextBlockSpanWithTextFragment(TextBlockSpan originalSpan, string textFragment)\n            {\n                TextBlockSpan newItem;\n                        \n                if (originalSpan is TextBlockSectionLink textBlockSectionLink)\n                    newItem = new TextBlockSectionLink { SectionName = textBlockSectionLink.SectionName };\n            \n                else if (originalSpan is TextBlockHyperlink textBlockHyperlink)\n                    newItem = new TextBlockHyperlink { Url = textBlockHyperlink.Url };\n            \n                else if (originalSpan is TextBlockPageNumber textBlockPageNumber)\n                    newItem = textBlockPageNumber;\n\n                else\n                    newItem = new TextBlockSpan();\n\n                newItem.Text = textFragment;\n                newItem.Style = originalSpan.Style;\n                \n                result.Add(newItem);\n            }\n            \n            void AddParagraphSpacing()\n            {\n                if (ParagraphSpacing <= Size.Epsilon)\n                    return;\n                \n                // space ensure proper line spacing\n                result.Add(new TextBlockSpan() { Text = \"\\n \", Style = TextStyle.ParagraphSpacing }); \n                result.Add(new TextBlockParagraphSpacing(0, ParagraphSpacing));\n                result.Add(new TextBlockSpan() { Text = \" \\n\", Style = TextStyle.ParagraphSpacing });\n            }\n            \n            void AddParagraphFirstLineIndentation()\n            {\n                if (ParagraphFirstLineIndentation <= Size.Epsilon)\n                    return;\n                \n                result.Add(new TextBlockSpan() { Text = \"\\n\", Style = TextStyle.ParagraphSpacing });\n                result.Add(new TextBlockParagraphSpacing(ParagraphFirstLineIndentation, 0));\n            }\n        }\n\n        /// <summary>\n        /// Adjusts the concurrency level for the SkParagraph.PlanLayout method to optimize performance.\n        ///\n        /// While the Skia implementation is thread-safe, it appears to contain internal locks that hinder scalability.\n        /// Consequently, using multithreading for document rendering can reduce performance. This includes increased memory usage \n        /// and slower generation times—potentially even worse than rendering documents sequentially.\n        ///\n        /// TODO: investigate further on how to improve scalability and remove this mutex\n        /// </summary>\n        private static readonly object PlanLayoutLock = new();\n        \n        private void CalculateParagraphMetrics(Size availableSpace)\n        {\n            if (Math.Abs(WidthForLineMetricsCalculation - availableSpace.Width) > Size.Epsilon)\n                AreParagraphMetricsValid = false;\n            \n            if (AreParagraphMetricsValid) \n                return;\n            \n            WidthForLineMetricsCalculation = availableSpace.Width;\n\n            lock (PlanLayoutLock)\n                Paragraph.PlanLayout(availableSpace.Width);\n\n            CheckUnresolvedGlyphs();\n                \n            LineMetrics = Paragraph.GetLineMetrics();\n            PlaceholderPositions = Paragraph.GetPlaceholderPositions();\n            MaximumWidth = LineMetrics.Any() ? LineMetrics.Max(x => x.Width) : 0;\n            \n            AreParagraphMetricsValid = true;\n        }\n        \n        private void CheckUnresolvedGlyphs()\n        {\n            if (!Settings.CheckIfAllTextGlyphsAreAvailable)\n                return;\n                \n            var unsupportedGlyphs = Paragraph.GetUnresolvedCodepoints();\n                   \n            if (!unsupportedGlyphs.Any())\n                return;\n                \n            var formattedGlyphs = unsupportedGlyphs    \n                .Select(codepoint =>\n                {\n                    var character = char.ConvertFromUtf32(codepoint);\n                    return $\"U-{codepoint:X4} '{character}'\";\n                });\n                \n            var glyphs = string.Join(\"\\n\", formattedGlyphs);\n\n            throw new DocumentDrawingException(\n                $\"Could not find an appropriate font fallback for the following glyphs: \\n\" +\n                $\"${glyphs} \\n\\n\" +\n                $\"Possible solutions: \\n\" +\n                $\"1) Install fonts that contain missing glyphs in your runtime environment. \\n\" +\n                $\"2) Configure the fallback TextStyle using the 'TextStyle.FontFamilyFallback' method. \\n\" +\n                $\"3) Register additional application specific fonts using the 'FontManager.RegisterFont' method. \\n\\n\" +\n                $\"You can disable this check by setting the 'Settings.CheckIfAllTextGlyphsAreAvailable' option to 'false'. \\n\" +\n                $\"However, this may result with text glyphs being incorrectly rendered without any warning.\");\n        }\n        \n        #region Handling Of Text Blocks With Only With Space\n        \n        private static ConcurrentDictionary<int, float> ParagraphContainingOnlyWhiteSpaceHeightCache { get; } = new(); // key: TextStyle.Id\n        \n        private bool CheckIfContainsOnlyWhiteSpace()\n        {\n            foreach (var textBlockItem in Items)\n            {\n                // TextBlockPageNumber needs to be checked first, as it derives from TextBlockSpan,\n                // and before the generation starts, its Text property is empty \n                if (textBlockItem is TextBlockPageNumber)\n                    return false;\n                \n                if (textBlockItem is TextBlockSpan textBlockSpan && !string.IsNullOrWhiteSpace(textBlockSpan.Text))\n                    return false;\n\n                if (textBlockItem is TextBlockElement)\n                    return false;\n            }\n            \n            return true;\n        }\n        \n        private float MeasureHeightOfParagraphContainingOnlyWhiteSpace()\n        {\n            return Items\n                .OfType<TextBlockSpan>()\n                .Select(x => ParagraphContainingOnlyWhiteSpaceHeightCache.GetOrAdd(x.Style.Id, Measure))\n                .DefaultIfEmpty(0)\n                .Max();\n            \n            static float Measure(int textStyleId)\n            {\n                var paragraphStyle = new ParagraphStyle\n                {\n                    Alignment = ParagraphStyleConfiguration.TextAlign.Start,\n                    Direction = ParagraphStyleConfiguration.TextDirection.Ltr,\n                    MaxLinesVisible = 1_000_000,\n                    LineClampEllipsis = string.Empty\n                };\n            \n                var builder = SkParagraphBuilderPoolManager.Get(paragraphStyle);\n\n                try\n                {\n                    var textStyle = TextStyleManager.GetTextStyle(textStyleId).GetSkTextStyle();\n                    builder.AddText(\"\\u00A0\", textStyle); // non-breaking space\n\n                    using var paragraph = builder.CreateParagraph();\n                    paragraph.PlanLayout(1000);\n                    return paragraph.GetLineMetrics().First().Height;\n                }\n                finally\n                {\n                    SkParagraphBuilderPoolManager.Return(builder);\n                }\n            }\n        }\n        \n        #endregion\n        \n        #region IStateful\n        \n        private bool IsRendered { get; set; }\n        private int CurrentLineIndex { get; set; }\n        private float CurrentTopOffset { get; set; }\n    \n        public struct TextBlockState\n        {\n            public bool IsRendered;\n            public int CurrentLineIndex;\n            public float CurrentTopOffset;\n        }\n        \n        public void ResetState(bool hardReset = false)\n        {\n            IsRendered = false;\n            CurrentLineIndex = 0;\n            CurrentTopOffset = 0;\n        }\n\n        public object GetState()\n        {\n            return new TextBlockState\n            {\n                IsRendered = IsRendered,\n                CurrentLineIndex = CurrentLineIndex,\n                CurrentTopOffset = CurrentTopOffset\n            };\n        }\n\n        public void SetState(object state)\n        {\n            var textBlockState = (TextBlockState) state;\n            \n            IsRendered = textBlockState.IsRendered;\n            CurrentLineIndex = textBlockState.CurrentLineIndex;\n            CurrentTopOffset = textBlockState.CurrentTopOffset;\n        }\n    \n        #endregion\n\n        internal override string? GetCompanionHint() => Text.Substring(0, Math.Min(Text.Length, 50));\n        internal override string? GetCompanionSearchableContent() => Text;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Translate.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Translate : ContainerElement\n    {\n        public float TranslateX { get; set; } = 0;\n        public float TranslateY { get; set; } = 0;\n\n        internal override void Draw(Size availableSpace)\n        {\n            var translate = new Position(TranslateX, TranslateY);\n            \n            Canvas.Translate(translate);\n            base.Draw(availableSpace);\n            Canvas.Translate(translate.Reverse());\n        }\n\n        internal override string? GetCompanionHint()\n        {\n            return string.Join(\"   \", GetOptions().Where(x => x.value != 0).Select(x => $\"{x.Label}={x.value.FormatAsCompanionNumber()}\"));\n            \n            IEnumerable<(string Label, float value)> GetOptions()\n            {\n                yield return (\"X\", TranslateX);\n                yield return (\"Y\", TranslateY);\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/Unconstrained.cs",
    "content": "﻿using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class Unconstrained : ContainerElement, IContentDirectionAware\n    {\n        public ContentDirection ContentDirection { get; set; }\n        \n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var childSize = base.Measure(Size.Max);\n            \n            if (childSize.Type == SpacePlanType.PartialRender)\n                return SpacePlan.PartialRender(0, 0);\n            \n            if (childSize.Type == SpacePlanType.FullRender)\n                return SpacePlan.FullRender(0, 0);\n            \n            return childSize;\n        }\n\n        internal override void Draw(Size availableSpace)\n        {\n            var measurement = base.Measure(Size.Max);\n            \n            if (measurement.Type is SpacePlanType.Empty or SpacePlanType.Wrap)\n                return;\n\n            var translate = ContentDirection == ContentDirection.RightToLeft\n                ? new Position(-measurement.Width, 0)\n                : Position.Zero;\n            \n            Canvas.Translate(translate);\n            base.Draw(measurement);\n            Canvas.Translate(translate.Reverse());\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Elements/ZIndex.cs",
    "content": "using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Elements\n{\n    internal sealed class ZIndex : ContainerElement\n    {\n        public int Depth { get; set; }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            var previousZIndex = Canvas.GetZIndex();\n            \n            Canvas.SetZIndex(Depth);\n            base.Draw(availableSpace);\n            Canvas.SetZIndex(previousZIndex);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/AlignmentExtensions.cs",
    "content": "﻿using QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class AlignmentExtensions\n    {\n        #region Horizontal\n        \n        private static IContainer AlignHorizontal(this IContainer element, HorizontalAlignment horizontalAlignment)\n        {\n            var alignment = element as Alignment ?? new Alignment();\n            alignment.Horizontal = horizontalAlignment;\n            return element.Element(alignment);\n        }\n        \n        /// <summary>\n        /// Aligns content horizontally to the left side.\n        /// <a href=\"https://www.questpdf.com/api-reference/alignment.html\">Learn more</a>\n        /// </summary>\n        public static IContainer AlignLeft(this IContainer element)\n        {\n            return element.AlignHorizontal(HorizontalAlignment.Left);\n        }\n        \n        /// <summary>\n        /// Aligns content horizontally to the center, ensuring equal space on both left and right sides.\n        /// <a href=\"https://www.questpdf.com/api-reference/alignment.html\">Learn more</a>\n        /// </summary>\n        public static IContainer AlignCenter(this IContainer element)\n        {\n            return element.AlignHorizontal(HorizontalAlignment.Center);\n        }\n        \n        /// <summary>\n        /// Aligns its content horizontally to the right side.\n        /// <a href=\"https://www.questpdf.com/api-reference/alignment.html\">Learn more</a>\n        /// </summary>\n        public static IContainer AlignRight(this IContainer element)\n        {\n            return element.AlignHorizontal(HorizontalAlignment.Right);\n        }\n        \n        #endregion\n        \n        #region Vertical\n        \n        private static IContainer AlignVertical(this IContainer element, VerticalAlignment verticalAlignment)\n        {\n            var alignment = element as Alignment ?? new Alignment();\n            alignment.Vertical = verticalAlignment;\n            return element.Element(alignment);\n        }\n        \n        /// <summary>\n        /// Aligns content vertically to the upper side.\n        /// <a href=\"https://www.questpdf.com/api-reference/alignment.html\">Learn more</a>\n        /// </summary>\n        public static IContainer AlignTop(this IContainer element)\n        {\n            return element.AlignVertical(VerticalAlignment.Top);\n        }\n        \n        /// <summary>\n        /// Aligns content vertically to the center, ensuring equal space above and below.\n        /// <a href=\"https://www.questpdf.com/api-reference/alignment.html\">Learn more</a>\n        /// </summary>\n        public static IContainer AlignMiddle(this IContainer element)\n        {\n            return element.AlignVertical(VerticalAlignment.Middle);\n        }\n        \n        /// <summary>\n        /// Aligns content vertically to the bottom side.\n        /// <a href=\"https://www.questpdf.com/api-reference/alignment.html\">Learn more</a>\n        /// </summary>\n        public static IContainer AlignBottom(this IContainer element)\n        {\n            return element.AlignVertical(VerticalAlignment.Bottom);\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/ColumnExtensions.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class ColumnDescriptor\n    {\n        internal Column Column { get; } = new();\n\n        internal ColumnDescriptor()\n        {\n            \n        }\n\n        /// <summary>\n        /// Adjusts vertical spacing between items.\n        /// </summary>\n        public void Spacing(float value, Unit unit = Unit.Point)\n        {\n            if (value < 0)\n                throw new ArgumentOutOfRangeException(nameof(value), \"The column spacing cannot be negative.\");\n            \n            Column.Spacing = value.ToPoints(unit);\n        }\n        \n        /// <summary>\n        /// Adds a new item to the column element.\n        /// </summary>\n        /// <returns>The container of the newly created item.</returns>\n        public IContainer Item()\n        {\n            var container = new Container();\n            Column.Items.Add(container);\n            return container;\n        }\n    }\n    \n    public static class ColumnExtensions\n    {\n        [Obsolete(\"This element has been renamed since version 2022.2. Please use the 'Column' method.\")]\n        [ExcludeFromCodeCoverage]\n        public static void Stack(this IContainer element, Action<ColumnDescriptor> handler)\n        {\n            element.Column(handler);\n        }\n        \n        /// <summary>\n        /// Draws a collection of elements vertically (from top to bottom).\n        /// <a href=\"https://www.questpdf.com/api-reference/column.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// Supports paging.\n        /// </remarks>\n        /// <param name=\"handler\">The action to configure the column's content.</param>\n        public static void Column(this IContainer element, Action<ColumnDescriptor> handler)\n        {\n            var descriptor = new ColumnDescriptor();\n            handler(descriptor);\n            element.Element(descriptor.Column);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/ComponentExtentions.cs",
    "content": "using System;\nusing System.Linq.Expressions;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class ComponentExtensions\n    {\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"component\"]/*' />\n        /// <param name=\"component\">Instance of the class implementing the <see cref=\"IComponent\"></see> interface.</param>\n        public static void Component<T>(this IContainer element, T component) where T : IComponent\n        {\n            var componentContainer = element\n                .Container()\n                .DebugPointer(DebugPointerType.Component, component.GetType().Name);\n            \n            component.Compose(componentContainer);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"component\"]/*' />\n        public static void Component<T>(this IContainer element) where T : IComponent, new()\n        {\n            element.Component(new T());\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/ConstrainedExtensions.cs",
    "content": "﻿using System;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class ConstrainedExtensions\n    {\n        #region Width\n        \n        private static IContainer ConstrainedWidth(this IContainer element, float? min = null, float? max = null)\n        {\n            var constrained = element as Constrained ?? new Constrained();\n\n            if (min < 0)\n                throw new ArgumentOutOfRangeException(nameof(min), \"The minimum width cannot be negative.\");\n            \n            if (max < 0)\n                throw new ArgumentOutOfRangeException(nameof(max), \"The maximum width cannot be negative.\");\n            \n            if (min > max)\n                throw new ArgumentOutOfRangeException(nameof(min), \"The minimum width cannot be greater than the maximum width.\");\n            \n            if (min.HasValue)\n                constrained.MinWidth = min;\n            \n            if (max.HasValue)\n                constrained.MaxWidth = max;\n            \n            return element.Element(constrained);\n        }\n        \n        /// <summary>\n        /// Sets the exact width of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/width.html\">Learn more</a>\n        /// </summary>\n        /// <returns>The container with the specified exact width.</returns>\n        public static IContainer Width(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.ConstrainedWidth(min: value, max: value);\n        }\n        \n        /// <summary>\n        /// Sets the minimum width of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/width.html\">Learn more</a>\n        /// </summary>\n        /// <returns>The container with the specified minimum width.</returns>\n        public static IContainer MinWidth(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.ConstrainedWidth(min: value);\n        }\n        \n        /// <summary>\n        /// Sets the maximum width of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/width.html\">Learn more</a>\n        /// </summary>\n        /// <returns>The container with the specified maximum width.</returns>\n        public static IContainer MaxWidth(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.ConstrainedWidth(max: value);\n        }\n        \n        #endregion\n        \n        #region Height\n        \n        private static IContainer ConstrainedHeight(this IContainer element, float? min = null, float? max = null)\n        {\n            var constrained = element as Constrained ?? new Constrained();\n            \n            if (min < 0)\n                throw new ArgumentOutOfRangeException(nameof(min), \"The minimum height cannot be negative.\");\n            \n            if (max < 0)\n                throw new ArgumentOutOfRangeException(nameof(max), \"The maximum height cannot be negative.\");\n            \n            if (min > max)\n                throw new ArgumentOutOfRangeException(nameof(min), \"The minimum height cannot be greater than the maximum height.\");\n            \n            if (min.HasValue) \n                constrained.MinHeight = min;\n            \n            if (max.HasValue)\n                constrained.MaxHeight = max;\n            \n            return element.Element(constrained);\n        }\n        \n        /// <summary>\n        /// Sets the exact height of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/height.html\">Learn more</a>\n        /// </summary>\n        /// <returns>The container with the specified exact height.</returns>\n        public static IContainer Height(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.ConstrainedHeight(min: value, max: value);\n        }\n        \n        /// <summary>\n        /// Sets the minimum height of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/height.html\">Learn more</a>\n        /// </summary>\n        /// <returns>The container with the specified minimum height.</returns>\n        public static IContainer MinHeight(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.ConstrainedHeight(min: value);\n        }\n        \n        /// <summary>\n        /// Sets the maximum height of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/height.html\">Learn more</a>\n        /// </summary>\n        /// <returns>The container with the specified maximum height.</returns>\n        public static IContainer MaxHeight(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.ConstrainedHeight(max: value);\n        }\n        \n        #endregion\n        \n        internal static IContainer EnforceSizeWhenEmpty(this IContainer element)\n        {\n            (element as Constrained).EnforceSizeWhenEmpty = true;\n            return element;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/ContentDirectionExtensions.cs",
    "content": "﻿using QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class ContentDirectionExtensions\n    {\n        internal static IContainer ContentDirection(this IContainer element, ContentDirection direction)\n        {\n            return element.Element(new ContentDirectionSetter\n            {\n                ContentDirection = direction\n            });\n        }\n        \n        /// <summary>\n        /// Sets the left-to-right (LTR) direction for its entire content.\n        /// <a href=\"https://www.questpdf.com/api-reference/content-direction.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"contentDirection.ltr.remarks\"]/*' />\n        public static IContainer ContentFromLeftToRight(this IContainer element)\n        {\n            return element.ContentDirection(Infrastructure.ContentDirection.LeftToRight);\n        }\n        \n        /// <summary>\n        /// Sets the right-to-left (RTL) direction for its entire content.\n        /// <a href=\"https://www.questpdf.com/api-reference/content-direction.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"contentDirection.rtl.remarks\"]/*' />\n        public static IContainer ContentFromRightToLeft(this IContainer element)\n        {\n            return element.ContentDirection(Infrastructure.ContentDirection.RightToLeft);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/DebugExtensions.cs",
    "content": "﻿using QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Drawing.Proxy;\nusing QuestPDF.Elements;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class DebugExtensions\n    {\n        /// <summary>\n        /// Draws a labeled box around its inner content.\n        /// Useful for visual debugging and pinpointing output from specific code blocks.\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/debug-area.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"text\">Optional label displayed within the box.</param>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public static IContainer DebugArea(this IContainer parent, string? text = null, Color? color = null)\n        {\n            var container = new Container();\n\n            parent.Component(new DebugArea\n            {\n                Child = container,\n                Text = text ?? string.Empty,\n                Color = color ?? Colors.Red.Medium\n            });\n\n            return container;\n        }\n\n        /// <summary>\n        /// <para>\n        ///     Inserts a virtual debug element visible in the document hierarchy tree in the QuestPDF Companion App,\n        ///     as well as in the enhanced debugging message provided by the <see cref=\"DocumentLayoutException\" />.\n        /// </para>\n        /// \n        /// <para>It helps with understanding and navigation of the document hierarchy.</para>\n        /// <a href=\"https://www.questpdf.com/api-reference/debug-pointer.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// This debug element does not appear in the final PDF output.\n        /// </remarks>\n        /// <param name=\"elementTraceText\">Text visible somewhere in the \"element trace\" content identifying given document fragment.</param>\n        public static IContainer DebugPointer(this IContainer parent, string label)\n        {\n            return parent.DebugPointer(DebugPointerType.UserDefined, label);\n        }\n        \n        internal static IContainer DebugPointer(this IContainer parent, DebugPointerType type, string label)\n        {\n            return parent.Element(new DebugPointer\n            {\n                Type = type,\n                Label = label\n            });\n        }\n        \n        internal static IContainer LayoutOverflowVisualization(this IContainer parent)\n        {\n            return parent.Element(new LayoutOverflowVisualization());\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/DecorationExtensions.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class DecorationDescriptor\n    {\n        internal Decoration Decoration { get; } = new Decoration();\n\n        internal DecorationDescriptor()\n        {\n            \n        }\n        \n        /// <summary>\n        /// Returns a container for the section positioned before (above) the primary main content.\n        /// </summary>\n        /// <remarks>\n        /// This container is fully visible on each page and does not support paging.\n        /// </remarks>\n        public IContainer Before()\n        {\n            if (Decoration.Before is not (Empty or DebugPointer))\n                throw new DocumentComposeException(\"The 'Decoration.Before' layer has already been defined. Please call this method only once.\");\n\n            var container = new Container();\n            Decoration.Before = container;\n            \n            return container\n                .DebugPointer(DebugPointerType.ElementStructure, \"Before\")\n                .RepeatAsHeader();\n        }\n        \n        /// <summary>\n        /// Provides a handler to the section that appears before (above) the main content.\n        /// </summary>\n        /// <remarks>\n        /// This container is fully visible on each page and does not support paging.\n        /// </remarks>\n        public void Before(Action<IContainer> handler)\n        {\n            handler?.Invoke(Before());\n        }\n        \n        /// <summary>\n        /// Returns a container for the main section.\n        /// </summary>\n        /// <remarks>\n        /// This container does support paging.\n        /// </remarks>\n        public IContainer Content()\n        {\n            if (Decoration.Content is not (Empty or DebugPointer))\n                throw new DocumentComposeException(\"The 'Decoration.Content' layer has already been defined. Please call this method only once.\");\n            \n            var container = new Container();\n            Decoration.Content = container;\n            return container.DebugPointer(DebugPointerType.ElementStructure, \"Content\");\n        }\n        \n        /// <summary>\n        /// Provides a handler to define content of the main section.\n        /// </summary>\n        /// <remarks>\n        /// This container does support paging.\n        /// </remarks>\n        public void Content(Action<IContainer> handler)\n        {\n            handler?.Invoke(Content());\n        }\n        \n        /// <summary>\n        /// Returns a container for the section positioned after (below) the main content.\n        /// </summary>\n        /// <remarks>\n        /// This container is fully visible on each page and does not support paging.\n        /// </remarks>\n        public IContainer After()\n        {\n            if (Decoration.After is not (Empty or DebugPointer))\n                throw new DocumentComposeException(\"The 'Decoration.After' layer has already been defined. Please call this method only once.\");\n            \n            var container = new Container();\n            Decoration.After = container;\n\n            return container\n                .DebugPointer(DebugPointerType.ElementStructure, \"After\")\n                .RepeatAsFooter();\n        }\n        \n        /// <summary>\n        /// Provides a handler to the section that appears after (below) the main content.\n        /// </summary>\n        /// <remarks>\n        /// This container is fully visible on each page and does not support paging.\n        /// </remarks>\n        public void After(Action<IContainer> handler)\n        {\n            handler?.Invoke(After());\n        }\n\n        #region Obsolete\n\n        [Obsolete(\"This element has been renamed since version 2022.2. Please use the 'Before' method.\")]\n        [ExcludeFromCodeCoverage]\n        public IContainer Header()\n        {\n            var container = new Container();\n            Decoration.Before = container;\n            return container;\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.2. Please use the 'Before' method.\")]\n        [ExcludeFromCodeCoverage]\n        public void Header(Action<IContainer> handler)\n        {\n            handler?.Invoke(Header());\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.2. Please use the 'After' method.\")]\n        [ExcludeFromCodeCoverage]\n        public IContainer Footer()\n        {\n            var container = new Container();\n            Decoration.After = container;\n            return container;\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.2. Please use the 'After' method.\")]\n        [ExcludeFromCodeCoverage]\n        public void Footer(Action<IContainer> handler)\n        {\n            handler?.Invoke(Footer());\n        }\n\n        #endregion\n    }\n    \n    public static class DecorationExtensions\n    {\n        /// <summary>\n        /// <para>Divides the container's space into three distinct sections: before, content, and after.</para>\n        /// <para>The \"before\" section is rendered above the main content, while the \"after\" section is rendered below it.</para>\n        /// <para>If the main \"content\" spans across multiple pages, both the \"before\" and \"after\" sections are consistently rendered on every page.</para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/decoration.html\">Learn more</a>\n        /// </summary>\n        /// <example>\n        /// A typical use-case for this method is to render a table that spans multiple pages, with a consistent caption or header on each page.\n        /// </example>\n        /// <param name=\"handler\">The action to configure the content.</param>\n        public static void Decoration(this IContainer element, Action<DecorationDescriptor> handler)\n        {\n            var descriptor = new DecorationDescriptor();\n            handler(descriptor);\n            \n            element.Element(descriptor.Decoration);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/DocumentOperation.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing QuestPDF.Qpdf;\n\nnamespace QuestPDF.Fluent;\n\n/// <summary>\n/// Provides functionality for performing various operations on PDF documents, including loading, merging, overlaying, underlaying, selecting specific pages, adding attachments, and applying encryption settings.\n/// </summary>\npublic sealed class DocumentOperation\n{\n    /// <summary>\n    /// Represents configuration options for applying an overlay or underlay to a PDF document using qpdf.\n    /// </summary>\n    public sealed class LayerConfiguration\n    {\n        /// <summary>\n        /// The file path of the overlay or underlay PDF file to be used.\n        /// </summary>\n        public string FilePath { get; set; }\n\n        /// <summary>\n        /// Specifies the range of pages in the output document where the overlay or underlay will be applied.\n        /// If not specified, the overlay or underlay is applied to all output pages.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.pageSelector\"]/*' />\n        public string? TargetPages { get; set; }\n\n        /// <summary>\n        /// Specifies the range of pages in the overlay or underlay file to be used initially.\n        /// If not specified, all pages in the overlay or underlay file will be used in sequence.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.pageSelector\"]/*' />\n        public string? SourcePages { get; set; }\n\n        /// <summary>\n        /// Specifies an optional range of pages in the overlay or underlay file that will repeat after the initial source pages are exhausted.\n        /// Useful for repeating certain pages of the overlay or underlay file across multiple pages of the output.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.pageSelector\"]/*' />\n        public string? RepeatSourcePages { get; set; }\n    }\n\n    public enum DocumentAttachmentRelationship\n    {\n        /// <summary>\n        /// Indicates data files relevant to the document (e.g., supporting datasets or data tables).\n        /// </summary>\n        Data,\n        \n        /// <summary>\n        /// Represents a source file directly used to create the document.\n        /// </summary>\n        Source,\n        \n        /// <summary>\n        /// An alternative representation of the document content (e.g., XML, HTML).\n        /// </summary>\n        Alternative,\n        \n        /// <summary>\n        /// A file supplementing the content, like additional resources.\n        /// </summary>\n        Supplement,\n        \n        /// <summary>\n        /// No specific relationship is defined.\n        /// </summary>\n        Unspecified\n    }\n    \n    public sealed class DocumentAttachment\n    {\n        /// <summary>\n        /// Sets the key for the attachment, specific to the PDF format.\n        /// Defaults to the file name without its path.\n        /// </summary>\n        public string? Key { get; set; }\n    \n        /// <summary>\n        /// The file path of the attachment. Ensure that the specified file exists.\n        /// </summary>\n        public string FilePath { get; set; }\n    \n        /// <summary>\n        /// Specifies the display name for the attachment.\n        /// This name is typically shown to the user and used by most graphical PDF viewers when saving the file.\n        /// Defaults to the file name without its path.\n        /// </summary>\n        public string? AttachmentName { get; set; }\n    \n        /// <summary>\n        /// Specifies the creation date of the attachment. \n        /// Defaults to the file's creation time.\n        /// </summary>\n        public DateTime? CreationDate { get; set; }\n    \n        /// <summary>\n        /// Specifies the modification date of the attachment.\n        /// Defaults to the file's last modified time.\n        /// </summary>\n        public DateTime? ModificationDate { get; set; }\n    \n        /// <summary>\n        /// Specifies the MIME type of the attachment, such as \"text/plain\", \"application/pdf\", \"image/png\", etc.\n        /// </summary>\n        public string? MimeType { get; set; }\n    \n        /// <summary>\n        /// Sets a description for the attachment, which may be displayed by some PDF viewers.\n        /// </summary>\n        public string? Description { get; set; }\n    \n        /// <summary>\n        /// Indicates whether to replace an existing attachment with the same key.\n        /// If false, an exception is thrown if an attachment with the same key already exists.\n        /// </summary>\n        public bool Replace { get; set; } = true;\n        \n        /// <summary>\n        /// Specifies the relationship of the embedded file to the document for PDF/A-3b compliance.\n        /// </summary>\n        public DocumentAttachmentRelationship? Relationship { get; set; } = null;\n    }\n\n    public class EncryptionBase\n    {\n        /// <summary>\n        /// The user password for the PDF, allowing restricted access based on encryption settings. \n        /// May be left null to enable opening the PDF without a password, though this may restrict certain operations.\n        /// </summary>\n        public string? UserPassword { get; set; }\n        \n        /// <summary>\n        /// The owner password for the PDF, granting full access to all document features.\n        /// An empty owner password is considered insecure, as is using the same value for both user and owner passwords.\n        /// </summary>\n        public string OwnerPassword { get; set; }\n    }\n    \n    public sealed class Encryption40Bit : EncryptionBase\n    {\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.annotation\"]/*' />\n        public bool AllowAnnotation { get; set; } = true;\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.contentExtraction\"]/*' />\n        public bool AllowContentExtraction { get; set; } = true;\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.modification\"]/*' />\n        public bool AllowModification { get; set; } = true;\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.printing\"]/*' />\n        public bool AllowPrinting { get; set; } = true;\n    }\n\n    public sealed class Encryption128Bit : EncryptionBase\n    {\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.annotation\"]/*' />\n        public bool AllowAnnotation { get; set; } = true;\n    \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.assembly\"]/*' />\n        public bool AllowAssembly { get; set; } = true;\n    \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.contentExtraction\"]/*' />\n        public bool AllowContentExtraction { get; set; } = true;\n    \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.fillingForms\"]/*' />\n        public bool AllowFillingForms { get; set; } = true;\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.printing\"]/*' />\n        public bool AllowPrinting { get; set; } = true;\n    \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.encryptMetadata\"]/*' />\n        public bool EncryptMetadata { get; set; } = true;\n    }\n\n    public sealed class Encryption256Bit : EncryptionBase\n    {\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.annotation\"]/*' />\n        public bool AllowAnnotation { get; set; } = true;\n    \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.assembly\"]/*' />\n        public bool AllowAssembly { get; set; } = true;\n    \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.contentExtraction\"]/*' />\n        public bool AllowContentExtraction { get; set; } = true;\n    \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.fillingForms\"]/*' />\n        public bool AllowFillingForms { get; set; } = true;\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.allow.printing\"]/*' />\n        public bool AllowPrinting { get; set; } = true;\n    \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.encryption.encryptMetadata\"]/*' />\n        public bool EncryptMetadata { get; set; } = true;\n    }\n    \n    internal JobConfiguration Configuration { get; private set; }\n    \n    private DocumentOperation()\n    {\n            \n    }\n\n    /// <summary>\n    /// Loads the specified PDF file for processing, enabling operations such as merging, overlaying or underlaying content, selecting pages, adding attachments, and encrypting.\n    /// </summary>\n    /// <param name=\"filePath\">The full path to the PDF file to be loaded.</param>\n    /// <param name=\"password\">The password for the PDF file, if it is password-protected. Optional.</param>\n    public static DocumentOperation LoadFile(string filePath, string? password = null)\n    {\n        if (!File.Exists(filePath))\n            throw new Exception($\"The file could not be found: {filePath}\");\n        \n        return new DocumentOperation\n        {\n            Configuration = new JobConfiguration\n            {\n                InputFile = filePath,\n                Password = password\n            }\n        };\n    }\n    \n    /// <summary>\n    /// Selects specific pages from the current document based on the provided page selector, marking them for further operations.\n    /// </summary>\n    /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.pageSelector\"]/*' />\n    public DocumentOperation TakePages(string pageSelector)\n    {\n        Configuration.Pages ??= new List<JobConfiguration.PageConfiguration>();\n        \n        Configuration.Pages.Add(new JobConfiguration.PageConfiguration\n        {\n            File = \".\",\n            Range = pageSelector\n        });\n        \n        return this;\n    }\n    \n    /// <summary>\n    /// Merges pages from the specified PDF file into the current document, according to the provided page selection.\n    /// </summary>\n    /// <param name=\"filePath\">The path to the PDF file to be merged.</param>\n    /// <param name=\"pageSelector\">An optional <see cref=\"DocumentPageSelector\"/> to specify the range of pages to merge. If not provided, all pages will be merged.</param>\n    /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"documentOperation.pageSelector\"]/*' />\n    public DocumentOperation MergeFile(string filePath, string? pageSelector = null)\n    {\n        if (!File.Exists(filePath))\n            throw new Exception($\"The file could not be found: {filePath}\");\n        \n        if (Configuration.Pages == null)\n            TakePages(\"1-z\");\n        \n        Configuration.Pages.Add(new JobConfiguration.PageConfiguration\n        {\n            File = filePath,\n            Range = pageSelector ?? \"1-z\"\n        });\n        \n        return this;\n    }\n\n    /// <summary>\n    /// Applies an underlay to the document using the specified configuration.\n    /// The underlay pages are drawn beneath the target pages in the output file, potentially obscured by the original content.\n    /// </summary>    \n    public DocumentOperation UnderlayFile(LayerConfiguration configuration)\n    {\n        if (!File.Exists(configuration.FilePath))\n            throw new Exception($\"The file could not be found: {configuration.FilePath}\");\n        \n        Configuration.Underlay ??= new List<JobConfiguration.LayerConfiguration>();\n        \n        Configuration.Underlay.Add(new JobConfiguration.LayerConfiguration\n        {\n            File = configuration.FilePath,\n            To = configuration.TargetPages,\n            From = configuration.SourcePages,\n            Repeat = configuration.RepeatSourcePages\n        });\n        \n        return this;\n    }\n    \n    /// <summary>\n    /// Applies an overlay to the document using the specified configuration.\n    /// The overlay pages are drawn on top of the target pages in the output file, potentially obscuring the original content.\n    /// </summary>\n    public DocumentOperation OverlayFile(LayerConfiguration configuration)\n    {\n        if (!File.Exists(configuration.FilePath))\n            throw new Exception($\"The file could not be found: {configuration.FilePath}\");\n        \n        Configuration.Overlay ??= new List<JobConfiguration.LayerConfiguration>();\n        \n        Configuration.Overlay.Add(new JobConfiguration.LayerConfiguration\n        {\n            File = configuration.FilePath,\n            To = configuration.TargetPages,\n            From = configuration.SourcePages,\n            Repeat = configuration.RepeatSourcePages\n        });\n        \n        return this;\n    }\n\n    /// <summary>\n    /// Extends the current document's XMP metadata by adding content within the <c>rdf:Description</c> tag.\n    /// This allows for adding additional descriptive metadata to the PDF, which is useful for compliance standards\n    /// like PDF/A or for industry-specific metadata (e.g., ZUGFeRD).\n    /// </summary>\n    /// <param name=\"metadata\">\n    /// A string containing the metadata to add. This metadata must be valid XML content and conform to the\n    /// RDF structure required by the PDF XMP metadata specification.\n    /// </param>\n    public DocumentOperation ExtendMetadata(string metadata)\n    {\n        Configuration.ExtendMetadata = metadata;\n        return this;\n    }\n    \n    /// <summary>\n    /// Adds an attachment to the document, with specified metadata and configuration options.\n    /// </summary>\n    public DocumentOperation AddAttachment(DocumentAttachment attachment)\n    {\n        Configuration.AddAttachment ??= new List<JobConfiguration.AddDocumentAttachment>();\n\n        if (!File.Exists(attachment.FilePath))\n            throw new Exception($\"The file could not be found: {attachment.FilePath}\");\n        \n        var file = new FileInfo(attachment.FilePath);\n        \n        Configuration.AddAttachment.Add(new JobConfiguration.AddDocumentAttachment\n        {\n            Key = attachment.Key ?? Path.GetFileName(attachment.FilePath),\n            File = attachment.FilePath,\n            FileName = attachment.AttachmentName ?? file.Name,\n            CreationDate = GetFormattedDate(attachment.CreationDate, File.GetCreationTimeUtc(attachment.FilePath)),\n            ModificationDate = GetFormattedDate(attachment.ModificationDate, File.GetLastWriteTime(attachment.FilePath)),\n            MimeType = attachment.MimeType ?? GetDefaultMimeType(),\n            Description = attachment.Description,\n            Replace = attachment.Replace ? string.Empty : null,\n            Relationship = GetRelationship(attachment.Relationship)\n        });\n        \n        return this;\n\n        string GetDefaultMimeType()\n        {\n            var fileExtension = Path.GetExtension(attachment.FilePath);\n            fileExtension = fileExtension.TrimStart('.').ToLowerInvariant();\n            return MimeHelper.FileExtensionToMimeConversionTable.TryGetValue(fileExtension, out var value) ? value : \"text/plain\";\n        }\n        \n        string GetFormattedDate(DateTime? value, DateTime defaultValue)\n        {\n            return $\"D:{(value ?? defaultValue).ToUniversalTime():yyyyMMddHHmmsss}Z\";\n        }\n        \n        string? GetRelationship(DocumentAttachmentRelationship? relationship)\n        {\n            return relationship switch\n            {\n                DocumentAttachmentRelationship.Data => \"/Data\",\n                DocumentAttachmentRelationship.Source => \"/Source\",\n                DocumentAttachmentRelationship.Alternative => \"/Alternative\",\n                DocumentAttachmentRelationship.Supplement => \"/Alternative\",\n                DocumentAttachmentRelationship.Unspecified => \"/Unspecified\",\n                null => null,\n                _ => throw new ArgumentOutOfRangeException(nameof(relationship), relationship, null)\n            };\n        }\n    }\n\n    /// <summary>\n    /// Removes any existing encryption from the current PDF document, effectively making it accessible without a password or encryption restrictions.\n    /// </summary>\n    public DocumentOperation Decrypt()\n    {\n        Configuration.Decrypt = string.Empty;\n        return this;\n    }\n    \n    /// <summary>\n    /// Remove security restrictions associated with digitally signed PDF files.\n    /// This may be combined with Decrypt() operation to allow free editing of previously signed/encrypted files.\n    /// This option invalidates and disables any digital signatures but leaves their visual appearances intact.\n    /// </summary>\n    public DocumentOperation RemoveRestrictions()\n    {\n        Configuration.Decrypt = string.Empty;\n        Configuration.RemoveRestrictions = string.Empty;\n        return this;\n    }\n    \n    /// <summary>\n    /// Encrypts the document using 40-bit encryption, applying specified owner and user passwords along with defined permissions.\n    /// </summary>\n    public DocumentOperation Encrypt(Encryption40Bit encryption)\n    {\n        if (Configuration.Encrypt != null)\n            throw new InvalidOperationException(\"Encryption process can be set only once\");\n        \n        Configuration.Encrypt = new JobConfiguration.EncryptionSettings\n        {\n            UserPassword = encryption.UserPassword,\n            OwnerPassword = encryption.OwnerPassword,\n            Options40Bit = new JobConfiguration.Encryption40Bit\n            {\n                Annotate = FormatBooleanFlag(encryption.AllowAnnotation),\n                Extract = FormatBooleanFlag(encryption.AllowContentExtraction),\n                Modify = encryption.AllowModification ? \"all\" : \"none\",\n                Print = encryption.AllowPrinting ? \"full\" : \"none\",\n            }\n        };\n        \n        return this;\n    }\n    \n    /// <summary>\n    /// Encrypts the document using 128-bit encryption, applying specified owner and user passwords along with defined permissions.\n    /// </summary>\n    public DocumentOperation Encrypt(Encryption128Bit encryption)\n    {\n        if (Configuration.Encrypt != null)\n            throw new InvalidOperationException(\"Encryption process can be set only once\");\n        \n        Configuration.Encrypt = new JobConfiguration.EncryptionSettings\n        {\n            UserPassword = encryption.UserPassword,\n            OwnerPassword = encryption.OwnerPassword,\n            Options128Bit = new JobConfiguration.Encryption128Bit\n            {\n                Annotate = FormatBooleanFlag(encryption.AllowAnnotation),\n                Assemble = FormatBooleanFlag(encryption.AllowAssembly),\n                Extract = FormatBooleanFlag(encryption.AllowContentExtraction),\n                Form = FormatBooleanFlag(encryption.AllowFillingForms),\n                Print = encryption.AllowPrinting ? \"full\" : \"none\",\n                CleartextMetadata = encryption.EncryptMetadata ? null : string.Empty\n            }\n        };\n        \n        return this;\n    }\n    \n    /// <summary>\n    /// Encrypts the document using 256-bit encryption, applying specified owner and user passwords along with defined permissions.\n    /// </summary>\n    public DocumentOperation Encrypt(Encryption256Bit encryption)\n    {\n        if (Configuration.Encrypt != null)\n            throw new InvalidOperationException(\"Encryption process can be set only once\");\n        \n        Configuration.Encrypt = new JobConfiguration.EncryptionSettings\n        {\n            UserPassword = encryption.UserPassword,\n            OwnerPassword = encryption.OwnerPassword,\n            Options256Bit = new JobConfiguration.Encryption256Bit\n            {\n                Annotate = FormatBooleanFlag(encryption.AllowAnnotation),\n                Assemble = FormatBooleanFlag(encryption.AllowAssembly),\n                Extract = FormatBooleanFlag(encryption.AllowContentExtraction),\n                Form = FormatBooleanFlag(encryption.AllowFillingForms),\n                Print = encryption.AllowPrinting ? \"full\" : \"none\",\n                CleartextMetadata = encryption.EncryptMetadata ? null : string.Empty\n            }\n        };\n        \n        return this;\n    }\n\n    private string FormatBooleanFlag(bool value)\n    {\n        return value ? \"y\" : \"n\";\n    }\n    \n    /// <summary>\n    /// Creates linearized (web-optimized) output files.\n    /// Linearized files are structured to allow compliant PDF readers to begin displaying content before the entire file is downloaded.\n    /// Normally, a PDF reader requires the entire file to be present to render content, as essential cross-reference data typically appears at the file’s end.\n    /// </summary>\n    public DocumentOperation Linearize()\n    {\n        Configuration.Linearize = string.Empty;\n        return this;\n    }\n    \n    /// <summary>\n    /// Executes the configured operations on the document and saves the resulting file to the specified path.\n    /// </summary>\n    /// <param name=\"filePath\">The path where the output file will be saved.</param>\n    public void Save(string filePath)\n    {\n        if (File.Exists(filePath))\n            File.Delete(filePath);\n        \n        Configuration.OutputFile = filePath;\n        var json = SimpleJsonSerializer.Serialize(Configuration);\n        QpdfAPI.ExecuteJob(json);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/DynamicComponentExtensions.cs",
    "content": "using QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class DynamicComponentExtensions\n    {\n        /// <summary>\n        /// Represents a dynamically generated section of the document.\n        /// Components are page-aware, understand their positioning, can dynamically construct other content elements, and assess their dimensions, enabling complex layout creations.\n        /// <a href=\"https://www.questpdf.com/concepts/code-patterns/dynamic-components.html\">Learn more</a>\n        /// </summary>\n        /// <example>\n        /// <para>\n        /// Consider an invoice that presents all purchased items in a table format.\n        /// Instead of just showing the final total price under the table, the requirement is to display the cumulative prices on each separate page.\n        /// </para>\n        /// <para>Using the dynamic component, you can manually assemble the table, count how many items are visible on each page, calculate the price sum for items visible on each page, and then render the result under each sub-table.</para>\n        /// </example>\n        public static void Dynamic(this IContainer element, IDynamicComponent dynamicElement)\n        {\n            var componentProxy = DynamicComponentProxy.CreateFrom(dynamicElement);\n            element.Element(new DynamicHost(componentProxy));\n        }\n\n        /// <summary>\n        /// Represents a section of the document dynamically created based on its inner state.\n        /// Components are page-aware, understand their positioning, can dynamically construct other content elements, and assess their dimensions, enabling complex layout creations.\n        /// <a href=\"https://www.questpdf.com/concepts/code-patterns/dynamic-components.html\">Learn more</a>\n        /// </summary>\n        /// <example>\n        /// <para>\n        /// Consider an invoice that presents all purchased items in a table format.\n        /// Instead of just showing the final total price under the table, the requirement is to display the cumulative prices on each separate page.\n        /// </para>\n        /// <para>Using the dynamic component, you can manually assemble the table, count how many items are visible on each page, calculate the price sum for items visible on each page, and then render the result under each sub-table.</para>\n        /// </example>\n        public static void Dynamic<TState>(this IContainer element, IDynamicComponent<TState> dynamicElement) where TState : struct\n        {\n            var componentProxy = DynamicComponentProxy.CreateFrom(dynamicElement);\n            element.DebugPointer(DebugPointerType.Dynamic, dynamicElement.GetType().Name).Element(new DynamicHost(componentProxy));\n        }\n        \n        /// <summary>\n        /// Allows to inject the unattached content created by the <see cref=\"DynamicContext.CreateElement\"/> method within the <see cref=\"DynamicComponentExtensions.Dynamic\">Dynamic component</see>.\n        /// </summary>\n        public static void Element(this IContainer element, IDynamicElement child)\n        {\n            ElementExtensions.Element(element, child);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/ElementExtensions.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Net.Mime;\nusing System.Runtime.CompilerServices;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Fluent\n{\n    /// <summary>\n    /// Provides extension methods for manipulating and enhancing elements within a container.\n    /// </summary>\n    public static class ElementExtensions\n    {\n        static ElementExtensions()\n        {\n            SkNativeDependencyCompatibilityChecker.Test();\n        }\n        \n        internal static T Element<T>(this IContainer element, T child) where T : IElement\n        {\n            if (element?.Child != null && element.Child is Empty == false)\n            {\n                var message = \"You should not assign multiple child elements to a single-child container. \" +\n                              \"This may happen when a container variable is used outside of its scope/closure OR the container is used in multiple fluent API chains OR the container is used incorrectly in a loop. \" +\n                              \"This exception is thrown to help you detect that some part of the code is overriding fragments of the document layout with a new content - essentially destroying existing content.\";\n\n                throw new DocumentComposeException(message);\n            }\n\n            if (element != child as Element)\n                element.Child = child as Element;\n            \n            if (child is Element childElement)\n                childElement.CodeLocation = SourceCodePath.CreateFromCurrentStackTrace();\n\n            return child;\n        }\n        \n        /// <summary>\n        /// Passes the Fluent API chain to the provided <paramref name=\"handler\"/> method.\n        /// <a href=\"https://www.questpdf.com/concepts/code-patterns/content-styling.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// <para>This method is particularly useful for code refactoring, improving its structure and readability.</para>\n        /// <para>Extracting implementation of certain layout structures into separate methods, allows you to accurately describe their purpose and reuse them code in various parts of the application.</para>\n        /// </remarks>\n        /// <param name=\"handler\">A delegate that takes the current container and populates it with content.</param>\n        public static void Element(\n            this IContainer parent, \n            Action<IContainer> handler,\n            [CallerArgumentExpression(\"handler\")] string handlerName = null,\n            [CallerMemberName] string parentName = \"\",\n            [CallerFilePath] string sourceFilePath = \"\",\n            [CallerLineNumber] int sourceLineNumber = 0)\n        {\n            var handlerContainer = parent\n                .Container()\n                .Element(new SourceCodePointer\n                {\n                    MethodName = handlerName,\n                    CalledFrom = parentName,\n                    FilePath = sourceFilePath,\n                    LineNumber = sourceLineNumber\n                });\n            \n            handler(handlerContainer);\n        }\n        \n        /// <summary>\n        /// Passes the Fluent API chain to the provided <paramref name=\"handler\"/> method.\n        /// <a href=\"https://www.questpdf.com/concepts/code-patterns/content-styling.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// <para>This method is particularly useful for code refactoring, improving its structure and readability.</para>\n        /// <para>Extracting implementation of certain layout structures into separate methods, allows you to accurately describe their purpose and reuse them code in various parts of the application.</para>\n        /// </remarks>\n        /// <param name=\"handler\">A method that accepts the current container, optionally populates it with content, and returns a subsequent container to continue the Fluent API chain.</param>\n        /// <returns>The container returned by the <paramref name=\"handler\"/> method.</returns>\n        public static IContainer Element(\n            this IContainer parent, \n            Func<IContainer, IContainer> handler,\n            [CallerArgumentExpression(\"handler\")] string handlerName = null,\n            [CallerMemberName] string parentName = \"\",\n            [CallerFilePath] string sourceFilePath = \"\",\n            [CallerLineNumber] int sourceLineNumber = 0)\n        {\n            var handlerContainer = parent\n                .Element(new SourceCodePointer\n                {\n                    MethodName = handlerName,\n                    CalledFrom = parentName,\n                    FilePath = sourceFilePath,\n                    LineNumber = sourceLineNumber\n                });\n            \n            return handler(handlerContainer);\n        }\n        \n        public static void Element(this IContainer parent, IContainer child)\n        {\n            parent.Child = child as IElement;\n        }\n        \n        internal static IContainer NonTrackingElement(this IContainer parent, Func<IContainer, IContainer> handler)\n        {\n            return handler(parent.Container());\n        }\n        \n        /// <summary>\n        /// Constrains its content to maintain a given width-to-height ratio.\n        /// <a href=\"https://www.questpdf.com/api-reference/aspect-ratio.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// This container enforces strict space constraints. The <see cref=\"DocumentLayoutException\" /> may be thrown if these constraints can't be satisfied.\n        /// </remarks>\n        /// <param name=\"ratio\">Represents the aspect ratio as a width-to-height division. For instance, a container with a width of 250 points and a height of 200 points has an aspect ratio of 1.25.</param>\n        /// <param name=\"option\">Determines the approach the component should adopt when maintaining the specified aspect ratio.</param>\n        public static IContainer AspectRatio(this IContainer element, float ratio, AspectRatioOption option = AspectRatioOption.FitWidth)\n        {\n            if (ratio <= 0)\n                throw new ArgumentOutOfRangeException(nameof(ratio), \"The aspect ratio must be greater than zero.\");\n            \n            return element.Element(new AspectRatio\n            {\n                Ratio = ratio,\n                Option = option\n            });\n        }\n\n        /// <summary>\n        /// Draws a basic placeholder useful for prototyping.\n        /// <a href=\"https://www.questpdf.com/api-reference/placeholder.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// You can control the size of the Placeholder by chaining other elements before its invocation, e.g.:\n        /// <code>\n        /// .Width(200)\n        /// .Height(100)\n        /// .Placeholder(\"Sample text\");\n        /// </code>\n        /// </remarks>\n        /// <param name=\"text\">When provided, the placeholder displays this text. If omitted, a simple image icon is shown instead.</param>\n        public static void Placeholder(this IContainer element, string? text = null)\n        {\n            element.Component(new Placeholder\n            {\n                Text = text ?? string.Empty\n            });\n        }\n\n        /// <summary>\n        /// <para>The ShowOnce element modifies how content is displayed across multiple pages.</para>\n        /// <para>\n        /// By default, all elements are fully rendered only once and never repeated.\n        /// However, in some contexts such as page headers and footers, as well as decoration before and after slots, the content is repeated on every page.\n        /// To prevent this, you can use the ShowOnce element.\n        /// </para>\n        /// <a href=\"https://www.questpdf.com/api-reference/show-once.html\">Learn more</a>\n        /// </summary>\n        /// <example>\n        /// <para>Combine this element with SkipOnce to achieve more complex behaviors, e.g.:</para>\n        /// <para><c>.SkipOnce().ShowOnce()</c> ensures the child element is displayed only on the second page.</para>\n        /// <para><c>.SkipOnce().SkipOnce()</c> starts displaying the child element from the third page onwards.</para>\n        /// <para><c>.ShowOnce().SkipOnce()</c> draws nothing, as the order of invocation is important.</para>\n        /// </example>\n        public static IContainer ShowOnce(this IContainer element)\n        {\n            return element.Element(new ShowOnce());\n        }\n\n        /// <summary>\n        /// If the container spans multiple pages, its content is omitted on the first page and then displayed on the second and subsequent pages.\n        /// <a href=\"https://www.questpdf.com/api-reference/skip-once.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// A common use-case for this element is when displaying a consistent header across pages but needing to conditionally show/hide specific fragments on the first page.\n        /// </remarks>\n        /// <example>\n        /// <para>Combine this element with ShowOnce to achieve more complex behaviors, e.g.:</para>\n        /// <para><c>.SkipOnce().ShowOnce()</c> ensures the child element is displayed only on the second page.</para>\n        /// <para><c>.SkipOnce().SkipOnce()</c> starts displaying the child element from the third page onwards.</para>\n        /// <para><c>.ShowOnce().SkipOnce()</c> draws nothing, as the order of invocation is important.</para>\n        /// </example>\n        public static IContainer SkipOnce(this IContainer element)\n        {\n            return element.Element(new SkipOnce());\n        }\n\n        /// <summary>\n        /// Ensures its content is displayed entirely on a single page by disabling the default paging capability.\n        /// <a href=\"https://www.questpdf.com/api-reference/show-entire.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// <para>While many library elements inherently support paging, allowing content to span multiple pages, this element restricts that behavior.</para>\n        /// <para>Employ this when a single-page display is crucial.</para>\n        /// <para>Be cautious: its strict space constraints can trigger the <see cref=\"DocumentLayoutException\" /> if content exceeds the page's capacity.</para>\n        /// </remarks>\n        public static IContainer ShowEntire(this IContainer element)\n        {\n            return element.Element(new ShowEntire());\n        }\n\n        /// <summary>\n        /// <para>\n        /// Ensures that the container's content occupies at least a specified minimum height on its first page of occurrence.\n        /// If there is enough space, the content is rendered as usual. However, if a page break is required,\n        /// this method ensures that a minimum amount of space is available before rendering the content.\n        /// If the required space is not available, the content is moved to the next page.\n        /// </para>\n        /// <para>\n        /// This rule applies only to the first page where the content appears. If the content spans multiple pages,\n        /// all subsequent pages are rendered without this restriction. \n        /// </para>\n        /// <para>\n        /// This method is particularly useful for structured elements like tables, where rendering only a small fragment \n        /// at the bottom of a page could negatively impact readability. By ensuring a minimum height, \n        /// you can prevent undesired content fragmentation.\n        /// </para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/ensure-space.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"minHeight\">The minimum height, in points, that the element should occupy before a page break.</param>\n        public static IContainer EnsureSpace(this IContainer element, float minHeight = Elements.EnsureSpace.DefaultMinHeight)\n        {\n            if (minHeight < 0)\n                throw new ArgumentOutOfRangeException(nameof(minHeight), \"The EnsureSpace minimum height cannot be negative.\");\n            \n            return element.Element(new EnsureSpace\n            {\n                MinHeight = minHeight\n            });\n        }\n        \n        /// <summary>\n        /// <para>\n        /// Attempts to keep the container's content together on its first page of occurrence.\n        /// If the content does not fit entirely on that page, it is moved to the next page. \n        /// If it spans multiple pages, all subsequent pages are rendered as usual without restriction.\n        /// </para>\n        /// <para>\n        /// This method is useful for ensuring that content remains visually coherent and is not arbitrarily split.\n        /// </para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/prevent-page-break.html\">Learn more</a>\n        /// </summary>\n        public static IContainer PreventPageBreak(this IContainer element)\n        {\n            return element.Element(new PreventPageBreak());\n        }\n\n        /// <summary>\n        /// Inserts a break that pushes the subsequent content to start on a new page.\n        /// <a href=\"https://www.questpdf.com/api-reference/page-break.html\">Learn more</a>\n        /// </summary>\n        public static void PageBreak(this IContainer element)\n        {\n            element.Element(new PageBreak());\n        }\n        \n        /// <summary>\n        /// A neutral layout structure that neither contributes to nor alters its content.\n        /// </summary>\n        /// <remarks>\n        /// By default, certain FluentAPI calls may be batched together for optimized performance. Introduce this element if you wish to separate and prevent such optimizations.\n        /// </remarks>\n        public static IContainer Container(this IContainer element)\n        {\n            return element.Element(new Container());\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the Hyperlink method.\")]\n        [ExcludeFromCodeCoverage]\n        public static IContainer ExternalLink(this IContainer element, string url)\n        {\n            return element.Hyperlink(url);\n        }\n        \n        /// <summary>\n        /// Creates a clickable area that redirects the user to a designated webpage.\n        /// <a href=\"https://www.questpdf.com/api-reference/hyperlink.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"param.url\"]/*' />\n        public static IContainer Hyperlink(this IContainer element, string url)\n        {\n            if (string.IsNullOrWhiteSpace(url))\n                throw new ArgumentException(\"The URL cannot be null or whitespace.\", nameof(url));\n            \n            return element.Element(new Hyperlink\n            {\n                Url = url\n            });\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the Section method.\")]\n        [ExcludeFromCodeCoverage]\n        public static IContainer Location(this IContainer element, string locationName)\n        {\n            return element.Section(locationName);\n        }\n        \n        /// <summary>\n        /// Defines a named fragment of the document that can span multiple pages.\n        /// <a href=\"https://www.questpdf.com/api-reference/section.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// <para>Several other elements interact with sections:</para>\n        /// <para>Use <see cref=\"ElementExtensions.SectionLink\">SectionLink</see> to create a clickable area redirecting user to the first page of the associated section.</para>\n        /// <para>The <see cref=\"TextExtensions.Text(IContainer, Action&lt;TextDescriptor&gt;)\">Text</see> element can display section properties, such as the starting page, ending page, and length.</para>\n        /// </remarks>\n        /// <param name=\"sectionName\">An internal text key representing the section. It should be unique and won't appear in the final document.</param>\n        public static IContainer Section(this IContainer element, string sectionName)\n        {\n            if (string.IsNullOrWhiteSpace(sectionName))\n                throw new ArgumentException(\"The section name cannot be null or whitespace.\", nameof(sectionName));\n            \n            return element\n                .DebugPointer(DebugPointerType.Section, sectionName)\n                .Element(new Section\n                {\n                    SectionName = sectionName\n                });\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the SectionLink method.\")]\n        [ExcludeFromCodeCoverage]\n        public static IContainer InternalLink(this IContainer element, string locationName)\n        {\n            return element.SectionLink(locationName);\n        }\n        \n        /// <summary>\n        /// Creates a clickable area that navigates the user to a designated section.\n        /// <a href=\"https://www.questpdf.com/api-reference/section-link.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"param.sectionName\"]/*' />\n        public static IContainer SectionLink(this IContainer element, string sectionName)\n        {\n            if (string.IsNullOrWhiteSpace(sectionName))\n                throw new ArgumentException(\"The section name cannot be null or whitespace.\", nameof(sectionName));\n            \n            return element.Element(new SectionLink\n            {\n                SectionName = sectionName\n            });\n        }\n        \n        /// <summary>\n        /// Conditionally draws or hides its inner content.\n        /// <a href=\"https://www.questpdf.com/api-reference/show-if.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"condition\">If the value is <see langword=\"true\"/>, its content is visible. Otherwise, it's hidden.</param>\n        public static IContainer ShowIf(this IContainer element, bool condition)\n        {\n            return condition ? element : new Container();\n        }\n        \n        /// <summary>\n        /// Conditionally draws or hides its inner content depending on drawing context.\n        /// Please use carefully as certain predicates may produce unstable layouts resulting with unexpected content or exceptions.\n        /// <a href=\"https://www.questpdf.com/api-reference/show-if.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"predicate\">If the predicate returns <see langword=\"true\"/>, its content is visible. Otherwise, it's hidden.</param>\n        public static IContainer ShowIf(this IContainer element, Predicate<ShowIfContext> predicate)\n        {\n            return element.Element(new ShowIf\n            {\n                VisibilityPredicate = predicate\n            });\n        }\n        \n        /// <summary>\n        /// Removes size constraints and grants its content virtually unlimited space.\n        /// <a href=\"https://www.questpdf.com/api-reference/unconstrained.html\">Learn more</a>\n        /// </summary>\n        public static IContainer Unconstrained(this IContainer element)\n        {\n            return element.Element(new Unconstrained());\n        }\n        \n        /// <summary>\n        /// Applies a default text style to all nested <see cref=\"MediaTypeNames.Text\">Text</see> elements.\n        /// <a href=\"https://www.questpdf.com/api-reference/default-text-style.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// If multiple text elements have a similar style, using this element can help simplify your code.\n        /// </remarks>\n        /// <param name=\"textStyle\">A TextStyle object used to override specific properties.</param>\n        public static IContainer DefaultTextStyle(this IContainer element, TextStyle textStyle)\n        {\n            return element.Element(new DefaultTextStyle\n            {\n                TextStyle = textStyle\n            });\n        }\n        \n        /// <summary>\n        /// Applies a default text style to all nested <see cref=\"MediaTypeNames.Text\">Text</see> elements.\n        /// <a href=\"https://www.questpdf.com/api-reference/default-text-style.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// If multiple text elements have a similar style, using this element can help simplify your code.\n        /// </remarks>\n        /// <param name=\"handler\">A handler to modify the default text style.</param>\n        public static IContainer DefaultTextStyle(this IContainer element, Func<TextStyle, TextStyle> handler)\n        {\n            return element.Element(new DefaultTextStyle\n            {\n                TextStyle = handler(TextStyle.Default)\n            });\n        }\n        \n        /// <summary>\n        /// Renders the element exclusively on the first page. Any portion of the element that doesn't fit is omitted.\n        /// <a href=\"https://www.questpdf.com/api-reference/stop-paging.html\">Learn more</a>\n        /// </summary>\n        public static IContainer StopPaging(this IContainer element)\n        {\n            return element.Element(new StopPaging());\n        }\n        \n        /// <summary>\n        /// Adjusts its content to fit within the available space by scaling it down proportionally if necessary.\n        /// <a href=\"https://www.questpdf.com/api-reference/scale-to-fit.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// <para>This container determines the best scale value through multiple scaling operations. With complex content, this may impact performance.</para>\n        /// <para>Pairing with certain elements, such as <see cref=\"ElementExtensions.AspectRatio\">AspectRatio</see>, might still lead to a <see cref=\"DocumentLayoutException\" />.</para>\n        /// </remarks>\n        public static IContainer ScaleToFit(this IContainer element)\n        {\n            return element.Element(new ScaleToFit());\n        }\n\n        /// <summary>\n        /// Repeats its content across multiple pages.\n        /// <a href=\"https://www.questpdf.com/api-reference/repeat.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// In certain layout structures, the content visibility may depend on other elements.\n        /// By default, most elements are rendered only once.\n        /// Use this element to repeat the content across multiple pages.\n        /// </remarks>\n        public static IContainer Repeat(this IContainer element)\n        {\n            return element.Element(new RepeatContent());\n        }\n        \n        internal static IContainer RepeatAsHeader(this IContainer element)\n        {\n            return element.Element(new RepeatContent\n            {\n                RepeatContext = RepeatContent.RepeatContextType.PageHeader\n            });\n        }\n        \n        internal static IContainer RepeatAsFooter(this IContainer element)\n        {\n            return element.Element(new RepeatContent\n            {\n                RepeatContext = RepeatContent.RepeatContextType.PageFooter\n            });\n        }\n        \n        /// <summary>\n        /// <para>\n        /// Delays the creation of document content and reduces its lifetime, significantly lowering memory usage in large documents containing thousands of pages. \n        /// This approach also enhances garbage collection efficiency in memory-constrained environments.\n        /// </para>\n        /// <para>\n        /// The provided <paramref name=\"contentBuilder\"/> delegate is invoked later in the document generation process.\n        /// For optimal performance, divide your document into smaller sections, each encapsulated within its own Lazy element.\n        /// Further optimizations can be achieved by nesting Lazy elements within each other. \n        /// However, note that this technique may increase the overall document generation time due to deferred content processing.\n        /// </para>\n        /// <a href=\"https://www.questpdf.com/api-reference/lazy.html\">Learn more</a>\n        /// </summary>\n        public static void Lazy(this IContainer element, Action<IContainer> contentBuilder)\n        {\n            element.Element(new Lazy\n            {\n                ContentSource = contentBuilder,\n                IsCacheable = false\n            });\n        }\n        \n        /// <summary>\n        /// Functions similarly to the Lazy element but enables the library to use caching mechanisms for the content.\n        /// This can help optimize managed memory usage, although native memory usage may remain high.\n        /// Use LazyWithCache only when the increased generation time associated with the Lazy element is unacceptable.\n        /// <a href=\"https://www.questpdf.com/api-reference/lazy.html\">Learn more</a>\n        /// </summary>\n        public static void LazyWithCache(this IContainer element, Action<IContainer> contentBuilder)\n        {\n            element.Element(new Lazy\n            {\n                ContentSource = contentBuilder,\n                IsCacheable = true\n            });\n        }\n        \n        /// <summary>\n        /// By default, the library draws content in the order it is defined, which may not always be the desired behavior.\n        /// This element allows you to alter the rendering order, ensuring that the content is displayed in the correct sequence.\n        /// The default z-index is 0, unless a different value is inherited from a parent container.\n        /// <a href=\"https://www.questpdf.com/api-reference/z-index.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"indexValue\">The z-index value. Higher values are rendered above lower values.</param>\n        public static IContainer ZIndex(this IContainer element, int indexValue)\n        {\n            return element.Element(new ZIndex\n            {\n                Depth = indexValue\n            });\n        }\n        \n        /// <summary>\n        /// Observes the rendering process of its content and captures its position and size on each page.\n        /// The captured data can be then used in the Dynamic component to build and position other elements.\n        /// <a href=\"https://www.questpdf.com/concepts/code-patterns/capture-content-position.html\">Learn more</a>\n        /// </summary>\n        public static IContainer CaptureContentPosition(this IContainer element, string id)\n        {\n            return element.Element(new ElementPositionLocator\n            {\n                Id = id\n            });\n        }\n        \n        #region Canvas [Obsolete]\n\n        private const string CanvasDeprecatedMessage = \"The Canvas API has been deprecated since version 2024.3.0. Please use the .Svg(stringContent) API to provide custom content, and consult documentation webpage regarding integrating SkiaSharp with QuestPDF: https://www.questpdf.com/api-reference/skiasharp-integration.html\";\n        \n        [Obsolete(CanvasDeprecatedMessage)]\n        public delegate void DrawOnCanvas(object canvas, Size availableSpace);\n        \n        [Obsolete(CanvasDeprecatedMessage)]\n        [ExcludeFromCodeCoverage]\n        public static void Canvas(this IContainer element, DrawOnCanvas handler)\n        {\n            throw new NotImplementedException(CanvasDeprecatedMessage);\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Fluent/ExtendExtensions.cs",
    "content": "﻿using QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class ExtendExtensions\n    {\n        private static IContainer Extend(this IContainer element, bool vertical = false, bool horizontal = false)\n        {\n            var extend = element as Extend ?? new Extend();\n\n            extend.ExtendVertical |= vertical;\n            extend.ExtendHorizontal |= horizontal;\n            \n            return element.Element(extend);\n        }\n        \n        /// <summary>\n        /// Forces its content to occupy entire available space, maximizing both width and height.\n        /// <a href=\"https://www.questpdf.com/api-reference/extend.html\">Learn more</a>\n        /// </summary>\n        public static IContainer Extend(this IContainer element)\n        {\n            return element.Extend(horizontal: true, vertical: true);\n        }\n        \n        /// <summary>\n        /// Forces its content to occupy entire available vertical space, maximizing height usage.\n        /// <a href=\"https://www.questpdf.com/api-reference/extend.html\">Learn more</a>\n        /// </summary>\n        public static IContainer ExtendVertical(this IContainer element)\n        {\n            return element.Extend(vertical: true);\n        }\n        \n        /// <summary>\n        /// Expands its content to occupy entire available horizontal space, maximizing width usage.\n        /// <a href=\"https://www.questpdf.com/api-reference/extend.html\">Learn more</a>\n        /// </summary>\n        public static IContainer ExtendHorizontal(this IContainer element)\n        {\n            return element.Extend(horizontal: true);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/GenerateExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Fluent\n{\n    public static class GenerateExtensions\n    {\n        static GenerateExtensions()\n        {\n            ClearGenerateAndShowFiles();\n        }\n        \n        internal static void Generate(this IDocument document, IDocumentCanvas documentCanvas)\n        {\n            DocumentGenerator.RenderDocument(documentCanvas, document, DocumentSettings.Default);\n        }\n        \n        #region Genearate And Show Configuration\n\n        private static readonly Random Random = new();\n        private const string GenerateAndShowNamePrefix = \"QuestPDF Preview\";\n\n        private static void ClearGenerateAndShowFiles()\n        {\n            var legacyPreviewFiles = Directory\n                .GetFiles(TemporaryStorage.GetPath(), $\"{GenerateAndShowNamePrefix} *\")\n                .Where(x => DateTime.UtcNow - new FileInfo(x).LastAccessTimeUtc > TimeSpan.FromHours(1));\n            \n            foreach (var legacyPreviewFile in legacyPreviewFiles)\n            {\n                try\n                {\n                    if (File.Exists(legacyPreviewFile))\n                        File.Delete(legacyPreviewFile);\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n\n        #endregion\n        \n        #region PDF\n        \n        /// <summary>\n        /// Generates the document in PDF format and returns it as a byte array.\n        /// </summary>\n        public static byte[] GeneratePdf(this IDocument document)\n        {\n            using var memoryStream = new MemoryStream();\n            document.GeneratePdf(memoryStream);\n            return memoryStream.ToArray();\n        }\n        \n        /// <summary>\n        /// Generates the document in PDF format and saves it to the specified file path.\n        /// </summary>\n        public static void GeneratePdf(this IDocument document, string filePath)\n        {\n            if (File.Exists(filePath))\n                File.Delete(filePath);\n            \n            using var fileStream = File.Create(filePath);\n            document.GeneratePdf(fileStream);\n        }\n\n        /// <summary>\n        /// Generates the document in PDF format and outputs it to a provided stream.\n        /// </summary>\n        public static void GeneratePdf(this IDocument document, Stream stream)\n        {\n            using var skiaStream = new SkWriteStream(stream);\n            DocumentGenerator.GeneratePdf(skiaStream, document);\n            skiaStream.Flush();\n        }\n        \n        /// <summary>\n        /// Generates the document in PDF format, saves it in temporary file, and then opens it with the default application.\n        /// </summary>\n        public static void GeneratePdfAndShow(this IDocument document)\n        {\n            var filePath = Path.Combine(TemporaryStorage.GetPath(), $\"{GenerateAndShowNamePrefix} {Random.Next()}.pdf\");\n            \n            document.GeneratePdf(filePath);\n            Helpers.Helpers.OpenFileUsingDefaultProgram(filePath);\n        }\n\n        #endregion\n\n        #region XPS\n        \n        /// <summary>\n        /// Generates the document in XPS format and returns it as a byte array.\n        /// </summary>\n        /// <remarks>\n        /// Supported only on the Windows platform.\n        /// </remarks>\n        public static byte[] GenerateXps(this IDocument document)\n        {\n            using var memoryStream = new MemoryStream();\n            document.GenerateXps(memoryStream);\n            return memoryStream.ToArray();\n        }\n        \n        /// <summary>\n        /// Generates the document in XPS format and saves it to the specified file path.\n        /// </summary>\n        /// <remarks>\n        /// Supported only on the Windows platform.\n        /// </remarks>\n        public static void GenerateXps(this IDocument document, string filePath)\n        {\n            if (File.Exists(filePath))\n                File.Delete(filePath);\n            \n            using var fileStream = File.Create(filePath);\n            document.GenerateXps(fileStream);\n        }\n\n        /// <summary>\n        /// Generates the document in XPS format and outputs it to a provided stream.\n        /// </summary>\n        /// <remarks>\n        /// Supported only on the Windows platform.\n        /// </remarks>\n        public static void GenerateXps(this IDocument document, Stream stream)\n        {\n            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                throw new PlatformNotSupportedException(\"XPS generation is only supported on the Windows platform.\");\n            \n            using var skiaStream = new SkWriteStream(stream);\n            DocumentGenerator.GenerateXps(skiaStream, document);\n            skiaStream.Flush();\n        }\n        \n        /// <summary>\n        /// Generates the document in XPS format, saves it in temporary file, and then opens it with the default application.\n        /// </summary>\n        /// <remarks>\n        /// Supported only on the Windows platform.\n        /// </remarks>\n        public static void GenerateXpsAndShow(this IDocument document)\n        {\n            var filePath = Path.Combine(TemporaryStorage.GetPath(), $\"{GenerateAndShowNamePrefix} {Random.Next()}.xps\");\n            document.GenerateXps(filePath);\n            Helpers.Helpers.OpenFileUsingDefaultProgram(filePath);\n        }\n        \n        #endregion\n\n        #region Images\n\n        /// <summary>\n        /// Generates the document as a series of images and returns them as a collection of byte arrays.\n        /// </summary>\n        /// <param name=\"settings\">Optional settings to customize the generation process, such as image resolution, compression ratio, and more.</param>\n        public static IEnumerable<byte[]> GenerateImages(this IDocument document, ImageGenerationSettings? settings = null)\n        {\n            settings ??= ImageGenerationSettings.Default;\n            return DocumentGenerator.GenerateImages(document, settings);\n        }\n\n        /// <param name=\"imageIndex\">Specifies the index of the generated image from the document, starting at 0.</param>\n        /// <returns>The file path where the image should be saved.</returns>\n        public delegate string GenerateDocumentImagePath(int imageIndex);\n        \n        /// <summary>\n        /// Generates the document as a sequence of images, saving them to paths determined by the <paramref name=\"imagePathSource\"/> delegate.\n        /// </summary>\n        /// <param name=\"imagePathSource\">A delegate that gets image index as an input, and returns file path where it should be saved.</param>\n        /// <param name=\"settings\">Optional settings for fine-tuning the generated images, such as resolution, compression ratio, etc.</param>\n        public static void GenerateImages(this IDocument document, GenerateDocumentImagePath imagePathSource, ImageGenerationSettings? settings = null)\n        {\n            settings ??= ImageGenerationSettings.Default;\n            \n            var index = 0;\n\n            foreach (var imageData in document.GenerateImages(settings))\n            {\n                var path = imagePathSource(index);\n\n                if (File.Exists(path))\n                    File.Delete(path);\n\n                File.WriteAllBytes(path, imageData);\n                index++;\n            }\n        }\n\n        #endregion\n        \n        #region SVG\n\n        /// <summary>\n        /// Generates the document as a series of SVG images and returns them as a collection of strings.\n        /// </summary>\n        public static ICollection<string> GenerateSvg(this IDocument document)\n        {\n            return DocumentGenerator.GenerateSvg(document);\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/GridExtensions.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class GridDescriptor\n    {\n        internal Grid Grid { get; } = new Grid();\n\n        internal GridDescriptor()\n        {\n            \n        }\n        \n        public void Spacing(float value, Unit unit = Unit.Point)\n        {\n            VerticalSpacing(value, unit);\n            HorizontalSpacing(value, unit);\n        }\n        \n        public void VerticalSpacing(float value, Unit unit = Unit.Point)\n        {\n            if (value < 0)\n                throw new ArgumentOutOfRangeException(nameof(value), \"The Grid vertical spacing cannot be negative.\");\n            \n            Grid.VerticalSpacing = value.ToPoints(unit);\n        }\n         \n        public void HorizontalSpacing(float value, Unit unit = Unit.Point)\n        {\n            if (value < 0)\n                throw new ArgumentOutOfRangeException(nameof(value), \"The Grid horizontal spacing cannot be negative.\");\n            \n            Grid.HorizontalSpacing = value.ToPoints(unit);\n        }\n        \n        public void Columns(int value = Grid.DefaultColumnsCount)\n        {\n            if (value < 1)\n                throw new ArgumentOutOfRangeException(nameof(value), \"The Grid columns count cannot be less than 1.\");\n            \n            Grid.ColumnsCount = value;\n        }\n        \n        public void Alignment(HorizontalAlignment alignment)\n        {\n            Grid.Alignment = alignment;\n        }\n\n        public void AlignLeft() => Alignment(HorizontalAlignment.Left);\n        public void AlignCenter() => Alignment(HorizontalAlignment.Center);\n        public void AlignRight() => Alignment(HorizontalAlignment.Right);\n        \n        public IContainer Item(int columns = 1)\n        {\n            if (columns < 1)\n                throw new ArgumentOutOfRangeException(nameof(columns), \"The Grid item cannot span less than 1 column.\");\n            \n            var container = new Container();\n            \n            var element = new GridElement\n            {\n                Columns = columns,\n                Child = container\n            };\n            \n            Grid.Children.Add(element);\n            return container;\n        }\n    }\n    \n    public static class GridExtensions\n    {\n        [Obsolete(\"This element has been deprecated since version 2022.11. Please use the Table element, or the combination of the Row and Column elements.\")]\n        [ExcludeFromCodeCoverage]\n        public static void Grid(this IContainer element, Action<GridDescriptor> handler)\n        {\n            var descriptor = new GridDescriptor();\n            \n            if (element is Alignment alignment && alignment.Horizontal.HasValue)\n                descriptor.Alignment(alignment.Horizontal.Value);\n            \n            handler(descriptor);\n            element.Component(descriptor.Grid);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/ImageExtensions.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class DynamicImageDescriptor\n    {\n        private Elements.DynamicImage ImageElement { get; }\n        \n        internal DynamicImageDescriptor(Elements.DynamicImage imageElement)\n        {\n            ImageElement = imageElement;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.useOriginalImage\"]/*' />\n        public DynamicImageDescriptor UseOriginalImage(bool value = true)\n        {\n            ImageElement.UseOriginalImage = value;\n            return this;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.rasterDPI\"]/*' />\n        public DynamicImageDescriptor WithRasterDpi(int dpi)\n        {\n            if (dpi <= 0)\n                throw new DocumentComposeException(\"DPI value must be greater than 0.\");\n            \n            ImageElement.TargetDpi = dpi;\n            return this;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.compressionQuality\"]/*' />\n        public DynamicImageDescriptor WithCompressionQuality(ImageCompressionQuality quality)\n        {\n            ImageElement.CompressionQuality = quality;\n            return this;\n        }\n    }\n    \n    public sealed class ImageDescriptor\n    {\n        private Elements.Image ImageElement { get; }\n        private AspectRatio AspectRatioElement { get; }\n        private float ImageAspectRatio { get; }\n\n        internal ImageDescriptor(Elements.Image imageElement, Elements.AspectRatio aspectRatioElement)\n        {\n            ImageElement = imageElement;\n            AspectRatioElement = aspectRatioElement;\n\n            var imageSize = ImageElement.DocumentImage.Size;\n            ImageAspectRatio = imageSize.Width / (float)imageSize.Height;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.useOriginalImage\"]/*' />\n        public ImageDescriptor UseOriginalImage(bool value = true)\n        {\n            ImageElement.UseOriginalImage = value;\n            return this;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.rasterDPI\"]/*' />\n        public ImageDescriptor WithRasterDpi(int dpi)\n        {\n            if (dpi <= 0)\n                throw new DocumentComposeException(\"DPI value must be greater than 0.\");\n            \n            ImageElement.TargetDpi = dpi;\n            return this;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.compressionQuality\"]/*' />\n        public ImageDescriptor WithCompressionQuality(ImageCompressionQuality quality)\n        {\n            ImageElement.CompressionQuality = quality;\n            return this;\n        }\n\n        #region Aspect Ratio\n        \n        /// <summary>\n        /// Scales the image to fill the full width of its container. This is the default behavior.\n        /// </summary>\n        public ImageDescriptor FitWidth()\n        {\n            return SetAspectRatio(AspectRatioOption.FitWidth);\n        }\n        \n        /// <summary>\n        /// <para>The image stretches vertically to fit the full available height.</para>\n        /// <para>Often used with height-constraining elements such as: <see cref=\"ConstrainedExtensions.Height\">Height</see>, <see cref=\"ConstrainedExtensions.MaxHeight\">MaxHeight</see>, etc.</para>\n        /// </summary>\n        public ImageDescriptor FitHeight()\n        {\n            return SetAspectRatio(AspectRatioOption.FitHeight);\n        }\n        \n        /// <summary>\n        /// Combines the FitWidth and FitHeight settings.\n        /// The image resizes itself to utilize all available space, preserving its aspect ratio.\n        /// It will either fill the width or height based on the container's dimensions.\n        /// </summary>\n        /// <remarks>\n        /// An optimal and safe choice.\n        /// </remarks>\n        public ImageDescriptor FitArea()\n        {\n            return SetAspectRatio(AspectRatioOption.FitArea);\n        }\n        \n        /// <summary>\n        /// The image adjusts to fill all the available space, disregarding its original proportions.\n        /// This can lead to distorted scaling and is generally not recommended for most scenarios.\n        /// </summary>\n        public ImageDescriptor FitUnproportionally()\n        {\n            AspectRatioElement.Ratio = 0;\n            return this;\n        }\n        \n        internal ImageDescriptor SetAspectRatio(AspectRatioOption option)\n        {\n            AspectRatioElement.Ratio = ImageAspectRatio;\n            AspectRatioElement.Option = option;\n            return this;\n        }\n        \n        #endregion\n    }\n    \n    public static class ImageExtensions\n    {\n        /// <summary>\n        /// Draws an image by decoding it from a provided byte array.\n        /// <a href=\"https://www.questpdf.com/api-reference/image/basics.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.remarks\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.descriptor\"]/*' />\n        public static ImageDescriptor Image(this IContainer parent, byte[] imageData)\n        {\n            var image = Infrastructure.Image.FromBinaryData(imageData);\n            image.IsShared = false;\n            return parent.Image(image);\n        }\n        \n        /// <summary>\n        /// Draws the image loaded from a file located at the provided path.\n        /// <a href=\"https://www.questpdf.com/api-reference/image/basics.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.remarks\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.descriptor\"]/*' />\n        public static ImageDescriptor Image(this IContainer parent, string filePath)\n        {\n            var image = StaticImageCache.LoadFromCache(filePath);\n            return parent.Image(image);\n        }\n        \n        /// <summary>\n        /// Draws the image loaded from a stream.\n        /// <a href=\"https://www.questpdf.com/api-reference/image/basics.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.remarks\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.descriptor\"]/*' />\n        public static ImageDescriptor Image(this IContainer parent, Stream fileStream)\n        {\n            var image = Infrastructure.Image.FromStream(fileStream);\n            image.IsShared = false;\n            return parent.Image(image);\n        }\n        \n        /// <summary>\n        /// Draws the <see cref=\"Infrastructure.Image\" /> object. Allows to optimize the generation process.\n        /// <a href=\"https://www.questpdf.com/api-reference/image/basics.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.remarks\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.descriptor\"]/*' />\n        public static ImageDescriptor Image(this IContainer parent, Infrastructure.Image image)\n        {\n            if (image == null)\n                throw new DocumentComposeException(\"Cannot load or decode provided image.\");\n            \n            var imageElement = new QuestPDF.Elements.Image\n            {\n                DocumentImage = image\n            };\n\n            var aspectRationElement = new AspectRatio\n            {\n                Child = imageElement\n            };\n            \n            parent.Element(aspectRationElement);\n\n            var bestScalingOption = GetBestAspectRatioOptionFromParent(parent);\n            return new ImageDescriptor(imageElement, aspectRationElement).SetAspectRatio(bestScalingOption);\n        }\n        \n        internal static AspectRatioOption GetBestAspectRatioOptionFromParent(IContainer container)\n        {\n            if (container is not Constrained constrained)\n                return AspectRatioOption.FitWidth;\n\n            var hasWidthConstraint = constrained.MinWidth is not null || constrained.MaxWidth is not null;\n            var hasHeightConstraint = constrained.MinHeight is not null || constrained.MaxHeight is not null;\n                \n            if (hasWidthConstraint && hasHeightConstraint)\n                return AspectRatioOption.FitArea;\n                \n            if (hasWidthConstraint)\n                return AspectRatioOption.FitWidth;\n                \n            if (hasHeightConstraint)\n                return AspectRatioOption.FitHeight;\n                \n            return AspectRatioOption.FitWidth;\n        }\n        \n        /// <summary>\n        /// Renders an image of dynamic size dictated by the document layout constraints.\n        /// </summary>\n        /// <remarks>\n        /// Ideal for generating pixel-perfect images that might lose quality upon scaling, such as maps or charts.\n        /// </remarks>\n        /// <param name=\"dynamicImageSource\">\n        /// A delegate that requests an image of desired resolution calculated based on target physical image size and provided DPI.\n        /// </param>\n        /// <returns>A descriptor for adjusting image attributes like scaling behavior, compression quality, and resolution.</returns>\n        public static DynamicImageDescriptor Image(this IContainer element, GenerateDynamicImageDelegate dynamicImageSource)\n        {\n            var dynamicImage = new DynamicImage\n            {\n                Source = dynamicImageSource\n            };\n            \n            element.Element(dynamicImage);\n            return new DynamicImageDescriptor(dynamicImage);\n        }\n        \n        /// <summary>\n        /// Renders an image of dynamic size dictated by the document layout constraints.\n        /// </summary>\n        /// <remarks>\n        /// Ideal for generating pixel-perfect images that might lose quality upon scaling, such as maps or charts.\n        /// </remarks>\n        /// <param name=\"dynamicImageSource\">\n        /// A delegate that requests an image of desired resolution calculated based on target physical image size and provided DPI.\n        /// </param>\n        /// <returns>A descriptor for adjusting image attributes like scaling behavior, compression quality, and resolution.</returns>\n        public static DynamicImageDescriptor Image(this IContainer element, Func<ImageSize, byte[]> dynamicImageSource)\n        {\n            var dynamicImage = new DynamicImage\n            {\n                Source = payload => dynamicImageSource(payload.ImageSize)\n            };\n            \n            element.Element(dynamicImage);\n            return new DynamicImageDescriptor(dynamicImage);\n        }\n        \n        #region Obsolete\n        \n        [Obsolete(\"This element has been changed since version 2023.5. Please use the Image method overload that takes the GenerateDynamicImageDelegate as an argument.\")]\n        [ExcludeFromCodeCoverage]\n        public static void Image(this IContainer element, Func<Size, byte[]> imageSource)\n        {\n            element.Image((ImageSize x) => imageSource(new Size(x.Width, x.Height)));\n        }\n        \n        [Obsolete(\"This element has been changed since version 2023.5. Please use the Image method overload that returns the ImageDescriptor object.\")]\n        [ExcludeFromCodeCoverage]\n        public static void Image(this IContainer parent, byte[] imageData, ImageScaling scaling)\n        {\n            parent.Image(imageData).ApplyScaling(scaling);\n        }\n        \n        [Obsolete(\"This element has been changed since version 2023.5. Please use the Image method overload that returns the ImageDescriptor object.\")]\n        [ExcludeFromCodeCoverage]\n        public static void Image(this IContainer parent, string filePath, ImageScaling scaling)\n        {\n            parent.Image(filePath).ApplyScaling(scaling);\n        }\n        \n        [Obsolete(\"This element has been changed since version 2023.5. Please use the Image method overload that returns the ImageDescriptor object.\")]\n        [ExcludeFromCodeCoverage]\n        public static void Image(this IContainer parent, Stream fileStream, ImageScaling scaling)\n        {\n            parent.Image(fileStream).ApplyScaling(scaling);\n        }\n        \n        internal static void ApplyScaling(this ImageDescriptor descriptor, ImageScaling scaling)\n        {\n            if (scaling == ImageScaling.Resize)\n                descriptor.FitUnproportionally();\n\n            else if (scaling == ImageScaling.FitWidth)\n                descriptor.FitWidth();\n            \n            else if (scaling == ImageScaling.FitHeight)\n                descriptor.FitHeight();\n            \n            else if (scaling == ImageScaling.FitArea)\n                descriptor.FitArea();\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/InlinedExtensions.cs",
    "content": "﻿using System;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class InlinedDescriptor\n    {\n        internal Inlined Inlined { get; } = new Inlined();\n\n        internal InlinedDescriptor()\n        {\n            \n        }\n        \n        #region Spacing\n        \n        /// <summary>\n        /// Sets the vertical and horizontal gaps between items.\n        /// </summary>\n        public void Spacing(float value, Unit unit = Unit.Point)\n        {\n            VerticalSpacing(value, unit);\n            HorizontalSpacing(value, unit);\n        }\n        \n        /// <summary>\n        /// Sets the vertical gaps between items.\n        /// </summary>\n        public void VerticalSpacing(float value, Unit unit = Unit.Point)\n        {\n            if (value < 0)\n                throw new ArgumentOutOfRangeException(nameof(value), \"The Inlined vertical spacing cannot be negative.\");\n            \n            Inlined.VerticalSpacing = value.ToPoints(unit);\n        }\n\n        /// <summary>\n        /// Sets the horizontal gaps between items.\n        /// </summary>\n        public void HorizontalSpacing(float value, Unit unit = Unit.Point)\n        {\n            if (value < 0)\n                throw new ArgumentOutOfRangeException(nameof(value), \"The Inlined horizontal spacing cannot be negative.\");\n            \n            Inlined.HorizontalSpacing = value.ToPoints(unit);\n        }\n        \n        #endregion\n        \n        #region Baseline\n\n        /// <summary>\n        /// Positions items vertically such that their top edges align on a single line.\n        /// </summary>\n        public void BaselineTop()\n        {\n            Inlined.BaselineAlignment = VerticalAlignment.Top;\n        }\n\n        /// <summary>\n        /// Positions items to have their centers in a straight horizontal line.\n        /// </summary>\n        public void BaselineMiddle()\n        {\n            Inlined.BaselineAlignment = VerticalAlignment.Middle;\n        }\n\n        /// <summary>\n        /// Positions items vertically such that their bottom edges align on a single line.\n        /// </summary>\n        public void BaselineBottom()\n        {\n            Inlined.BaselineAlignment = VerticalAlignment.Bottom;\n        }\n\n        #endregion\n\n        #region Horizontal Alignment\n        \n        internal void Alignment(InlinedAlignment? alignment)\n        {\n            Inlined.ElementsAlignment = alignment;\n        }\n\n        /// <summary>\n        /// Aligns items horizontally to the left side.\n        /// </summary>\n        public void AlignLeft()\n        {\n            Inlined.ElementsAlignment = InlinedAlignment.Left;\n        }\n\n        /// <summary>\n        /// Aligns items horizontally to the center.\n        /// </summary>\n        public void AlignCenter()\n        {\n            Inlined.ElementsAlignment = InlinedAlignment.Center;\n        }\n\n        /// <summary>\n        /// Aligns items horizontally to the left right.\n        /// </summary>\n        public void AlignRight()\n        {\n            Inlined.ElementsAlignment = InlinedAlignment.Right;\n        }\n\n        /// <summary>\n        /// Distributes items horizontally, ensuring even spacing from edge to edge of the container.\n        /// </summary>\n        public void AlignJustify()\n        {\n            Inlined.ElementsAlignment = InlinedAlignment.Justify;\n        }\n        \n        /// <summary>\n        /// Spaces items equally in a horizontal arrangement, both between items and at the ends.\n        /// </summary>\n        public void AlignSpaceAround()\n        {\n            Inlined.ElementsAlignment = InlinedAlignment.SpaceAround;\n        }\n\n        #endregion\n\n        /// <summary>\n        /// Adds a new item to the container.\n        /// </summary>\n        /// <returns>The container of the newly created item.</returns>\n        public IContainer Item()\n        {\n            var container = new Constrained();\n            Inlined.Elements.Add(container);\n            return container;\n        }\n    }\n    \n    public static class InlinedExtensions\n    {\n        /// <summary>\n        /// Arranges its items sequentially in a line, wrapping to the next line if necessary.\n        /// <a href=\"https://www.questpdf.com/api-reference/inlined.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// Supports the paging functionality.\n        /// </remarks>\n        /// <param name=\"handler\">Handler to configure content of this container, as well as spacing and items alignment.</param>\n        public static void Inlined(this IContainer element, Action<InlinedDescriptor> handler)\n        {\n            var descriptor = new InlinedDescriptor();\n            handler(descriptor);\n            \n            element.Element(descriptor.Inlined);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/LayerExtensions.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class LayersDescriptor\n    {\n        internal Layers Layers { get; } = new Layers();\n\n        internal LayersDescriptor()\n        {\n            \n        }\n        \n        private IContainer Layer(bool isPrimary)\n        {\n            var container = new Container();\n            \n            var element = new Layer\n            {\n                IsPrimary = isPrimary,\n                Child = container\n            };\n            \n            Layers.Children.Add(element);\n            return container;\n        }\n\n        /// <summary>\n        /// Specifies an additional layer for the container.\n        /// </summary>\n        /// <remarks>\n        /// <para>The order of code execution determines the drawing order:</para>\n        /// <para>If the layer is defined before the primary layer, it's drawn underneath the primary content (as a background).</para>\n        /// <para>If defined after the primary layer, it's drawn in front of the primary content (as a watermark).</para>\n        /// </remarks>\n        public IContainer Layer() => Layer(false);\n        \n        /// <summary>\n        /// Sets the primary content for the container. \n        /// </summary>\n        /// <remarks>\n        /// Exactly one primary layer should be defined.\n        /// </remarks>\n        public IContainer PrimaryLayer() => Layer(true);\n\n        internal void Validate()\n        {\n            var primaryLayers = Layers.Children.Count(x => x.IsPrimary);\n\n            if (primaryLayers == 0)\n                throw new DocumentComposeException(\"The Layers component needs to have exactly one primary layer. It has none.\");\n            \n            if (primaryLayers != 1)\n                throw new DocumentComposeException($\"The Layers component needs to have exactly one primary layer. It has {primaryLayers}.\");\n        }\n    }\n    \n    public static class LayerExtensions\n    {\n        /// <summary>\n        /// <para>Adds content either underneath (as a background) or on top of (as a watermark) the main content.</para>\n        /// <para>The main layer supports paging, can span multiple pages, and determines the container's target length.</para>\n        /// <para>Additional layers can also span multiple pages and are repeated on each one.</para>\n        /// <a href=\"https://www.questpdf.com/api-reference/layers.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"handler\">Handler for defining content of the container, including exactly one primary layer and any additional layers in a specified order.</param>\n        public static void Layers(this IContainer element, Action<LayersDescriptor> handler)\n        {\n            var descriptor = new LayersDescriptor();\n\n            handler(descriptor);\n            descriptor.Validate();\n            \n            element.Element(descriptor.Layers);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/LineExtensions.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public class LineDescriptor\n    {\n        internal Line Line { get; } = new Line();\n\n        internal LineDescriptor()\n        {\n            \n        }\n        \n        /// <summary>\n        /// Specifies the color for the line.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public LineDescriptor LineColor(Color color)\n        {\n            Line.Color = color;\n            return this;\n        }\n\n        /// <summary>\n        /// Configures a dashed pattern for the line.\n        /// For example, a pattern of [2, 3] creates a dash of 2 units followed by a gap of 3 units.\n        /// </summary>\n        /// <param name=\"dashPattern\">The length of this array must be even.</param>\n        public LineDescriptor LineDashPattern(float[] dashPattern, Unit unit = Unit.Point)\n        {\n            if (dashPattern == null)\n                throw new ArgumentNullException(nameof(dashPattern), \"The dash pattern cannot be null.\");\n            \n            if (dashPattern.Length == 0)\n                throw new ArgumentException(\"The dash pattern cannot be empty.\", nameof(dashPattern));\n            \n            if (dashPattern.Length % 2 != 0)\n                throw new ArgumentException(\"The dash pattern must contain an even number of elements.\", nameof(dashPattern));\n            \n            Line.DashPattern = dashPattern.Select(x => x.ToPoints(unit)).ToArray();\n            return this;\n        }\n\n        /// <summary>\n        /// Applies a linear gradient to a line using the specified colors.\n        /// </summary>\n        public LineDescriptor LineGradient(Color[] colors)\n        {\n            if (colors == null)\n                throw new ArgumentNullException(nameof(colors), \"The gradient colors cannot be null.\");\n\n            if (colors.Length == 0)\n                throw new ArgumentException(\"The gradient colors cannot be empty.\", nameof(colors));\n\n            Line.GradientColors = colors;\n            return this;\n        }\n    }\n    \n    public static class LineExtensions\n    {\n        private static LineDescriptor Line(this IContainer element, LineType type, float thickness)\n        {\n            if (thickness < 0)\n                throw new ArgumentOutOfRangeException(nameof(thickness), \"The Line thickness cannot be negative.\");\n            \n            var descriptor = new LineDescriptor();\n            descriptor.Line.Thickness = thickness;\n            descriptor.Line.Type = type;\n            \n            element.Element(descriptor.Line);\n            return descriptor;\n        }\n        \n        /// <summary>\n        /// Renders a vertical line with a specified thickness.\n        /// <a href=\"https://www.questpdf.com/api-reference/line.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// The line is not just a visual element; it occupies actual space within the document.\n        /// </remarks>\n        /// <returns>A descriptor to modify line attributes.</returns>\n        public static LineDescriptor LineVertical(this IContainer element, float thickness, Unit unit = Unit.Point)\n        {\n            return element.Line(LineType.Vertical, thickness.ToPoints(unit));\n        }\n        \n        /// <summary>\n        /// Renders a horizontal line with a specified thickness.\n        /// <a href=\"https://www.questpdf.com/api-reference/line.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// The line is not just a visual element; it occupies actual space within the document.\n        /// </remarks>\n        /// <returns>A descriptor to modify line attributes.</returns>\n        public static LineDescriptor LineHorizontal(this IContainer element, float thickness, Unit unit = Unit.Point)\n        {\n            return element.Line(LineType.Horizontal, thickness.ToPoints(unit));\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/MinimalApi.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class Document : IDocument\n    {\n        static Document()\n        {\n            SkNativeDependencyCompatibilityChecker.Test();\n        }\n        \n        private Action<IDocumentContainer> ContentSource { get; }\n        private DocumentMetadata Metadata { get; set; } = DocumentMetadata.Default;\n        private DocumentSettings Settings { get; set; } = DocumentSettings.Default;\n\n        private Document(Action<IDocumentContainer> contentSource)\n        {\n            ContentSource = contentSource;\n        }\n        \n        /// <summary>\n        /// Creates a new empty document and provides handler to specify its content.\n        /// </summary>\n        /// <returns>A Document object with the specified content. This object allows to set metadata, configure generation parameters, and produce output files such as PDF, XPS, or images.</returns>\n        public static Document Create(Action<IDocumentContainer> handler)\n        {\n            return new Document(handler);\n        }\n\n        /// <summary>\n        /// Configures the metadata of the PDF document, such as title, author, keywords, etc.\n        /// </summary>\n        public Document WithMetadata(DocumentMetadata metadata)\n        {\n            Metadata = metadata ?? Metadata;\n            return this;\n        }\n        \n        /// <summary>\n        /// Enables fine-tuning of the document generation process, influencing attributes of the resulting PDF such as target DPI, image compression, compliance with the PDF/A standard, etc.\n        /// </summary>\n        public Document WithSettings(DocumentSettings settings)\n        {\n            Settings = settings ?? Settings;\n            return this;\n        }\n        \n        /// <summary>\n        /// Combines multiple documents together into a single one.\n        /// </summary>\n        /// <returns>A MergedDocument object that allows to set metadata, configure generation parameters, adjust merging strategy, and produce output files such as PDF, XPS, or images.</returns>\n        public static MergedDocument Merge(IEnumerable<IDocument> documents)\n        {\n            return new MergedDocument(documents);\n        }\n\n        /// <summary>\n        /// Combines multiple documents together into a single one.\n        /// </summary>\n        /// <returns>A MergedDocument object that allows to set metadata, configure generation parameters, adjust merging strategy, and produce output files such as PDF, XPS, or images.</returns>\n        public static MergedDocument Merge(params IDocument[] documents)\n        {\n            return new MergedDocument(documents);\n        }\n        \n        #region IDocument\n\n        /// <summary>\n        /// Implements the IDocument interface. Don't use within the Fluent API chain.\n        /// </summary>\n        public DocumentMetadata GetMetadata() => Metadata;\n        \n        /// <summary>\n        /// Implements the IDocument interface. Don't use within the Fluent API chain.\n        /// </summary>\n        public DocumentSettings GetSettings() => Settings;\n        \n        /// <summary>\n        /// Implements the IDocument interface. Don't use within the Fluent API chain.\n        /// </summary>\n        public void Compose(IDocumentContainer container) => ContentSource(container);\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/MultiColumnExtensions.cs",
    "content": "using System;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Fluent;\n\npublic sealed class MultiColumnDescriptor\n{\n    internal MultiColumn MultiColumn { get; } = new MultiColumn();\n\n    internal MultiColumnDescriptor()\n    {\n        \n    }\n        \n    /// <summary>\n    /// Configures the horizontal spacing between adjacent columns in the layout.\n    /// </summary>\n    /// <remarks>\n    /// This method affects the visual presentation of the column arrangement.\n    /// Positive values increase separation, while negative values may cause overlap.\n    /// </remarks>\n    public void Spacing(float value, Unit unit = Unit.Point)\n    {\n        MultiColumn.Spacing = value.ToPoints(unit);\n    }\n    \n    /// <summary>\n    /// Defines the number of vertical columns in the layout.\n    /// </summary>\n    /// <remarks>\n    /// This method determines the basic structure of the grid layout.\n    /// Setting this value will redistribute the existing elements across the new column count.\n    /// </remarks>\n    public void Columns(int value = 2)\n    {\n        if (value < 2)\n            throw new DocumentComposeException(\"The 'MultiColumn.Columns' value should be higher than 1.\");\n        \n        MultiColumn.ColumnCount = value;\n    }\n\n    /// <summary>\n    /// Controls the content distribution across columns to achieve balanced heights.\n    /// </summary>\n    /// <remarks>\n    /// <para>When enabled: content flow is adjusted to equalize column heights; each column will have approximately the same height.</para>\n    /// <para>When disabled: layout occupies the full vertical space, the last column may be shorter or empty, depending on content quantity.</para>\n    /// </remarks>\n    public void BalanceHeight(bool enable = true)\n    {\n        MultiColumn.BalanceHeight = enable;\n    }\n\n    /// <summary>\n    /// Retrieves a container for the primary content to be distributed across multiple columns.\n    /// </summary>\n    /// <remarks>\n    /// The returned container serves as the main content area for the multi-column layout.\n    /// It supports all available layout elements and automatically divides its content among the defined columns.\n    /// </remarks>\n    public IContainer Content()\n    {\n        if (MultiColumn.Content is not Empty)\n            throw new DocumentComposeException(\"The 'MultiColumn.Content' layer has already been defined. Please call this method only once.\");\n        \n        var container = new Container();\n        MultiColumn.Content = container;\n        return container;\n    }\n    \n    /// <summary>\n    /// Retrieves a container for content positioned between columns in the layout.\n    /// </summary>\n    /// <remarks>\n    /// The container's dimensions are determined by the height of the columns and the configured spacing.\n    /// This container supports all available layout elements, allowing for flexible design of inter-column content.\n    /// </remarks>\n    public IContainer Spacer()\n    {\n        if (MultiColumn.Spacer is not Empty)\n            throw new DocumentComposeException(\"The 'MultiColumn.Spacer' layer has already been defined. Please call this method only once.\");\n        \n        var container = new Container();\n        MultiColumn.Spacer = container;\n        \n        return container\n            .Artifact(SkSemanticNodeSpecialId.LayoutArtifact)\n            .Repeat();\n    }\n}\n\npublic static class MultiColumnExtensions\n{\n    /// <summary>\n    /// Creates a multi-column layout within the current container element.\n    /// </summary>\n    /// <remarks>\n    /// A multi-column layout organizes content into vertical columns, similar to a newspaper or magazine layout.\n    /// This approach allows for efficient use of horizontal space and can improve readability, especially\n    /// for wide containers or screens. The content flows from one column to the next, and the number of\n    /// columns can be adjusted based on the container's width or specific design requirements.\n    /// </remarks>\n    /// <param name=\"handler\">The action to configure the column's content and behavior.</param>\n    public static void MultiColumn(this IContainer element, Action<MultiColumnDescriptor> handler)\n    {\n        var descriptor = new MultiColumnDescriptor();\n        handler(descriptor);\n\n        element\n            .Element(x => descriptor.MultiColumn.BalanceHeight ? x.ShrinkVertical() : x)\n            .Element(descriptor.MultiColumn);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/PaddingExtensions.cs",
    "content": "﻿using QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class PaddingExtensions\n    { \n        private static IContainer Padding(this IContainer element, float top = 0, float bottom = 0, float left = 0, float right = 0)\n        {\n            var padding = element as Padding ?? new Padding();\n\n            padding.Top += top;\n            padding.Bottom += bottom;\n            padding.Left += left;\n            padding.Right += right;\n            \n            return element.Element(padding);\n        }\n        \n        /// <summary>\n        /// <para>For positive values, adds empty space around its content.</para>\n        /// <para>For negative values, pushes its content beyond the edges, increasing available space, similarly to negative HTML margins.</para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/padding.html\">Learn more</a>\n        /// </summary>\n        public static IContainer Padding(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Padding(top: value, bottom: value, left: value, right: value);\n        }\n        \n        /// <summary>\n        /// <para>For positive values, adds empty space horizontally (left and right) around its content.</para>\n        /// <para>For negative values, pushes its content beyond the horizontal edges, increasing available space, similarly to negative HTML margins.</para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/padding.html\">Learn more</a>\n        /// </summary>\n        public static IContainer PaddingHorizontal(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Padding(left: value, right: value);\n        }\n\n        /// <summary>\n        /// <para>For positive values, adds empty space vertically (top and bottom) around its content.</para>\n        /// <para>For negative values, pushes its content beyond the vertical edges, increasing available space, similarly to negative HTML margins.</para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/padding.html\">Learn more</a>\n        /// </summary>\n        public static IContainer PaddingVertical(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Padding(top: value, bottom: value);\n        }\n        \n        /// <summary>\n        /// <para>For positive values, adds empty space above its content.</para>\n        /// <para>For negative values, pushes its content beyond the top edge, increasing available space, similarly to negative HTML margins.</para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/padding.html\">Learn more</a>\n        /// </summary>\n        public static IContainer PaddingTop(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Padding(top: value);\n        }\n        \n        /// <summary>\n        /// <para>For positive values, adds empty space below its content.</para>\n        /// <para>For negative values, pushes its content beyond the bottom edge, increasing available space, similarly to negative HTML margins.</para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/padding.html\">Learn more</a>\n        /// </summary>\n        public static IContainer PaddingBottom(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Padding(bottom: value);\n        }\n        \n        /// <summary>\n        /// <para>For positive values, adds empty space to the left of its content.</para>\n        /// <para>For negative values, pushes its content beyond the left edge, increasing available space, similarly to negative HTML margins.</para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/padding.html\">Learn more</a>\n        /// </summary>\n        public static IContainer PaddingLeft(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Padding(left: value);\n        }\n        \n        /// <summary>\n        /// <para>For positive values, adds empty space to the right of its content.</para>\n        /// <para>For negative values, pushes its content beyond the right edge, increasing available space, similarly to negative HTML margins.</para>\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/padding.html\">Learn more</a>\n        /// </summary>\n        public static IContainer PaddingRight(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Padding(right: value);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/PageExtensions.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class PageDescriptor\n    {\n        internal Page Page { get; } = new Page();\n\n        internal PageDescriptor()\n        {\n            \n        }\n        \n        #region Size\n        \n        /// <summary>\n        /// Configures the dimensions of every page within the set.\n        /// </summary>\n        public void Size(float width, float height, Unit unit = Unit.Point)\n        {\n            var pageSize = new PageSize(width, height, unit);\n            \n            MinSize(pageSize);\n            MaxSize(pageSize);\n        }\n        \n        /// <summary>\n        /// Configures the dimensions of every page within the set.\n        /// </summary>\n        public void Size(PageSize pageSize)\n        {\n            MinSize(pageSize);\n            MaxSize(pageSize);\n        }\n        \n        /// <summary>\n        /// Enables the continuous page size mode, allowing the page's height to adjust according to content while retaining a constant specified <paramref name=\"width\" />.\n        /// </summary>\n        /// <example>\n        /// This configuration is suitable for producing PDFs intended for printing on the paper roll.\n        /// </example>\n        public void ContinuousSize(float width, Unit unit = Unit.Point)\n        {\n            MinSize(new PageSize(width.ToPoints(unit), 0));\n            MaxSize(new PageSize(width.ToPoints(unit), Infrastructure.Size.Max.Height));\n        }\n\n        /// <summary>\n        /// Enables the flexible page size mode, where the output page's dimensions can vary based on its content.\n        /// Specifies the smallest possible page size.\n        /// </summary>\n        /// <remarks>\n        /// Note that with this setting, individual pages within the document may have different sizes.\n        /// </remarks>\n        public void MinSize(PageSize pageSize)\n        {\n            Page.MinSize = pageSize;\n        }\n        \n        /// <summary>\n        /// Enables the flexible page size mode, where the output page's dimensions can vary based on its content.\n        /// Specifies the largest possible page size.\n        /// </summary>\n        /// <remarks>\n        /// Note that with this setting, individual pages within the document may have different sizes.\n        /// </remarks>\n        public void MaxSize(PageSize pageSize)\n        {\n            Page.MaxSize = pageSize;\n        }\n        \n        #endregion\n        \n        #region Margin\n\n        /// <summary>\n        /// Adds empty space to the left of the primary layer (header + content + footer).\n        /// </summary>\n        public void MarginLeft(float value, Unit unit = Unit.Point)\n        {\n            Page.MarginLeft = value.ToPoints(unit);\n        }\n        \n        /// <summary>\n        /// Adds empty space to the right of the primary layer (header + content + footer).\n        /// </summary>\n        public void MarginRight(float value, Unit unit = Unit.Point)\n        {\n            Page.MarginRight = value.ToPoints(unit);\n        }\n        \n        /// <summary>\n        /// Adds empty space above the primary layer (header + content + footer).\n        /// </summary>\n        public void MarginTop(float value, Unit unit = Unit.Point)\n        {\n            Page.MarginTop = value.ToPoints(unit);\n        }\n        \n        /// <summary>\n        /// Adds empty space below the primary layer (header + content + footer).\n        /// </summary>\n        public void MarginBottom(float value, Unit unit = Unit.Point)\n        {\n            Page.MarginBottom = value.ToPoints(unit);\n        }\n        \n        /// <summary>\n        /// Adds empty space vertically (top and bottom) around the primary layer (header + content + footer).\n        /// </summary>\n        public void MarginVertical(float value, Unit unit = Unit.Point)\n        {\n            MarginTop(value, unit);\n            MarginBottom(value, unit);\n        }\n        \n        /// <summary>\n        /// Adds empty space horizontally (left and right) around the primary layer (header + content + footer).\n        /// </summary>\n        public void MarginHorizontal(float value, Unit unit = Unit.Point)\n        {\n            MarginLeft(value, unit);\n            MarginRight(value, unit);\n        }\n        \n        /// <summary>\n        /// Adds empty space around the primary layer (header + content + footer).\n        /// </summary>\n        public void Margin(float value, Unit unit = Unit.Point)\n        {\n            MarginVertical(value, unit);\n            MarginHorizontal(value, unit);\n        }\n        \n        #endregion\n        \n        #region Properties\n\n        /// <summary>\n        /// Applies a default text style to all <see cref=\"TextExtensions.Text\">Text</see> elements within the page set.\n        /// </summary>\n        /// <remarks>\n        /// Use this method to achieve consistent text styling across entire document.\n        /// </remarks>\n        /// <param name=\"handler\">A delegate to adjust the global text style attributes.</param>\n        public void DefaultTextStyle(TextStyle textStyle)\n        {\n            Page.DefaultTextStyle = textStyle;\n        }\n        \n        /// <summary>\n        /// Applies a default text style to all <see cref=\"MediaTypeNames.Text\">Text</see> elements within the page set.\n        /// </summary>\n        /// <remarks>\n        /// Use this method to achieve consistent text styling across entire document.\n        /// </remarks>\n        /// <param name=\"handler\">A handler to adjust the global text style attributes.</param>\n        public void DefaultTextStyle(Func<TextStyle, TextStyle> handler)\n        {\n            DefaultTextStyle(handler(TextStyle.Default));\n        }\n        \n        /// <summary>\n        /// Applies a left-to-right (LTR) content direction to all elements within the page set.\n        /// <a href=\"https://www.questpdf.com/api-reference/page/settings.html#content-direction\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"contentDirection.ltr.remarks\"]/*' />\n        public void ContentFromLeftToRight()\n        {\n            Page.ContentDirection = ContentDirection.LeftToRight;\n        }\n        \n        /// <summary>\n        /// Applies a right-to-left (RTL) content direction to all elements within the page set.\n        /// <a href=\"https://www.questpdf.com/api-reference/page/settings.html#content-direction\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"contentDirection.rtl.remarks\"]/*' />\n        public void ContentFromRightToLeft()\n        {\n            Page.ContentDirection = ContentDirection.RightToLeft;\n        }\n        \n        /// <summary>\n        /// Sets a background color of the page, which is white by default.\n        /// </summary>\n        /// <remarks>\n        /// When working with file formats that support the alpha channel, it is possible to set the color to <see cref=\"Colors.Transparent\" /> if necessary.\n        /// </remarks>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public void PageColor(Color color)\n        {\n            Page.BackgroundColor = color;\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the PageColor method.\")]\n        [ExcludeFromCodeCoverage]\n        public void Background(Color color)\n        {\n            PageColor(color);\n        }\n        \n        #endregion\n        \n        #region Slots\n        \n        /// <summary>\n        /// Represents a layer drawn behind the primary layer (header + content + footer), serving as a background.\n        /// </summary>\n        /// <remarks>\n        /// Unaffected by the Margin configuration, it always occupies entire page.\n        /// </remarks>\n        public IContainer Background()\n        {\n            if (Page.Background is not Empty)\n                throw new DocumentComposeException(\"The 'Page.Background' layer has already been defined. Please call this method only once.\");\n            \n            var container = new Container();\n            Page.Background = container;\n            return container;\n        }\n        \n        /// <summary>\n        /// Represents a layer drawn in front of the primary layer (header + content + footer), serving as a watermark.\n        /// </summary>\n        /// <remarks>\n        /// Unaffected by the Margin configuration, it always occupies entire page.\n        /// </remarks>\n        public IContainer Foreground()\n        {\n            if (Page.Foreground is not Empty)\n                throw new DocumentComposeException(\"The 'Page.Foreground' layer has already been defined. Please call this method only once.\");\n            \n            var container = new Container();\n            Page.Foreground = container;\n            return container;\n        }\n        \n        /// <summary>\n        /// Represents the segment at the very top of the page, just above the main content.\n        /// </summary>\n        /// <remarks>\n        /// This container does not support paging capability. It's expected to be fully displayed on every page.\n        /// </remarks>\n        public IContainer Header()\n        {\n            if (Page.Header is not Empty)\n                throw new DocumentComposeException(\"The 'Page.Header' layer has already been defined. Please call this method only once.\");\n            \n            var container = new Container();\n            Page.Header = container;\n            return container;\n        }\n        \n        /// <summary>\n        /// Represents the primary content, located in-between the header and footer.\n        /// </summary>\n        /// <remarks>\n        /// This container does support paging capability and determines the final lenght of the document.\n        /// </remarks>\n        public IContainer Content()\n        {\n            if (Page.Content is not Empty)\n                throw new DocumentComposeException(\"The 'Page.Content' layer has already been defined. Please call this method only once.\");\n            \n            var container = new Container();\n            Page.Content = container;\n            return container;\n        }\n        \n        /// <summary>\n        /// Represents the section at the very bottom of the page, just below the main content.\n        /// </summary>\n        /// <remarks>\n        /// This container does not support paging capability. It's expected to be fully displayed on every page.\n        /// </remarks>\n        public IContainer Footer()\n        {\n            if (Page.Footer is not Empty)\n                throw new DocumentComposeException(\"The 'Page.Footer' layer has already been defined. Please call this method only once.\");\n            \n            var container = new Container();\n            Page.Footer = container;\n            return container;\n        }\n        \n        #endregion\n    }\n    \n    public static class PageExtensions\n    {\n        /// <summary>\n        /// Creates a new page set with consistent attributes, such as margin, color, and watermark.\n        /// The length of each set depends on its content.\n        /// </summary>\n        /// <remarks>\n        /// By leveraging multiple page sets, you can produce documents containing pages of distinct sizes and characteristics.\n        /// </remarks>\n        /// <param name=\"handler\">Delegate to define page content (layout and visual elements).</param>\n        /// <returns>Continuation of the Document API chain, permitting the definition of other page sets.</returns>\n        public static IDocumentContainer Page(this IDocumentContainer document, Action<PageDescriptor> handler)\n        {\n            var descriptor = new PageDescriptor();\n            handler(descriptor);\n            \n            (document as DocumentContainer).Pages.Add(descriptor.Page);\n            \n            return document;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/RotateExtensions.cs",
    "content": "﻿using QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class RotateExtensions\n    {\n        private static IContainer SimpleRotate(this IContainer element, int turnDirection)\n        {\n            var scale = element as SimpleRotate ?? new SimpleRotate();\n            scale.TurnCount += turnDirection;\n            return element.Element(scale);\n        }\n        \n        /// <summary>\n        /// Rotates its content 90 degrees counterclockwise.\n        /// <a href=\"https://www.questpdf.com/api-reference/rotate.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// Note: Rotation can alter certain attributes; for example, 'width' might effectively become 'height'.\n        /// </remarks>\n        public static IContainer RotateLeft(this IContainer element)\n        {\n            return element.SimpleRotate(-1);\n        }\n        \n        /// <summary>\n        /// Rotates its content 90 degrees clockwise.\n        /// <a href=\"https://www.questpdf.com/api-reference/rotate.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// Note: Rotation can alter certain attributes; for example, 'width' might effectively become 'height'.\n        /// </remarks>\n        public static IContainer RotateRight(this IContainer element)\n        {\n            return element.SimpleRotate(1);\n        }\n        \n        /// <summary>\n        /// Rotates its content clockwise by a given angle.\n        /// <a href=\"https://www.questpdf.com/api-reference/rotate.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"angle\">Rotation angle in degrees. A value of 360 degrees represents a full rotation.</param>\n        public static IContainer Rotate(this IContainer element, float angle)\n        {\n            var scale = element as Rotate ?? new Rotate();\n            scale.Angle += angle;\n            return element.Element(scale);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/RowExtensions.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class RowDescriptor\n    {\n        internal Row Row { get; } = new();\n\n        internal RowDescriptor()\n        {\n            \n        }\n        \n        /// <summary>\n        /// Adjusts horizontal spacing between items.\n        /// </summary>\n        public void Spacing(float spacing, Unit unit = Unit.Point)\n        {\n            if (spacing < 0)\n                throw new ArgumentOutOfRangeException(nameof(spacing), \"The row spacing cannot be negative.\");\n            \n            Row.Spacing = spacing.ToPoints(unit);\n        }\n\n        private IContainer Item(RowItemType type, float size = 0)\n        {\n            var item = new RowItem\n            {\n                Type = type,\n                Size = size\n            };\n            \n            Row.Items.Add(item);\n            return item;\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.2. Please use the RelativeItem method.\")]\n        [ExcludeFromCodeCoverage]\n        public IContainer RelativeColumn(float size = 1)\n        {\n            return Item(RowItemType.Relative, size);\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.2. Please use the ConstantItem method.\")]\n        [ExcludeFromCodeCoverage]\n        public IContainer ConstantColumn(float size)\n        {\n            return Item(RowItemType.Constant, size);\n        }\n\n        /// <summary>\n        /// Adds a new item to the row element. This item occupies space proportionally to other relative items.\n        /// </summary>\n        /// <example>\n        /// For a row element with a width of 100 points that has three items (a relative item of size 1, a relative item of size 5, and a constant item of size 10 points),\n        /// the items will occupy sizes of 15 points, 75 points, and 10 points respectively.\n        /// </example>\n        /// <returns>The container of the newly added item.</returns>\n        public IContainer RelativeItem(float size = 1)\n        {\n            if (size <= 0)\n                throw new ArgumentOutOfRangeException(nameof(size), \"The relative item size must be greater than zero.\");\n            \n            return Item(RowItemType.Relative, size);\n        }\n        \n        /// <summary>\n        /// Adds a new item to the row element with a specified constant size.\n        /// </summary>\n        /// <returns>The container of the newly created item.</returns>\n        public IContainer ConstantItem(float size, Unit unit = Unit.Point)\n        {\n            if (size < 0)\n                throw new ArgumentOutOfRangeException(nameof(size), \"The constant item size cannot be negative.\");\n            \n            return Item(RowItemType.Constant, size.ToPoints(unit));\n        }\n\n        /// <summary>\n        /// Adds a new item to the row element. The size of this item adjusts based on its content.\n        /// </summary>\n        /// <remarks>\n        /// <para>The AutoItem requests as much horizontal space as its content requires.</para>\n        /// <para>It doesn't adjust its size based on other items and may frequently result in a <see cref=\"DocumentLayoutException\" />.</para>\n        /// <para>It's recommended to use this API in conjunction with the <see cref=\"ConstrainedExtensions.MaxWidth\">MaxWidth</see> element.</para>\n        /// </remarks>\n        /// <returns>The container of the newly created item.</returns>\n        public IContainer AutoItem()\n        {\n            return Item(RowItemType.Auto);\n        }\n    }\n    \n    public static class RowExtensions\n    {\n        /// <summary>\n        /// Draws a collection of elements horizontally.\n        /// Depending on the content direction mode, elements will be drawn from left to right, or from right to left.\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/row.html\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// <para>Supports paging.</para>\n        /// <para>Depending on its content, the Row element may repeatedly draw certain items across multiple pages. Use the <see cref=\"ElementExtensions.ShowOnce\">ShowOnce</see> element to modify this behavior if it's not desired.</para>\n        /// </remarks>\n        /// <param name=\"handler\">The action to configure the row's content.</param>\n        public static void Row(this IContainer element, Action<RowDescriptor> handler)\n        {\n            var descriptor = new RowDescriptor();\n            handler(descriptor);\n            element.Element(descriptor.Row);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/ScaleExtensions.cs",
    "content": "﻿using System;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class ScaleExtensions\n    {\n        private static IContainer ScaleValue(this IContainer element, float x = 1, float y = 1)\n        {\n            var scale = element as Scale ?? new Scale();\n\n            scale.ScaleX *= x;\n            scale.ScaleY *= y;\n            \n            return element.Element(scale);\n        }\n        \n        /// <summary>\n        /// Scales its inner content proportionally.\n        /// <a href=\"https://www.questpdf.com/api-reference/scale.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"scale.remarks\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"scale.factorParam\"]/*' />\n        public static IContainer Scale(this IContainer element, float factor)\n        {\n            if (factor == 0)\n                throw new ArgumentException(\"Vertical scale factor cannot be zero.\", nameof(factor));\n            \n            return element.ScaleValue(x: factor, y: factor);\n        }\n        \n        /// <summary>\n        /// Scales the available horizontal space (along the X axis), causing content to appear expanded or squished, rather than simply larger or smaller.\n        /// <a href=\"https://www.questpdf.com/api-reference/scale.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"scale.remarks\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"scale.factorParam\"]/*' />\n        public static IContainer ScaleHorizontal(this IContainer element, float factor)\n        {\n            if (factor == 0)\n                throw new ArgumentException(\"Vertical scale factor cannot be zero.\", nameof(factor));\n            \n            return element.ScaleValue(x: factor);\n        }\n        \n        /// <summary>\n        /// Scales the available vertical space (along the Y axis), causing content to appear expanded or squished, rather than simply larger or smaller.\n        /// <a href=\"https://www.questpdf.com/api-reference/scale.html\">Learn more</a> \n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"scale.remarks\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"scale.factorParam\"]/*' />\n        public static IContainer ScaleVertical(this IContainer element, float factor)\n        {\n            if (factor == 0)\n                throw new ArgumentException(\"Vertical scale factor cannot be zero.\", nameof(factor));\n            \n            return element.ScaleValue(y: factor);\n        }\n        \n        /// <summary>\n        /// Flips its content to create a mirror image along the Y axis, swapping elements from left to right.\n        /// <a href=\"https://www.questpdf.com/api-reference/flip.html\">Learn more</a>\n        /// </summary>\n        /// <example>\n        /// Elements on the left will appear on the right.\n        /// </example>\n        public static IContainer FlipHorizontal(this IContainer element)\n        {\n            return element.ScaleValue(x: -1);\n        }\n        \n        /// <summary>\n        /// Flips its content to create a mirror image along the X axis, moving elements from the top to the bottom.\n        /// <a href=\"https://www.questpdf.com/api-reference/flip.html\">Learn more</a>\n        /// </summary>\n        /// <example>\n        /// Elements at the top will be positioned at the bottom.\n        /// </example>\n        public static IContainer FlipVertical(this IContainer element)\n        {\n            return element.ScaleValue(y: -1);\n        }\n        \n        /// <summary>\n        /// Creates a mirror image of its content across both axes.\n        /// <a href=\"https://www.questpdf.com/api-reference/flip.html\">Learn more</a>\n        /// </summary>\n        /// <example>\n        /// Elements originally in the top-left corner will be positioned in the bottom-right corner.\n        /// </example>\n        public static IContainer FlipOver(this IContainer element)\n        {\n            return element.ScaleValue(x: -1, y: -1);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/SemanticExtensions.cs",
    "content": "using System;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Fluent;\n\npublic static class SemanticExtensions\n{\n    internal static IContainer Artifact(this IContainer container, int nodeId)\n    {\n        return container.Element(new Elements.ArtifactTag\n        {\n            Id = nodeId\n        });\n    }\n    \n    /// <summary>\n    /// Excludes the container content from the semantic tree.\n    /// Use for decorative elements, layout artifacts, or other non-structural content that shouldn't be part of the document's logical structure.\n    /// </summary>\n    public static IContainer SemanticIgnore(this IContainer container)\n    {\n        return container.Artifact(SkSemanticNodeSpecialId.OtherArtifact);\n    }\n    \n    internal static IContainer SemanticTag(this IContainer container, string type, string? alternativeText = null, string? language = null)\n    {\n        return container.Element(new Elements.SemanticTag\n        {\n            TagType = type, \n            Alt = alternativeText,\n            Lang = language\n        });\n    }\n\n    /// <summary>\n    /// Marks a self-contained body of text that forms a single narrative or exposition,\n    /// such as a blog post, news story, or forum post.\n    /// As a best practice, articles should not be nested within each other.\n    /// </summary>\n    public static IContainer SemanticArticle(this IContainer container)\n    {\n        return container.SemanticTag(\"Art\");\n    }\n    \n    /// <summary>\n    /// Applies a 'Section' tag, grouping a set of related content.\n    /// A section typically includes a heading (e.g., SemanticHeader2) and its corresponding content.\n    /// Sections can be nested to create a hierarchical document structure.\n    /// </summary>\n    public static IContainer SemanticSection(this IContainer container)\n    {\n        return container.SemanticTag(\"Sect\");\n    }\n    \n    /// <summary>\n    /// Marks a generic block-level container for grouping elements.\n    /// It's often used when a more specific semantic tag (like 'Article' or 'Section') doesn't apply,\n    /// serving as a general-purpose 'div', similar to its HTML counterpart.\n    /// </summary>\n    public static IContainer SemanticDivision(this IContainer container)\n    {\n        return container.SemanticTag(\"Div\");\n    }\n    \n    /// <summary>\n    /// Designates a block of text that is a quotation, typically consisting of one or more paragraphs.\n    /// This is for block-level quotes, as opposed to <see cref=\"SemanticQuote\"/> which is for inline text.\n    /// </summary>\n    public static IContainer SemanticBlockQuotation(this IContainer container)\n    {\n        return container.SemanticTag(\"BlockQuote\");\n    }\n    \n    /// <summary>\n    /// Identifies a brief portion of text that serves as a caption or description\n    /// for a table, figure, or image. It should be placed near the element it describes.\n    /// </summary>\n    public static IContainer SemanticCaption(this IContainer container)\n    {\n        return container.SemanticTag(\"Caption\");\n    }\n    \n    /// <summary>\n    /// Marks a section of the document as an index.\n    /// This container typically holds a sequence of entries and references.\n    /// </summary>\n    public static IContainer SemanticIndex(this IContainer container)\n    {\n        return container.SemanticTag(\"Index\");\n    }\n    \n    /// <summary>\n    /// Applies a language attribute to a container, specifying the natural language (e.g., 'en-US', 'es-ES') of its content.\n    /// This is crucial for accessibility, enabling screen readers to use the correct pronunciation.\n    /// </summary>\n    /// <param name=\"language\">The ISO 639 language code (e.g., 'en-US' or 'fr-FR') for the content.</param>\n    public static IContainer SemanticLanguage(this IContainer container, string language)\n    {\n        return container.SemanticTag(\"NonStruct\", language: language);\n    }\n    \n    #region Table of Contents\n    \n    /// <summary>\n    /// Marks a container as a Table of Contents (TOC).\n    /// <para>\n    /// A TOC should be composed of <see cref=\"SemanticTableOfContentsItem\"/> elements.\n    /// TOCs can be nested to represent a hierarchical document structure.\n    /// </para>\n    /// <para>This tag can also be used for lists of figures, lists of tables, or bibliographies.</para>\n    /// </summary>\n    public static IContainer SemanticTableOfContents(this IContainer container)\n    {\n        return container.SemanticTag(\"TOC\");\n    }\n    \n    /// <summary>\n    /// Marks an individual item within a <see cref=\"SemanticTableOfContents\"/>.\n    /// This typically represents a single entry in the list.\n    /// </summary>\n    public static IContainer SemanticTableOfContentsItem(this IContainer container)\n    {\n        return container.SemanticTag(\"TOCI\");\n    }\n    \n    #endregion\n    \n    #region Headers\n    \n    private static IContainer SemanticHeader(this IContainer container, int level)\n    {\n        if (level < 1 || level > 6)\n            throw new ArgumentOutOfRangeException(nameof(level), \"Header level must be between 1 and 6.\");\n\n        return container.SemanticTag($\"H{level}\");\n    }\n    \n    /// <summary>\n    /// Marks the content as a level 1 heading (H1), the highest level in the document hierarchy.\n    /// Headings are crucial for navigation and outlining the document's structure.\n    /// </summary>\n    public static IContainer SemanticHeader1(this IContainer container)\n    {\n        return container.SemanticHeader(1);\n    }\n    \n    /// <summary>\n    /// Marks the content as a level 2 heading (H2).\n    /// </summary>\n    public static IContainer SemanticHeader2(this IContainer container)\n    {\n        return container.SemanticHeader(2);\n    }\n    \n    /// <summary>\n    /// Marks the content as a level 3 heading (H3).\n    /// </summary>\n    public static IContainer SemanticHeader3(this IContainer container)\n    {\n        return container.SemanticHeader(3);\n    }\n    \n    /// <summary>\n    /// Marks the content as a level 4 heading (H4).\n    /// </summary>\n    public static IContainer SemanticHeader4(this IContainer container)\n    {\n        return container.SemanticHeader(4);\n    }\n    \n    /// <summary>\n    /// Marks the content as a level 5 heading (H5).\n    /// </summary>\n    public static IContainer SemanticHeader5(this IContainer container)\n    {\n        return container.SemanticHeader(5);\n    }\n    \n    /// <summary>\n    /// Marks the content as a level 6 heading (H6), the lowest level in the document hierarchy.\n    /// </summary>\n    public static IContainer SemanticHeader6(this IContainer container)\n    {\n        return container.SemanticHeader(6);\n    }\n    \n    #endregion\n    \n    /// <summary>\n    /// Marks a container as a paragraph.\n    /// This is one of the most common block-level tags for organizing text content.\n    /// </summary>\n    public static IContainer SemanticParagraph(this IContainer container)\n    {\n        return container.SemanticTag(\"P\");\n    }\n    \n    #region Lists\n    \n    /// <summary>\n    /// Marks a container as a list.\n    /// Its direct children should be one or more <see cref=\"SemanticListItem\"/> elements.\n    /// A <see cref=\"SemanticCaption\"/> can also be included as an optional first child.\n    /// </summary>\n    public static IContainer SemanticList(this IContainer container)\n    {\n        return container.SemanticTag(\"L\");\n    }\n\n    /// <summary>\n    /// Marks an individual item within a <see cref=\"SemanticList\"/>.\n    /// Its children should typically be a <see cref=\"SemanticListLabel\"/> (e.g., the bullet or number) and/or a <see cref=\"SemanticListItemBody\"/> (the content).\n    /// </summary>\n    public static IContainer SemanticListItem(this IContainer container)\n    {\n        return container.SemanticTag(\"LI\");\n    }\n    \n    /// <summary>\n    /// Marks the label of a list item.\n    /// This container holds the bullet, number (e.g., '1.'), or term (in a definition list) that identifies the list item.\n    /// </summary>\n    public static IContainer SemanticListLabel(this IContainer container)\n    {\n        return container.SemanticTag(\"Lbl\");\n    }\n    \n    /// <summary>\n    /// Marks the body or descriptive content of a <see cref=\"SemanticListItem\"/>.\n    /// This contains the main text or content associated with the list item's label.\n    /// </summary>\n    public static IContainer SemanticListItemBody(this IContainer container)\n    {\n        return container.SemanticTag(\"LBody\");\n    }\n    \n    #endregion\n    \n    #region Table\n    \n    /// <summary>\n    /// Marks a container as a table.\n    /// The library automatically automatically tags headers, rows, cells, etc.\n    /// </summary>\n    public static IContainer SemanticTable(this IContainer container)\n    {\n        return container.SemanticTag(\"Table\");\n    }\n    \n    #endregion\n    \n    #region Inline Elements\n    \n    /// <summary>\n    /// Marks a generic inline portion of text (Span).\n    /// This is useful for grouping inline elements or applying styling, similar to an HTML &lt;span&gt;.\n    /// </summary>\n    /// <param name=\"alternativeText\">Optional alternative text, often used to provide an expansion for an abbreviation or other supplementary information.</param>\n    public static IContainer SemanticSpan(this IContainer container, string? alternativeText = null)\n    {\n        return container.SemanticTag(\"Span\", alternativeText);\n    }\n    \n    /// <summary>\n    /// Marks an inline portion of text as a quote.\n    /// This differs from <see cref=\"SemanticBlockQuotation\"/>, which is intended for block-level content (one or more paragraphs).\n    /// </summary>\n    public static IContainer SemanticQuote(this IContainer container)\n    {\n        return container.SemanticTag(\"Quote\");\n    }\n\n    /// <summary>\n    /// Marks a fragment of text as computer code.\n    /// </summary>\n    public static IContainer SemanticCode(this IContainer container)\n    {\n        return container.SemanticTag(\"Code\");\n    }\n\n    /// <summary>\n    /// Marks the content as a hyperlink (Link).\n    /// </summary>\n    /// <param name=\"alternativeText\">Alternative text describing the link's purpose or destination. This is essential for screen readers.</param>\n    public static IContainer SemanticLink(this IContainer container, string alternativeText)\n    {\n        return container.SemanticTag(\"Link\", alternativeText: alternativeText);\n    }\n    \n    #endregion\n    \n    #region Illustration Elements\n    \n    /// <summary>\n    /// Marks a container as a figure, which is an item of graphical content like a chart, diagram, or photograph.\n    /// </summary>\n    /// <param name=\"alternativeText\">A textual description of the figure, read by screen readers. This is essential for accessibility.</param>\n    public static IContainer SemanticFigure(this IContainer container, string alternativeText)\n    {\n        return container.SemanticTag(\"Figure\", alternativeText: alternativeText);\n    }\n    \n    /// <summary>\n    /// An alias for <see cref=\"SemanticFigure\"/>. Marks the content as an image.\n    /// </summary>\n    /// <param name=\"alternativeText\">A textual description of the image, read by screen readers. This is essential for accessibility.</param>\n    public static IContainer SemanticImage(this IContainer container, string alternativeText)\n    {\n        return container.SemanticFigure(alternativeText);\n    }\n    \n    /// <summary>\n    /// Marks the content as a mathematical formula.\n    /// From a structural and accessibility standpoint, it is treated similarly to a figure.\n    /// </summary>\n    public static IContainer SemanticFormula(this IContainer container, string alternativeText)\n    {\n        return container.SemanticTag(\"Formula\", alternativeText: alternativeText);\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/ShrinkExtensions.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class ShrinkExtensions\n    {\n        private static IContainer Shrink(this IContainer element, bool? vertical = null, bool? horizontal = null)\n        {\n            var shrink = element as Shrink ?? new Shrink();\n\n            if (vertical.HasValue)\n                shrink.Vertical = vertical.Value;\n\n            if (horizontal.HasValue)\n                shrink.Horizontal = horizontal.Value;\n\n            return element.Element(shrink);\n        }\n\n        /// <summary>\n        /// Renders its content in the most compact size achievable. \n        /// Ideal for situations where the parent element provides more space than necessary.\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/shrink.html\">Learn more</a>\n        /// </summary>\n        public static IContainer Shrink(this IContainer element)\n        {\n            return element.Shrink(vertical: true, horizontal: true);\n        }\n\n        /// <summary>\n        /// Minimizes content height to the minimum, optimizing vertical space.\n        /// Ideal for situations where the parent element provides more space than necessary.\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/shrink.html\">Learn more</a>\n        /// </summary>\n        public static IContainer ShrinkVertical(this IContainer element)\n        {\n            return element.Shrink(vertical: true);\n        }\n\n        /// <summary>\n        /// Minimizes content width to the minimum, optimizing horizontal space.\n        /// Ideal for situations where the parent element provides more space than necessary.\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/shrink.html\">Learn more</a>\n        /// </summary>\n        public static IContainer ShrinkHorizontal(this IContainer element)\n        {\n            return element.Shrink(horizontal: true);\n        }\n\n        #region Obsolete\n\n        [Obsolete(\"This element has been renamed since version 2022.1. Please use the Shrink method.\")]\n        [ExcludeFromCodeCoverage]\n        public static IContainer Box(this IContainer element)\n        {\n            return element.Shrink();\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2023.11. Please use the Shrink method.\")]\n        [ExcludeFromCodeCoverage]\n        public static IContainer MinimalBox(this IContainer element)\n        {\n            return element.Shrink();\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/StyledBoxExtensions.cs",
    "content": "using System;\nusing QuestPDF.Elements;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class StyledBoxExtensions\n    {\n        /// <summary>\n        /// Sets a uniform border around the container with the specified thickness and color.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public static IContainer Border(this IContainer element, float all, Color color)\n        {\n            return element.Border(left: all, top: all, right: all, bottom: all).BorderColor(color);\n        }\n        \n        /// <summary>\n        /// Sets a solid background color behind its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/background.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public static IContainer Background(this IContainer element, Color color)\n        {\n            var styledBox = element as StyledBox ?? new StyledBox();\n            styledBox.BackgroundColor = color;\n            \n            return element.Element(styledBox);\n        }\n\n        /// <summary>\n        /// Applies a linear gradient background to the container with the specified angle and colors.\n        /// </summary>\n        /// <param name=\"angle\">The angle in degrees of the gradient direction.</param>\n        /// <param name=\"colors\">An array of <see cref=\"Color\"/> representing the gradient colors.</param>\n        public static IContainer BackgroundLinearGradient(this IContainer element, float angle, Color[] colors)\n        {\n            if (colors == null || colors.Length == 0)\n                throw new ArgumentException(\"The background linear-gradient colors cannot be empty.\", nameof(colors));\n            \n            var border = element as StyledBox ?? new StyledBox();\n            border.BackgroundGradientAngle = angle;\n            border.BackgroundGradientColors = colors;\n            return element.Element(border);\n        }\n        \n        #region Thickness\n        \n        private static IContainer Border(this IContainer element, float? top = null, float? bottom = null, float? left = null, float? right = null)\n        {\n            var styledBox = element as StyledBox ?? new StyledBox();\n\n            if (top < 0)\n                throw new ArgumentOutOfRangeException(nameof(top), \"The top border cannot be negative.\");\n            \n            if (bottom < 0)\n                throw new ArgumentOutOfRangeException(nameof(bottom), \"The bottom border cannot be negative.\");\n            \n            if (left < 0)\n                throw new ArgumentOutOfRangeException(nameof(left), \"The left border cannot be negative.\");\n            \n            if (right < 0)\n                throw new ArgumentOutOfRangeException(nameof(right), \"The right border cannot be negative.\");\n\n            if (styledBox.BorderColor == Colors.Transparent.Hex)\n                styledBox.BorderColor = Colors.Black;\n            \n            if (top.HasValue)\n                styledBox.BorderTop = top.Value;\n            \n            if (bottom.HasValue)\n                styledBox.BorderBottom = bottom.Value;\n            \n            if (left.HasValue)\n                styledBox.BorderLeft = left.Value;\n            \n            if (right.HasValue)\n                styledBox.BorderRight = right.Value;\n\n            return element.Element(styledBox);\n        }\n        \n        /// <summary>\n        /// Sets a uniform border (all edges) for its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/border.html\">Learn more</a>\n        /// </summary>\n        public static IContainer Border(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Border(top: value, bottom: value, left: value, right: value);\n        }\n        \n        /// <summary>\n        /// Sets a vertical border (left and right) for its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/border.html\">Learn more</a>\n        /// </summary>\n        public static IContainer BorderVertical(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Border(left: value, right: value);\n        }\n        \n        /// <summary>\n        /// Sets a horizontal border (top and bottom) for its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/border.html\">Learn more</a>\n        /// </summary>\n        public static IContainer BorderHorizontal(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Border(top: value, bottom: value);\n        }\n        \n        /// <summary>\n        /// Sets a border on the left side of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/border.html\">Learn more</a>\n        /// </summary>\n        public static IContainer BorderLeft(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Border(left: value);\n        }\n        \n        /// <summary>\n        /// Sets a border on the right side of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/border.html\">Learn more</a>\n        /// </summary>\n        public static IContainer BorderRight(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Border(right: value);\n        }\n        \n        /// <summary>\n        /// Sets a border on the top side of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/border.html\">Learn more</a>\n        /// </summary>\n        public static IContainer BorderTop(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Border(top: value);\n        }\n        \n        /// <summary>\n        /// Sets a border on the bottom side of its content.\n        /// <a href=\"https://www.questpdf.com/api-reference/border.html\">Learn more</a>\n        /// </summary>        \n        public static IContainer BorderBottom(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Border(bottom: value);\n        }\n        \n        #endregion\n        \n        #region Corner Radius\n        \n        private static IContainer CornerRadius(this IContainer element, float? topLeft = null, float? topRight = null, float? bottomRight = null, float? bottomLeft = null)\n        {\n            var styledBox = element as StyledBox ?? new StyledBox();\n            \n            if (topLeft < 0)\n                throw new ArgumentOutOfRangeException(nameof(topLeft), \"The top-left corner radius cannot be negative.\");\n            \n            if (topRight < 0)\n                throw new ArgumentOutOfRangeException(nameof(topRight), \"The top-right corner radius cannot be negative.\");\n            \n            if (bottomRight < 0)\n                throw new ArgumentOutOfRangeException(nameof(bottomRight), \"The bottom-right corner radius cannot be negative.\");\n            \n            if (bottomLeft < 0)\n                throw new ArgumentOutOfRangeException(nameof(bottomLeft), \"The bottom-left corner radius cannot be negative.\");\n            \n            if (topLeft.HasValue)\n                styledBox.BorderRadiusTopLeft = topLeft.Value;\n            \n            if (topRight.HasValue)\n                styledBox.BorderRadiusTopRight = topRight.Value;\n            \n            if (bottomRight.HasValue)\n                styledBox.BorderRadiusBottomRight = bottomRight.Value;\n            \n            if (bottomLeft.HasValue)\n                styledBox.BorderRadiusBottomLeft = bottomLeft.Value;\n            \n            return element.Element(styledBox);\n        }\n\n        /// <summary>\n        /// Applies a uniform corner radius to all corners of the container with the specified value and unit.\n        /// </summary>\n        public static IContainer CornerRadius(this IContainer element, float value = 0, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.CornerRadius(topLeft: value, topRight: value, bottomRight: value, bottomLeft: value);\n        }\n\n        /// <summary>\n        /// Applies a corner radius to the top-left corner of the container with the specified value and unit.\n        /// </summary>\n        public static IContainer CornerRadiusTopLeft(this IContainer element, float value = 0, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.CornerRadius(topLeft: value);\n        }\n        \n        /// <summary>\n        /// Applies a corner radius to the top-right corner of the container with the specified value and unit.\n        /// </summary>\n        public static IContainer CornerRadiusTopRight(this IContainer element, float value = 0, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.CornerRadius(topRight: value);\n        }\n        \n        /// <summary>\n        /// Applies a border radius to the bottom-left corner of the container with the specified value and unit.\n        /// </summary>\n        public static IContainer CornerRadiusBottomLeft(this IContainer element, float value = 0, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.CornerRadius(bottomLeft: value);\n        }\n        \n        /// <summary>\n        /// Applies a corner radius to the bottom-right corner of the container with the specified value and unit.\n        /// </summary>\n        public static IContainer CornerRadiusBottomRight(this IContainer element, float value = 0, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.CornerRadius(bottomRight: value);\n        }\n        \n        #endregion\n        \n        #region Border Style\n        \n        /// <summary>\n        /// Adjusts color of the border element.\n        /// <a href=\"https://www.questpdf.com/api-reference/border.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public static IContainer BorderColor(this IContainer element, Color color)\n        {\n            var border = element as StyledBox ?? new StyledBox();\n            border.BorderColor = color;\n            return element.Element(border);\n        }\n\n        /// <summary>\n        /// Sets a linear gradient for the border with the specified angle and colors.\n        /// </summary>\n        /// <param name=\"angle\">The angle of the gradient in degrees.</param>\n        /// <param name=\"colors\">An array of <see cref=\"Color\"/> objects representing the gradient colors.</param>\n        public static IContainer BorderLinearGradient(this IContainer element, float angle, Color[] colors)\n        {\n            if (colors == null || colors.Length == 0)\n                throw new ArgumentException(\"The border linear-gradient colors cannot be empty.\", nameof(colors));\n            \n            var border = element as StyledBox ?? new StyledBox();\n            border.BorderGradientAngle = angle;\n            border.BorderGradientColors = colors;\n            return element.Element(border);\n        }\n        \n        #endregion\n\n        #region Alignment\n\n        private static IContainer BorderAlignment(this IContainer element, float value)\n        {\n            var border = element as StyledBox ?? new StyledBox();\n            border.BorderAlignment = value;\n            return element.Element(border);\n        }\n\n        /// <summary>\n        /// Aligns the container's border to the outer edge of the element.\n        /// </summary>\n        public static IContainer BorderAlignmentOutside(this IContainer element)\n        {\n            return element.BorderAlignment(1);\n        }\n\n        /// <summary>\n        /// Aligns the border in the middle of the specified container boundaries.\n        /// This option is used by default when no alignment is specified.\n        /// </summary>\n        public static IContainer BorderAlignmentMiddle(this IContainer element)\n        {\n            return element.BorderAlignment(0.5f);\n        }\n\n        /// <summary>\n        /// Aligns the border to the inside of the container.\n        /// </summary>\n        public static IContainer BorderAlignmentInside(this IContainer element)\n        {\n            return element.BorderAlignment(0);\n        }\n\n        #endregion\n        \n        #region Shadow\n\n        /// <summary>\n        /// Applies a shadow to the container using the specified shadow style.\n        /// Shadows can enhance the visual depth and separation of elements in a document.\n        /// </summary>\n        public static IContainer Shadow(this IContainer element, BoxShadowStyle style)\n        {\n            if (style == null)\n                throw new ArgumentNullException(nameof(style), \"The box shadow style cannot be null.\");\n            \n            style.Validate();\n            \n            var styledBox = element as StyledBox ?? new StyledBox();\n            styledBox.Shadow = style;\n            return element.Element(styledBox);\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/SvgExtensions.cs",
    "content": "using System;\nusing System.IO;\nusing QuestPDF.Elements;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing SvgImage = QuestPDF.Infrastructure.SvgImage;\n\nnamespace QuestPDF.Fluent;\n\n/// <summary>\n/// Generates an SVG image based on the given resolution.\n/// </summary>\n/// <param name=\"size\">Desired resolution of the image in pixels.</param>\n/// <returns>An SVG format compatible text.</returns>\npublic delegate string? GenerateDynamicSvgDelegate(Size size);\n\npublic sealed class SvgImageDescriptor\n{\n    private Elements.SvgImage ImageElement { get; }\n    private AspectRatio AspectRatioElement { get; }\n    private float ImageAspectRatio { get; }\n\n    internal SvgImageDescriptor(Elements.SvgImage imageElement, Elements.AspectRatio aspectRatioElement)\n    {\n        ImageElement = imageElement;\n        AspectRatioElement = aspectRatioElement;\n        ImageAspectRatio = imageElement.Image.SkSvgImage.AspectRatio;\n    }\n    \n    /// <summary>\n    /// Scales the image to fill the full width of its container. This is the default behavior.\n    /// </summary>\n    public SvgImageDescriptor FitWidth()\n    {\n        return SetAspectRatio(AspectRatioOption.FitWidth);\n    }\n    \n    /// <summary>\n    /// <para>The image stretches vertically to fit the full available height.</para>\n    /// <para>Often used with height-constraining elements such as: <see cref=\"ConstrainedExtensions.Height\">Height</see>, <see cref=\"ConstrainedExtensions.MaxHeight\">MaxHeight</see>, etc.</para>\n    /// </summary>\n    public SvgImageDescriptor FitHeight()\n    {\n        return SetAspectRatio(AspectRatioOption.FitHeight);\n    }\n    \n    /// <summary>\n    /// Combines the FitWidth and FitHeight settings.\n    /// The image resizes itself to utilize all available space, preserving its aspect ratio.\n    /// It will either fill the width or height based on the container's dimensions.\n    /// </summary>\n    /// <remarks>\n    /// An optimal and safe choice.\n    /// </remarks>\n    public SvgImageDescriptor FitArea()\n    {\n        return SetAspectRatio(AspectRatioOption.FitArea);\n    }\n\n    internal SvgImageDescriptor SetAspectRatio(AspectRatioOption option)\n    {\n        AspectRatioElement.Ratio = ImageAspectRatio;\n        AspectRatioElement.Option = option;\n        return this;\n    }\n}\n\npublic static class SvgExtensions\n{\n    internal static void SvgPath(this IContainer container, string svgPath, Color color)\n    {\n        container.Element(new SvgPath\n        {\n            Path = svgPath,\n            FillColor = color\n        });\n    }\n    \n    /// <summary>\n    /// Draws the SVG image loaded from a text.\n    /// <a href=\"https://www.questpdf.com/api-reference/image/svg.html\">Learn more</a>\n    /// </summary>\n    /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"svg.remarks\"]/*' />\n    /// <param name=\"svg\">\n    /// Either a path to the SVG file or the SVG content itself.\n    /// </param>\n    /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"svg.descriptor\"]/*' />\n    public static SvgImageDescriptor Svg(this IContainer container, string svg)\n    {\n        var isFile = Path.GetExtension(svg).Equals(\".svg\", StringComparison.OrdinalIgnoreCase);\n        \n        var image = isFile ? SvgImage.FromFile(svg) : SvgImage.FromText(svg);\n        image.IsShared = false;\n        return container.Svg(image);\n    }\n    \n    /// <summary>\n    /// Draws the <see cref=\"Infrastructure.SvgImage\" /> object. Allows to optimize the generation process.\n    /// <a href=\"https://www.questpdf.com/api-reference/image/svg.html\">Learn more</a>\n    /// </summary>\n    /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"svg.remarks\"]/*' />\n    /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"svg.descriptor\"]/*' />\n    public static SvgImageDescriptor Svg(this IContainer parent, SvgImage image)\n    {\n        var imageElement = new QuestPDF.Elements.SvgImage\n        {\n            Image = image\n        };\n\n        var aspectRationElement = new AspectRatio\n        {\n            Child = imageElement\n        };\n            \n        parent.Element(aspectRationElement);\n        \n        var bestScalingOption = ImageExtensions.GetBestAspectRatioOptionFromParent(parent);\n        return new SvgImageDescriptor(imageElement, aspectRationElement).SetAspectRatio(bestScalingOption);\n    }\n    \n    /// <summary>\n    /// Renders an SVG image of dynamic size dictated by the document layout constraints.\n    /// </summary>\n    /// <remarks>\n    /// Ideal for integrating with other libraries, e.g. SkiaSharp or ScottPlot.\n    /// </remarks>\n    /// <param name=\"dynamicSvgSource\">\n    /// A delegate that requests an image of desired size.\n    /// </param>\n    public static void Svg(this IContainer element, GenerateDynamicSvgDelegate dynamicSvgSource)\n    {\n        var dynamicImage = new DynamicSvgImage\n        {\n            SvgSource = dynamicSvgSource\n        };\n            \n        element.Element(dynamicImage);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/TableExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Elements.Table;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public sealed class TableColumnsDefinitionDescriptor\n    {\n        internal List<TableColumnDefinition> Columns { get; } = new();\n        \n        internal TableColumnsDefinitionDescriptor()\n        {\n            \n        }\n        \n        /// <summary>\n        /// Defines a column of constant size that occupies the specified horizontal space.\n        /// </summary>\n        /// <returns>The container of the newly created column.</returns>\n        public void ConstantColumn(float width, Unit unit = Unit.Point)\n        {\n            if (width <= 0)\n                throw new ArgumentOutOfRangeException(nameof(width), \"Constant column width must be greater than zero.\");\n            \n            ComplexColumn(constantWidth: width.ToPoints(unit));\n        }\n        \n        /// <summary>\n        /// Defines a column with a relative size that adjusts its width in relation to other relative columns.\n        /// <a href=\"https://www.questpdf.com/api-reference/table/basics.html#columns-definition\">Learn more</a>\n        /// </summary>\n        /// <example>\n        /// For a table 100 points wide with three columns: a relative size of 1, a relative size of 5, and a constant size of 10 points, they will span 15 points, 75 points, and 10 points respectively.\n        /// </example>\n        /// <returns>The container for the newly defined column.</returns>\n        public void RelativeColumn(float width = 1)\n        {\n            if (width <= 0)\n                throw new ArgumentOutOfRangeException(nameof(width), \"Relative column width must be greater than zero.\");\n            \n            ComplexColumn(relativeWidth: width);\n        }\n        \n        private void ComplexColumn(float constantWidth = 0, float relativeWidth = 0)\n        {\n            var columnDefinition = new TableColumnDefinition(constantWidth, relativeWidth);\n            Columns.Add(columnDefinition);\n        }\n    }\n\n    public sealed class TableCellDescriptor\n    {\n        private ICollection<TableCell> Cells { get; }\n\n        internal TableCellDescriptor(ICollection<TableCell> cells)\n        {\n            Cells = cells;\n        }\n        \n        /// <summary>\n        /// Inserts a new item into the table element.\n        /// </summary>\n        /// <returns>The container for the newly inserted cell. Provides options to adjust the cell's position, size, and content.</returns>\n        public ITableCellContainer Cell()\n        {\n            var cell = new TableCell();\n            Cells.Add(cell);\n            return cell;\n        }\n    }\n    \n    public sealed class TableDescriptor\n    {\n        internal bool EnableAutomatedSemanticTagging { get; set; } = false;\n        \n        private Table HeaderTable { get; } = new();\n        private Table ContentTable { get; } = new();\n        private Table FooterTable { get; } = new();\n\n        internal TableDescriptor()\n        {\n            \n        }\n        \n        /// <summary>\n        /// Specifies the order and size of the table columns.\n        /// <a href=\"https://www.questpdf.com/api-reference/table/basics.html#columns-definition\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// This configuration affects both the main content as well as the header and footer sections.\n        /// </remarks>\n        /// <param name=\"handler\">Handler to define columns of the table.</param>\n        public void ColumnsDefinition(Action<TableColumnsDefinitionDescriptor> handler)\n        {\n            if (ContentTable.Columns.Any())\n                throw new DocumentComposeException(\"Table columns have already been defined. Please call the 'Table.ColumnsDefinition' method only once.\");\n            \n            var descriptor = new TableColumnsDefinitionDescriptor();\n            handler(descriptor);\n\n            HeaderTable.Columns = descriptor.Columns;\n            ContentTable.Columns = descriptor.Columns;\n            FooterTable.Columns = descriptor.Columns;\n        }\n        \n        /// <summary>\n        /// Adjusts rendering algorithm to better handle complex table structures, especially those spanning multiple pages. \n        /// This applies a unique rule to the final cells in each column, ensuring they stretch to fill the table's bottom edge.\n        /// Such an approach can enhance your table's visual appeal.\n        /// </summary>\n        public void ExtendLastCellsToTableBottom()\n        {\n            ContentTable.ExtendLastCellsToTableBottom = true;\n        }\n        \n        /// <summary>\n        /// Specifies a table header that appears on each page, positioned above the main content.\n        /// The cell placement and dimensions in this header are distinct from those in the main content.\n        /// <a href=\"https://www.questpdf.com/api-reference/table/header-and-footer.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"handler\">Handler for configuring the header cells.</param>\n        public void Header(Action<TableCellDescriptor> handler)\n        {\n            if (HeaderTable.Cells.Any())\n                throw new DocumentComposeException(\"The 'Table.Header' layer has already been defined. Please call this method only once.\");\n            \n            var descriptor = new TableCellDescriptor(HeaderTable.Cells);\n            handler(descriptor);\n        }\n        \n        /// <summary>\n        /// Specifies a table footer that appears on each page, positioned below the main content.\n        /// The placement and dimensions of cells within this footer are distinct from the main content.\n        /// <a href=\"https://www.questpdf.com/api-reference/table/header-and-footer.html\">Learn more</a>\n        /// </summary>\n        public void Footer(Action<TableCellDescriptor> handler)\n        {\n            if (FooterTable.Cells.Any())\n                throw new DocumentComposeException(\"The 'Table.Footer' layer has already been defined. Please call this method only once.\");\n            \n            var descriptor = new TableCellDescriptor(FooterTable.Cells);\n            handler(descriptor);\n        }\n        \n        /// <summary>\n        /// Inserts a new item into the table element.\n        /// </summary>\n        /// <returns>The container for the newly inserted cell, enabling customization of its position, size, and content.</returns>\n        public ITableCellContainer Cell()\n        {\n            var cell = new TableCell();\n            ContentTable.Cells.Add(cell);\n            return cell;\n        }\n\n        internal IElement CreateElement()\n        {\n            var container = new Container();\n\n            var hasHeader = HeaderTable.Cells.Any();\n            var hasFooter = FooterTable.Cells.Any();\n            \n            ConfigureTable(HeaderTable, Table.TablePartType.Header);\n            ConfigureTable(ContentTable, Table.TablePartType.Body);\n            ConfigureTable(FooterTable, Table.TablePartType.Footer);\n            \n            var tableRequiresAdvancedHeaderTagging = Table.DoesTableBodyRequireExtendedHeaderTagging(HeaderTable.Cells, ContentTable.Cells);\n            HeaderTable.TableRequiresAdvancedHeaderTagging = tableRequiresAdvancedHeaderTagging;\n            ContentTable.TableRequiresAdvancedHeaderTagging = tableRequiresAdvancedHeaderTagging;\n            ContentTable.HeaderCells = HeaderTable.Cells;\n            \n            container\n                .Decoration(decoration =>\n                {\n                    decoration\n                        .Before()\n                        .ShowIf(hasHeader)\n                        .NonTrackingElement(x => EnableAutomatedSemanticTagging ? x.SemanticTag(\"THead\") : x)\n                        .Element(HeaderTable);\n                    \n                    decoration\n                        .Content()\n                        .NonTrackingElement(x => EnableAutomatedSemanticTagging ? x.SemanticTag(\"TBody\") : x)\n                        .ShowIf(ContentTable.Cells.Any())\n                        .Element(ContentTable);\n                    \n                    decoration\n                        .After()\n                        .ShowIf(hasFooter)\n                        .NonTrackingElement(x => EnableAutomatedSemanticTagging ? x.SemanticTag(\"TFoot\") : x)\n                        .Element(FooterTable);\n                });\n\n            return container;\n            \n            void ConfigureTable(Table table, Table.TablePartType tablePartType)\n            {\n                if (!table.Columns.Any())\n                    throw new DocumentComposeException($\"Table should have at least one column. Please call the '{nameof(ColumnsDefinition)}' method to define columns.\");\n            \n                table.PlanCellPositions();\n                table.ValidateCellPositions();\n                \n                table.EnableAutomatedSemanticTagging = EnableAutomatedSemanticTagging;\n                table.PartType = tablePartType;\n            }\n        }\n    }\n    \n    public static class TableExtensions\n    {\n        /// <summary>\n        /// <para>Renders a set of items utilizing the table layout algorithm.</para>\n        /// <para>\n        /// Items may be auto-placed based on the order they're called or can have assigned specific column and row positions. Cells can also span multiple columns and/or rows.\n        /// </para>\n        /// </summary>\n        /// <param name=\"handler\">Handler to define the table content.</param>\n        public static void Table(this IContainer element, Action<TableDescriptor> handler)\n        {\n            var descriptor = new TableDescriptor();\n            descriptor.EnableAutomatedSemanticTagging = element is SemanticTag { TagType: \"Table\" };\n            handler(descriptor);\n            element.Element(descriptor.CreateElement());\n        }\n    }\n\n    public static class TableCellExtensions\n    {\n        /// <summary>\n        /// Specifies the column position (horizontal axis) of the cell.\n        /// <a href=\"https://www.questpdf.com/api-reference/table/basics.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"value\">Columns are numbered starting with 1.</param>\n        public static ITableCellContainer Column(this ITableCellContainer tableCellContainer, uint value)\n        {\n            if (tableCellContainer is TableCell tableCell)\n                tableCell.Column = (int)value;\n\n            return tableCellContainer;\n        }\n        \n        /// <summary>\n        /// Defines the number of columns a cell spans in the horizontal axis.\n        /// <a href=\"https://www.questpdf.com/api-reference/table/basics.html#manual-cell-placement\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// Useful when creating complex layouts.\n        /// </remarks>\n        public static ITableCellContainer ColumnSpan(this ITableCellContainer tableCellContainer, uint value)\n        {\n            if (tableCellContainer is TableCell tableCell)\n                tableCell.ColumnSpan = (int)value;\n\n            return tableCellContainer;\n        }\n        \n        /// <summary>\n        /// Specifies the row position (vertical axis) of the cell.\n        /// <a href=\"https://www.questpdf.com/api-reference/table/basics.html\">Learn more</a>\n        /// </summary>\n        /// <param name=\"value\">Rows are numbered starting with 1.</param>\n        public static ITableCellContainer Row(this ITableCellContainer tableCellContainer, uint value)\n        {\n            if (tableCellContainer is TableCell tableCell)\n                tableCell.Row = (int)value;\n\n            return tableCellContainer;\n        }\n        \n        /// <summary>\n        /// Defines the number of rows a cell spans in the vertical axis.\n        /// <a href=\"https://www.questpdf.com/api-reference/table/basics.html#manual-cell-placement\">Learn more</a>\n        /// </summary>\n        /// <remarks>\n        /// Useful when creating complex layouts.\n        /// </remarks>\n        public static ITableCellContainer RowSpan(this ITableCellContainer tableCellContainer, uint value)\n        {\n            if (tableCellContainer is TableCell tableCell)\n                tableCell.RowSpan = (int)value;\n\n            return tableCellContainer;\n        }\n\n        /// <summary>\n        /// Marks the specified table cell as a semantic horizontal header.\n        /// This allows assistive technologies to recognize the cell as a header, improving accessibility and semantic structure.\n        /// </summary>\n        public static ITableCellContainer AsSemanticHorizontalHeader(this ITableCellContainer tableCellContainer)\n        {\n            if (tableCellContainer is TableCell tableCell)\n                tableCell.IsSemanticHorizontalHeader = true;\n\n            return tableCellContainer;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/TextExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing QuestPDF.Elements;\nusing QuestPDF.Elements.Text;\nusing QuestPDF.Elements.Text.Items;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public class TextSpanDescriptor\n    {\n        internal readonly TextBlockSpan TextBlockSpan;\n\n        internal TextSpanDescriptor(TextBlockSpan textBlockSpan)\n        {\n            TextBlockSpan = textBlockSpan;\n        }\n\n        internal void MutateTextStyle<T>(Func<TextStyle, T, TextStyle> handler, T argument)\n        {\n            TextBlockSpan.Style = handler(TextBlockSpan.Style, argument);\n        }\n        \n        internal void MutateTextStyle(Func<TextStyle, TextStyle> handler)\n        {\n            TextBlockSpan.Style = handler(TextBlockSpan.Style);\n        }\n    }\n\n    /// <summary>\n    /// Transforms a page number into a custom text format (e.g., roman numerals).\n    /// </summary>\n    /// <remarks>\n    /// When <paramref name=\"pageNumber\"/> is null, the delegate should return a default placeholder text of a typical length.\n    /// </remarks>\n    public delegate string PageNumberFormatter(int? pageNumber);\n    \n    public sealed class TextPageNumberDescriptor : TextSpanDescriptor\n    {\n        internal Action<PageNumberFormatter> AssignFormatFunction { get; }\n        \n        internal TextPageNumberDescriptor(TextBlockSpan textBlockSpan, Action<PageNumberFormatter> assignFormatFunction) : base(textBlockSpan)\n        {\n            AssignFormatFunction = assignFormatFunction;\n            AssignFormatFunction(x => x?.ToString());\n        }\n\n        /// <summary>\n        /// Provides the capability to render the page number in a custom text format (e.g., roman numerals).\n        /// <a href=\"https://www.questpdf.com/api-reference/text/page-numbers.html\">Lear more</a>\n        /// </summary>\n        /// <param name=\"formatter\">The function designated to modify the number into text. When given a null input, a typical-sized placeholder text must be produced.</param>\n        public TextPageNumberDescriptor Format(PageNumberFormatter formatter)\n        {\n            AssignFormatFunction(formatter);\n            return this;\n        }\n    }\n    \n    public sealed class TextBlockDescriptor : TextSpanDescriptor\n    {\n        private TextBlock TextBlock;\n\n        internal TextBlockDescriptor(TextBlock textBlock, TextBlockSpan textBlockSpan) : base(textBlockSpan)\n        {\n            TextBlock = textBlock;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.left\"]/*' />\n        public TextBlockDescriptor AlignLeft()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Left;\n            return this;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.center\"]/*' />\n        public TextBlockDescriptor AlignCenter()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Center;\n            return this;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.right\"]/*' />\n        public TextBlockDescriptor AlignRight()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Right;\n            return this;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.justify\"]/*' />\n        public TextBlockDescriptor Justify()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Justify;\n            return this;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.start\"]/*' />\n        public TextBlockDescriptor AlignStart()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Start;\n            return this;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.end\"]/*' />\n        public TextBlockDescriptor AlignEnd()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.End;\n            return this;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.clampLines\"]/*' />\n        public TextBlockDescriptor ClampLines(int maxLines, string ellipsis = TextDescriptor.DefaultLineClampEllipsis)\n        {\n            if (maxLines < 0)\n                throw new ArgumentException(\"Line clamp must be greater or equal to zero\", nameof(maxLines));\n            \n            TextBlock.LineClamp = maxLines;\n            TextBlock.LineClampEllipsis = ellipsis ?? TextDescriptor.DefaultLineClampEllipsis;\n            return this;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.paragraph.spacing\"]/*' />\n        public TextBlockDescriptor ParagraphSpacing(float value, Unit unit = Unit.Point)\n        {\n            if (value < 0)\n                throw new ArgumentException(\"Paragraph spacing must be greater or equal to zero\", nameof(value));\n            \n            TextBlock.ParagraphSpacing = value.ToPoints(unit);\n            return this;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.paragraph.firstLineIndentation\"]/*' />\n        public TextBlockDescriptor ParagraphFirstLineIndentation(float value, Unit unit = Unit.Point)\n        {\n            if (value < 0)\n                throw new ArgumentException(\"Paragraph indentation must be greater or equal to zero\", nameof(value));\n            \n            TextBlock.ParagraphFirstLineIndentation = value.ToPoints(unit);\n            return this;\n        }\n    }\n    \n    public sealed class TextDescriptor\n    {\n        internal TextBlock TextBlock { get; } = new();\n        private TextStyle? DefaultStyle { get; set; }\n\n        internal const string DefaultLineClampEllipsis = \"…\";\n\n        internal TextDescriptor()\n        {\n            \n        }\n        \n        /// <summary>\n        /// Applies a consistent text style for the whole content within this <see cref=\"TextExtensions.Text\">Text</see> element.\n        /// </summary>\n        /// <param name=\"style\">The TextStyle object to override the default inherited text style.</param>\n        public void DefaultTextStyle(TextStyle style)\n        {\n            DefaultStyle = style;\n        }\n        \n        /// <summary>\n        /// Applies a consistent text style for the whole content within this <see cref=\"TextExtensions.Text\">Text</see> element.\n        /// </summary>\n        /// <param name=\"handler\">Handler to modify the default inherited text style.</param>\n        public void DefaultTextStyle(Func<TextStyle, TextStyle> style)\n        {\n            DefaultStyle = style(TextStyle.Default);\n        }\n  \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.left\"]/*' />\n        public void AlignLeft()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Left;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.center\"]/*' />\n        public void AlignCenter()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Center;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.right\"]/*' />\n        public void AlignRight()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Right;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.justify\"]/*' />\n        public void Justify()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Justify;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.start\"]/*' />\n        public void AlignStart()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.Start;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.alignment.end\"]/*' />\n        public void AlignEnd()\n        {\n            TextBlock.Alignment = TextHorizontalAlignment.End;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.clampLines\"]/*' />\n        public void ClampLines(int maxLines, string ellipsis = DefaultLineClampEllipsis)\n        {\n            TextBlock.LineClamp = maxLines;\n            TextBlock.LineClampEllipsis = ellipsis;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.paragraph.spacing\"]/*' />\n        public void ParagraphSpacing(float value, Unit unit = Unit.Point)\n        {\n            if (value < 0)\n                throw new ArgumentException(\"Paragraph spacing must be greater or equal to zero\", nameof(value));\n            \n            TextBlock.ParagraphSpacing = value.ToPoints(unit);\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.paragraph.firstLineIndentation\"]/*' />\n        public void ParagraphFirstLineIndentation(float value, Unit unit = Unit.Point)\n        {\n            if (value < 0)\n                throw new ArgumentException(\"Paragraph indentation must be greater or equal to zero\", nameof(value));\n            \n            TextBlock.ParagraphFirstLineIndentation = value.ToPoints(unit);\n        }\n\n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the overload that returns a TextSpanDescriptor object which allows to specify text style.\")]\n        [ExcludeFromCodeCoverage]\n        public void Span(string? text, TextStyle style)\n        {\n            Span(text).Style(style);\n        }\n        \n        /// <summary>\n        /// Appends the given text to the current paragraph.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.spanDescriptor\"]/*' />\n        public TextSpanDescriptor Span(string? text)\n        {\n            if (text == null)\n                return new TextSpanDescriptor(new TextBlockSpan());\n\n            var textSpan = new TextBlockSpan() { Text = text };\n            TextBlock.Items.Add(textSpan);\n            return new TextSpanDescriptor(textSpan);\n        }\n\n        /// <summary>\n        /// Appends a line with the provided text followed by an environment-specific newline character.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.spanDescriptor\"]/*' />\n        public TextSpanDescriptor Line(string? text)\n        {\n            text ??= string.Empty;\n            return Span(text + \"\\n\");\n        }\n\n        /// <summary>\n        /// Appends a blank line.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.spanDescriptor\"]/*' />\n        public TextSpanDescriptor EmptyLine()\n        {\n            return Span(\"\\n\");\n        }\n        \n        private TextPageNumberDescriptor PageNumber(Func<IPageContext, int?> pageNumber)\n        {\n            var textBlockItem = new TextBlockPageNumber();\n            TextBlock.Items.Add(textBlockItem);\n            \n            return new TextPageNumberDescriptor(textBlockItem, x => textBlockItem.Source = context => x(pageNumber(context)));\n        }\n\n        /// <summary>\n        /// Appends text showing the current page number.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.pageNumberDescriptor\"]/*' />\n        public TextPageNumberDescriptor CurrentPageNumber()\n        {\n            return PageNumber(x => x.CurrentPage);\n        }\n        \n        /// <summary>\n        /// Appends text showing the total number of pages in the document.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.pageNumberDescriptor\"]/*' />\n        public TextPageNumberDescriptor TotalPages()\n        {\n            return PageNumber(x => x.DocumentLength);\n        }\n\n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the BeginPageNumberOfSection method.\")]\n        [ExcludeFromCodeCoverage]\n        public void PageNumberOfLocation(string sectionName, TextStyle? style = null)\n        {\n            BeginPageNumberOfSection(sectionName).Style(style);\n        }\n        \n        /// <summary>\n        /// Appends text showing the number of the first page of the specified <see cref=\"ElementExtensions.Section\">Section</see>.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"param.sectionName\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.pageNumberDescriptor\"]/*' />\n        public TextPageNumberDescriptor BeginPageNumberOfSection(string sectionName)\n        {\n            return PageNumber(x => x.GetLocation(sectionName)?.PageStart);\n        }\n        \n        /// <summary>\n        /// Appends text showing the number of the last page of the specified <see cref=\"ElementExtensions.Section\">Section</see>.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"param.sectionName\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.pageNumberDescriptor\"]/*' />\n        public TextPageNumberDescriptor EndPageNumberOfSection(string sectionName)\n        {\n            return PageNumber(x => x.GetLocation(sectionName)?.PageEnd);\n        }\n        \n        /// <summary>\n        /// Appends text showing the page number relative to the beginning of the given <see cref=\"ElementExtensions.Section\">Section</see>.\n        /// </summary>\n        /// <example>\n        /// For a section spanning pages 20 to 50, page 35 will show as 15.\n        /// </example>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"param.sectionName\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.pageNumberDescriptor\"]/*' />\n        public TextPageNumberDescriptor PageNumberWithinSection(string sectionName)\n        {\n            return PageNumber(x => x.CurrentPage + 1 - x.GetLocation(sectionName)?.PageStart);\n        }\n        \n        /// <summary>\n        /// Appends text showing the total number of pages within the given <see cref=\"ElementExtensions.Section\">Section</see>.\n        /// </summary>\n        /// <example>\n        /// For a section spanning pages 20 to 50, the total is 30 pages.\n        /// </example>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"param.sectionName\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.pageNumberDescriptor\"]/*' />\n        public TextPageNumberDescriptor TotalPagesWithinSection(string sectionName)\n        {\n            return PageNumber(x => x.GetLocation(sectionName)?.Length);\n        }\n        \n        /// <summary>\n        /// Creates a clickable text that navigates the user to a specified <see cref=\"ElementExtensions.Section\">Section</see>.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"param.sectionName\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.spanDescriptor\"]/*' />\n        public TextSpanDescriptor SectionLink(string? text, string sectionName)\n        {\n            if (string.IsNullOrWhiteSpace(sectionName))\n                throw new ArgumentException(\"Section name cannot be null or whitespace.\", nameof(sectionName));\n\n            if (text == null)\n                return new TextSpanDescriptor(new TextBlockSpan());\n\n            var textBlockItem = new TextBlockSectionLink\n            {\n                Text = text,\n                SectionName = sectionName\n            };\n\n            TextBlock.Items.Add(textBlockItem);\n            return new TextSpanDescriptor(textBlockItem);\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the SectionLink method.\")]\n        [ExcludeFromCodeCoverage]\n        public void InternalLocation(string? text, string locationName, TextStyle? style = null)\n        {\n            SectionLink(text, locationName).Style(style);\n        }\n        \n        /// <summary>\n        /// Creates a clickable text that redirects the user to a specific webpage.\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"param.url\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.spanDescriptor\"]/*' />\n        public TextSpanDescriptor Hyperlink(string? text, string url)\n        {\n            if (string.IsNullOrWhiteSpace(url))\n                throw new ArgumentException(\"Url cannot be null or whitespace.\", nameof(url));\n\n            if (text == null)\n                return new TextSpanDescriptor(new TextBlockSpan());\n            \n            var textBlockItem = new TextBlockHyperlink\n            {\n                Text = text,\n                Url = url\n            };\n\n            TextBlock.Items.Add(textBlockItem);\n            return new TextSpanDescriptor(textBlockItem);\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the Hyperlink method.\")]\n        [ExcludeFromCodeCoverage]\n        public void ExternalLocation(string? text, string url, TextStyle? style = null)\n        {\n            Hyperlink(text, url).Style(style);\n        }\n        \n        /// <summary>\n        /// Embeds custom content within the text.\n        /// </summary>\n        /// <remarks>\n        /// The container must fit within one line and can not span multiple pages.\n        /// </remarks>\n        /// <param name=\"alignment\">Defines the position of the injected element in relation to text typography features (baseline, top/bottom edge).</param>\n        /// <returns>A container for the embedded content. Populate using the Fluent API.</returns>\n        public IContainer Element(TextInjectedElementAlignment alignment = TextInjectedElementAlignment.AboveBaseline)\n        {\n            var container = new Container();\n                \n            TextBlock.Items.Add(new TextBlockElement\n            {\n                Element = container,\n                Alignment = alignment\n            });\n            \n            return container.AlignBottom().MinimalBox();\n        }\n        \n        /// <summary>\n        /// Embeds custom content within the text.\n        /// </summary>\n        /// <remarks>\n        /// The container must fit within one line and can not span multiple pages.\n        /// </remarks>\n        /// <param name=\"alignment\">Defines the position of the injected element in relation to text typography features (baseline, top/bottom edge).</param>\n        /// <param name=\"handler\">Delegate to populate the embedded container with custom content.</param>\n        public void Element(Action<IContainer> handler, TextInjectedElementAlignment alignment = TextInjectedElementAlignment.AboveBaseline)\n        {\n            handler(Element(alignment));\n        }\n        \n        internal void Compose(IContainer container)\n        {\n            if (DefaultStyle != null)\n                container = container.DefaultTextStyle(DefaultStyle);\n\n            container.Element(TextBlock);\n        }\n    }\n    \n    public static class TextExtensions\n    {\n        /// <summary>\n        /// Draws rich formatted text.\n        /// </summary>\n        /// <param name=\"content\">Handler to define the content of the text elements (e.g.: paragraphs, spans, hyperlinks, page numbers).</param>\n        public static void Text(this IContainer element, Action<TextDescriptor> content)\n        {\n            var descriptor = new TextDescriptor();\n            \n            if (element is Alignment alignment)\n                descriptor.TextBlock.Alignment = MapAlignment(alignment.Horizontal);\n            \n            content?.Invoke(descriptor);\n            descriptor.Compose(element);\n        }\n        \n        [Obsolete(\"This method has been deprecated since version 2022.3. Please use the overload that returns a TextSpanDescriptor object which allows to specify text style.\")]\n        [ExcludeFromCodeCoverage]\n        public static void Text(this IContainer element, object? text, TextStyle style)\n        {\n            element.Text(text).Style(style);\n        }\n\n        [Obsolete(\"This method has been deprecated since version 2022.12. Please use an overload where the text parameter is passed explicitly as a string.\")]\n        [ExcludeFromCodeCoverage]\n        public static TextSpanDescriptor Text(this IContainer element, object? text)\n        {\n            return element.Text(text?.ToString());\n        }\n\n        /// <summary>\n        /// Draws the provided text on the page\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.returns.spanDescriptor\"]/*' />\n        public static TextBlockDescriptor Text(this IContainer container, string? text)\n        {\n            if (text == null)\n                return new TextBlockDescriptor(new TextBlock(), new TextBlockSpan());\n            \n            var textBlock = new TextBlock();\n            container.Element(textBlock);\n            \n            if (container is Alignment alignment)\n                textBlock.Alignment = MapAlignment(alignment.Horizontal);\n            \n            var textSpan = new TextBlockSpan { Text = text };\n            textBlock.Items.Add(textSpan);\n            \n            return new TextBlockDescriptor(textBlock, textSpan);\n        }\n        \n        private static TextHorizontalAlignment? MapAlignment(HorizontalAlignment? alignment)\n        {\n            return alignment switch\n            {\n                HorizontalAlignment.Left => TextHorizontalAlignment.Left,\n                HorizontalAlignment.Center => TextHorizontalAlignment.Center,\n                HorizontalAlignment.Right => TextHorizontalAlignment.Right,\n                _ => null\n            };\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/TextSpanDescriptorExtensions.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class TextSpanDescriptorExtensions\n    {\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.style\"]/*' />\n        public static T Style<T>(this T descriptor, TextStyle style) where T : TextSpanDescriptor\n        {\n            if (style == null)\n                return descriptor;\n            \n            descriptor.MutateTextStyle(TextStyleManager.OverrideStyle, style);\n            return descriptor;\n        }\n        \n        [Obsolete(\"This setting is not supported since the 2024.3 version. Please use the FontFamilyFallback method or rely on the new automated fallback mechanism.\")]\n        [ExcludeFromCodeCoverage]\n        public static T Fallback<T>(this T descriptor, TextStyle? value = null) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Fallback, value);\n            return descriptor;\n        }\n        \n        [Obsolete(\"This setting is not supported since the 2024.3 version. Please use the FontFamilyFallback method or rely on the new automated fallback mechanism.\")]\n        [ExcludeFromCodeCoverage]\n        public static T Fallback<T>(this T descriptor, Func<TextStyle, TextStyle> handler) where T : TextSpanDescriptor\n        {\n            return descriptor.Fallback(handler(TextStyle.Default));\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontColor\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public static T FontColor<T>(this T descriptor, Color color) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.FontColor, color);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.backgroundColor\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public static T BackgroundColor<T>(this T descriptor, Color color) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.BackgroundColor, color);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontFamily\"]/*' />\n        public static T FontFamily<T>(this T descriptor, params string[] values) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.FontFamily, values);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontSize\"]/*' />\n        public static T FontSize<T>(this T descriptor, float value) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.FontSize, value);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.lineHeight\"]/*' />\n        public static T LineHeight<T>(this T descriptor, float? factor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.LineHeight, factor);\n            return descriptor;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.letterSpacing\"]/*' />\n        public static T LetterSpacing<T>(this T descriptor, float factor = 0) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.LetterSpacing, factor);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.wordSpacing\"]/*' />\n        public static T WordSpacing<T>(this T descriptor, float factor = 0) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.WordSpacing, factor);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.italic\"]/*' />\n        public static T Italic<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Italic, value);\n            return descriptor;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.wrapAnywhere\"]/*' />\n        [Obsolete(\"This setting is not supported since the 2024.3 version. This flag should be handled automatically by the layout engine.\")]\n        [ExcludeFromCodeCoverage]\n        public static T WrapAnywhere<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor\n        {\n            return descriptor;\n        }\n        \n        #region Text Effects\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.strikethrough\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.remarks\"]/*' />\n        public static T Strikethrough<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Strikethrough, value);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.underline\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.remarks\"]/*' />\n        public static T Underline<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Underline, value);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.overline\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.remarks\"]/*' />\n        public static T Overline<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Overline, value);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.color\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static T DecorationColor<T>(this T descriptor, Color color) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DecorationColor, color);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.thickness\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static T DecorationThickness<T>(this T descriptor, float factor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DecorationThickness, factor);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.solid\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static T DecorationSolid<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DecorationSolid);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.double\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static T DecorationDouble<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DecorationDouble);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.wavy\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static T DecorationWavy<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DecorationWavy);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.dotted\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static T DecorationDotted<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DecorationDotted);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.dashed\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static T DecorationDashed<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DecorationDashed);\n            return descriptor;\n        }\n        \n        #endregion\n\n        #region Weight\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.thin\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T Thin<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Thin);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.extraLight\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T ExtraLight<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.ExtraLight);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.light\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T Light<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Light);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.normal\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T NormalWeight<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.NormalWeight);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.medium\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T Medium<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Medium);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.semiBold\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T SemiBold<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.SemiBold);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.bold\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T Bold<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Bold);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.extraBold\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T ExtraBold<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.ExtraBold);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.black\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T Black<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Black);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.extraBlack\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static T ExtraBlack<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.ExtraBlack);\n            return descriptor;\n        }\n\n        #endregion\n\n        #region Position\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.position.normal\"]/*' />\n        public static T NormalPosition<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.NormalPosition);\n            return descriptor;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.position.subscript\"]/*' />\n        public static T Subscript<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Subscript);\n            return descriptor;\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.position.superscript\"]/*' />\n        public static T Superscript<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.Superscript);\n            return descriptor;\n        }\n        \n        #endregion\n        \n        #region Direction\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.direction.auto\"]/*' />\n        public static T DirectionAuto<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DirectionAuto);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.direction.ltr\"]/*' />\n        public static T DirectionFromLeftToRight<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DirectionFromLeftToRight);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.direction.rtl\"]/*' />\n        public static T DirectionFromRightToLeft<T>(this T descriptor) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DirectionFromRightToLeft);\n            return descriptor;\n        }\n\n        #endregion\n        \n        #region Font Features\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontFeatures\"]/*' />\n        public static T EnableFontFeature<T>(this T descriptor, string featureName) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.EnableFontFeature, featureName);\n            return descriptor;\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontFeatures\"]/*' />\n        public static T DisableFontFeature<T>(this T descriptor, string featureName) where T : TextSpanDescriptor\n        {\n            descriptor.MutateTextStyle(TextStyleExtensions.DisableFontFeature, featureName);\n            return descriptor;\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/TextStyleExtensions.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Fluent\n{\n    public static class TextStyleExtensions\n    {\n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the FontColor method.\")]\n        [ExcludeFromCodeCoverage]\n        public static TextStyle Color(this TextStyle style, string value)\n        {\n            return style.FontColor(value);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontColor\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public static TextStyle FontColor(this TextStyle style, Color color)\n        {\n            return style\n                .Mutate(TextStyleProperty.Color, color)\n                .Mutate(TextStyleProperty.DecorationColor, color);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.backgroundColor\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"colorParam\"]/*' />\n        public static TextStyle BackgroundColor(this TextStyle style, Color color)\n        {\n            return style.Mutate(TextStyleProperty.BackgroundColor, color);\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the FontFamily method.\")]\n        [ExcludeFromCodeCoverage]\n        public static TextStyle FontType(this TextStyle style, string value)\n        {\n            return style.FontFamily(value);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontFamily\"]/*' />\n        public static TextStyle FontFamily(this TextStyle style, params string[] values)\n        {\n            if (values == null || values.Length == 0)\n                return style;\n            \n            return style.Mutate(TextStyleProperty.FontFamilies, values);\n        }\n        \n        [Obsolete(\"This element has been renamed since version 2022.3. Please use the FontSize method.\")]\n        [ExcludeFromCodeCoverage]\n        public static TextStyle Size(this TextStyle style, float value)\n        {\n            return style.FontSize(value);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontSize\"]/*' />\n        public static TextStyle FontSize(this TextStyle style, float value)\n        {\n            if (value <= 0)\n                throw new ArgumentException(\"Font size must be greater than 0.\");\n            \n            return style.Mutate(TextStyleProperty.Size, value);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.lineHeight\"]/*' />\n        public static TextStyle LineHeight(this TextStyle style, float? factor)\n        {\n            factor ??= TextStyle.NormalLineHeightCalculatedFromFontMetrics;\n            \n            if (factor < 0)\n                throw new ArgumentException(\"Line height must be greater than 0.\");\n            \n            return style.Mutate(TextStyleProperty.LineHeight, factor);\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.letterSpacing\"]/*' />\n        public static TextStyle LetterSpacing(this TextStyle style, float factor = 0)\n        {\n            return style.Mutate(TextStyleProperty.LetterSpacing, factor);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.wordSpacing\"]/*' />\n        public static TextStyle WordSpacing(this TextStyle style, float factor = 0)\n        {\n            return style.Mutate(TextStyleProperty.WordSpacing, factor);\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.italic\"]/*' />\n        public static TextStyle Italic(this TextStyle style, bool value = true)\n        {\n            return style.Mutate(TextStyleProperty.IsItalic, value);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.wrapAnywhere\"]/*' />\n        [Obsolete(\"This setting is not supported since the 2024.3 version. This flag should be handled automatically by the layout engine.\")]\n        [ExcludeFromCodeCoverage]\n        public static TextStyle WrapAnywhere(this TextStyle style, bool value = true)\n        {\n            return style;\n        }\n\n        #region Text Effects\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.strikethrough\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.remarks\"]/*' />\n        public static TextStyle Strikethrough(this TextStyle style, bool value = true)\n        {\n            return style.Mutate(TextStyleProperty.HasStrikethrough, value);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.underline\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.remarks\"]/*' />\n        public static TextStyle Underline(this TextStyle style, bool value = true)\n        {\n            return style.Mutate(TextStyleProperty.HasUnderline, value);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.overline\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.remarks\"]/*' />\n        public static TextStyle Overline(this TextStyle style, bool value = true)\n        {\n            return style.Mutate(TextStyleProperty.HasOverline, value);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.color\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static TextStyle DecorationColor(this TextStyle style, Color color)\n        {\n            return style.Mutate(TextStyleProperty.DecorationColor, color);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.thickness\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static TextStyle DecorationThickness(this TextStyle style, float factor)\n        {\n            return style.Mutate(TextStyleProperty.DecorationThickness, factor);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.solid\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static TextStyle DecorationSolid(this TextStyle style)\n        {\n            return style.Mutate(TextStyleProperty.DecorationStyle, TextStyleConfiguration.TextDecorationStyle.Solid);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.double\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static TextStyle DecorationDouble(this TextStyle style)\n        {\n            return style.Mutate(TextStyleProperty.DecorationStyle, TextStyleConfiguration.TextDecorationStyle.Double);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.wavy\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static TextStyle DecorationWavy(this TextStyle style)\n        {\n            return style.Mutate(TextStyleProperty.DecorationStyle, TextStyleConfiguration.TextDecorationStyle.Wavy);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.dotted\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static TextStyle DecorationDotted(this TextStyle style)\n        {\n            return style.Mutate(TextStyleProperty.DecorationStyle, TextStyleConfiguration.TextDecorationStyle.Dotted);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.dashed\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.decoration.applicability\"]/*' />\n        public static TextStyle DecorationDashed(this TextStyle style)\n        {\n            return style.Mutate(TextStyleProperty.DecorationStyle, TextStyleConfiguration.TextDecorationStyle.Dashed);\n        }\n        \n        #endregion\n        \n        #region Weight\n        \n        public static TextStyle Weight(this TextStyle style, FontWeight weight)\n        {\n            return style.Mutate(TextStyleProperty.FontWeight, weight);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.thin\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle Thin(this TextStyle style)\n        {\n            return style.Weight(FontWeight.Thin);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.extraLight\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle ExtraLight(this TextStyle style)\n        {\n            return style.Weight(FontWeight.ExtraLight);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.light\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle Light(this TextStyle style)\n        {\n            return style.Weight(FontWeight.Light);\n        }\n       \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.normal\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle NormalWeight(this TextStyle style)\n        {\n            return style.Weight(FontWeight.Normal);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.medium\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle Medium(this TextStyle style)\n        {\n            return style.Weight(FontWeight.Medium);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.semiBold\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle SemiBold(this TextStyle style)\n        {\n            return style.Weight(FontWeight.SemiBold);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.bold\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle Bold(this TextStyle style)\n        {\n            return style.Weight(FontWeight.Bold);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.extraBold\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle ExtraBold(this TextStyle style)\n        {\n            return style.Weight(FontWeight.ExtraBold);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.black\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle Black(this TextStyle style)\n        {\n            return style.Weight(FontWeight.Black);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.extraBlack\"]/*' />\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.weight.remarks\"]/*' />\n        public static TextStyle ExtraBlack(this TextStyle style)\n        {\n            return style.Weight(FontWeight.ExtraBlack);\n        }\n\n        #endregion\n\n        #region Position\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.position.normal\"]/*' />\n        public static TextStyle NormalPosition(this TextStyle style)\n        {\n            return style.Position(FontPosition.Normal);\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.position.subscript\"]/*' />\n        public static TextStyle Subscript(this TextStyle style)\n        {\n            return style.Position(FontPosition.Subscript);\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.position.superscript\"]/*' />\n        public static TextStyle Superscript(this TextStyle style)\n        {\n            return style.Position(FontPosition.Superscript);\n        }\n\n        private static TextStyle Position(this TextStyle style, FontPosition fontPosition)\n        {\n            return style.Mutate(TextStyleProperty.FontPosition, fontPosition);\n        }\n        \n        #endregion\n\n        #region Fallback\n        \n        [Obsolete(\"This setting is not supported since the 2024.3 version. Please use the FontFamilyFallback method or rely on the new automated fallback mechanism.\")]\n        [ExcludeFromCodeCoverage]\n        public static TextStyle Fallback(this TextStyle style, TextStyle? value = null)\n        {\n            var currentFontFamilies = style.FontFamilies ?? Array.Empty<string>();\n            var fallbackFontFamilies = value?.FontFamilies ?? Array.Empty<string>();\n            \n            var targetFontFamilies = currentFontFamilies\n                .Concat(fallbackFontFamilies)\n                .Where(x => !string.IsNullOrWhiteSpace(x))\n                .Distinct()\n                .ToArray();\n            \n            return style.FontFamily(targetFontFamilies);\n        }\n        \n        [Obsolete(\"This setting is not supported since the 2024.3 version. Please use the FontFamilyFallback method or rely on the new automated fallback mechanism.\")]\n        [ExcludeFromCodeCoverage]\n        public static TextStyle Fallback(this TextStyle style, Func<TextStyle, TextStyle> handler)\n        {\n            return style.Fallback(handler(TextStyle.Default));\n        }\n\n        #endregion\n\n        #region Direction\n\n        private static TextStyle TextDirection(this TextStyle style, TextDirection textDirection)\n        {\n            return style.Mutate(TextStyleProperty.Direction, textDirection);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.direction.auto\"]/*' />\n        public static TextStyle DirectionAuto(this TextStyle style)\n        {\n            return style.TextDirection(Infrastructure.TextDirection.Auto);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.direction.ltr\"]/*' />\n        public static TextStyle DirectionFromLeftToRight(this TextStyle style)\n        {\n            return style.TextDirection(Infrastructure.TextDirection.LeftToRight);\n        }\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.direction.rtl\"]/*' />\n        public static TextStyle DirectionFromRightToLeft(this TextStyle style)\n        {\n            return style.TextDirection(Infrastructure.TextDirection.RightToLeft);\n        }\n\n        #endregion\n\n        #region Font Features\n        \n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontFeatures\"]/*' />\n        public static TextStyle EnableFontFeature(this TextStyle style, string featureName)\n        {\n            return style.Mutate(TextStyleProperty.FontFeatures, new[] { (featureName, true) });\n        }\n\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"text.fontFeatures\"]/*' />\n        public static TextStyle DisableFontFeature(this TextStyle style, string featureName)\n        {\n            return style.Mutate(TextStyleProperty.FontFeatures, new[] { (featureName, false) });\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Fluent/TranslateExtensions.cs",
    "content": "﻿using QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Fluent\n{\n    public static class TranslateExtensions\n    {\n        private static IContainer Translate(this IContainer element, float x = 0, float y = 0)\n        {\n            var translate = element as Translate ?? new Translate();\n\n            translate.TranslateX += x;\n            translate.TranslateY += y;\n            \n            return element.Element(translate);\n        }\n\n        /// <summary>\n        /// Moves content along the horizontal axis.\n        /// A positive value moves content to the right; a negative value moves it to the left.\n        /// Does not alter the available space.\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/translate.html\">Learn more</a>\n        /// </summary>\n        public static IContainer TranslateX(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Translate(x: value);\n        }\n   \n        /// <summary>\n        /// Moves content along the vertical axis.\n        /// A positive value moves content downwards, a negative value moves it upwards.\n        /// Does not alter the available space.\n        /// <br />\n        /// <a href=\"https://www.questpdf.com/api-reference/translate.html\">Learn more</a>\n        /// </summary>\n        public static IContainer TranslateY(this IContainer element, float value, Unit unit = Unit.Point)\n        {\n            value = value.ToPoints(unit);\n            return element.Translate(y: value);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/CallerArgumentExpression.cs",
    "content": "#if !NET6_0_OR_GREATER\n\nnamespace System.Runtime.CompilerServices\n{\n    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]\n    internal sealed class CallerArgumentExpressionAttribute : Attribute\n    {\n        public CallerArgumentExpressionAttribute(string parameterName)\n        {\n            ParameterName = parameterName;\n        }\n\n        public string ParameterName { get; }\n    }\n}\n\n#endif"
  },
  {
    "path": "Source/QuestPDF/Helpers/ColorParser.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.Globalization;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Helpers;\n\nstatic class ColorParser\n{\n    private static readonly ConcurrentDictionary<string, Color?> Cache = new(); \n    \n    public static Color ParseColorHex(string hexString)\n    {\n        if (!TryParseColorHex(hexString, out var color))\n        {\n            throw new ArgumentException(\n                $\"The provided value '{hexString}' is not a valid hex color. \" +\n                \"The following formats are supported: #RGB, #ARGB, #RRGGBB, #AARRGGBB. \" +\n                \"The hash sign is optional so the following formats are also valid: RGB, ARGB, RRGGBB, AARRGGBB. \" +\n                \"For example #FF8800 is a solid orange color, while #20CF is a barely visible aqua color.\",\n                nameof(color));\n        }\n        \n        return color;\n    }\n    \n    // inspired by: https://github.com/mono/SkiaSharp/blob/9274aeec807fd17eec2a3266ad4c2475c37d8a0c/binding/SkiaSharp/SKColor.cs#L123\n    public static bool TryParseColorHex(string hexString, out Color color)\n    {\n        var result = Cache.GetOrAdd(hexString, ParseColor);\n        color = result ?? Colors.Black;\n        return result.HasValue;\n\n        static Color? ParseColor(string hexString)\n        {\n            uint color = 0;\n            \n            if (string.IsNullOrWhiteSpace(hexString))\n                return null;\n    \n            // clean up string\n            var hexSpan = hexString.Trim().TrimStart('#');\n    \n            var len = hexSpan.Length;\n    \n            if (len == 3 || len == 4)\n            {\n                byte a;\n                \n                // parse [A]\n                if (len == 4)\n                {\n                    if (!byte.TryParse(hexSpan.Substring(0, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out a))\n                        return null;\n    \n                    a = (byte)((a << 4) | a);\n                }\n                else\n                {\n                    a = 255;\n                }\n    \n                // parse RGB\n                if (!byte.TryParse(hexSpan.Substring(len - 3, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var r) ||\n                    !byte.TryParse(hexSpan.Substring(len - 2, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var g) ||\n                    !byte.TryParse(hexSpan.Substring(len - 1, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var b))\n                {\n                    return null;\n                }\n    \n                r |= (byte)(r << 4);\n                g |= (byte)(g << 4);\n                b |= (byte)(b << 4);\n                \n                // success\n                color = (uint)((a << 24) | (r << 16) | (g << 8) | b);\n                return new Color(color);\n            }\n    \n            if (len == 6 || len == 8)\n            {\n                // parse [AA]RRGGBB\n                if (!uint.TryParse(hexSpan, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var number))\n                    return null;\n    \n                // success\n                color = number;\n    \n                // alpha was not provided, so use 255\n                if (len == 6)\n                    color |= 0xFF000000;\n                \n                return new Color(color);\n            }\n    \n            return null;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/Colors.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\n#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member\n\nnamespace QuestPDF.Helpers\n{\n    /// <summary>\n    /// Offers a palette of colors defined by the Google Material Design System guidelines.\n    /// Each primary color (like red, blue, green) has associated shades and accent variations.\n    /// <br />\n    /// <a href=\"https://m2.material.io/design/color/the-color-system.html#tools-for-picking-colors\">Learn more</a>\n    /// </summary>\n    /// <example>\n    /// Access colors using the following pattern:\n    /// <code>\n    /// Colors.Black;\n    /// Colors.Red.Lighten5;\n    /// Colors.Blue.Medium; \n    /// Colors.Green.Darken4; \n    /// Colors.Yellow.Accent2; \n    /// </code>\n    /// </example>\n    public static class Colors\n    {\n        public static readonly Color Black = new(0xFF000000);\n        public static readonly Color White = new(0xFFFFFFFF);\n        public static readonly Color Transparent = new(0x00000000);\n\n        public static class Red\n        {\n            public static readonly Color Lighten5 = new(0xFFFFEBEE);\n            public static readonly Color Lighten4 = new(0xFFFFCDD2);\n            public static readonly Color Lighten3 = new(0xFFEF9A9A);\n            public static readonly Color Lighten2 = new(0xFFE57373);\n            public static readonly Color Lighten1 = new(0xFFEF5350);\n            \n            public static readonly Color Medium = new(0xFFF44336);\n            \n            public static readonly Color Darken1 = new(0xFFE53935);\n            public static readonly Color Darken2 = new(0xFFD32F2F);\n            public static readonly Color Darken3 = new(0xFFC62828);\n            public static readonly Color Darken4 = new(0xFFB71C1C);\n            \n            public static readonly Color Accent1 = new(0xFFFF8A80);\n            public static readonly Color Accent2 = new(0xFFFF5252);\n            public static readonly Color Accent3 = new(0xFFFF1744);\n            public static readonly Color Accent4 = new(0xFFD50000);\n        }\n\n        public static class Pink\n        {\n            public static readonly Color Lighten5 = new(0xFFFCE4EC);\n            public static readonly Color Lighten4 = new(0xFFF8BBD0);\n            public static readonly Color Lighten3 = new(0xFFF48FB1);\n            public static readonly Color Lighten2 = new(0xFFF06292);\n            public static readonly Color Lighten1 = new(0xFFEC407A);\n            \n            public static readonly Color Medium = new(0xFFE91E63);\n            \n            public static readonly Color Darken1 = new(0xFFD81B60);\n            public static readonly Color Darken2 = new(0xFFC2185B);\n            public static readonly Color Darken3 = new(0xFFAD1457);\n            public static readonly Color Darken4 = new(0xFF880E4F);\n            \n            public static readonly Color Accent1 = new(0xFFFF80AB);\n            public static readonly Color Accent2 = new(0xFFFF4081);\n            public static readonly Color Accent3 = new(0xFFF50057);\n            public static readonly Color Accent4 = new(0xFFC51162);\n        }\n\n        public static class Purple\n        {\n            public static readonly Color Lighten5 = new(0xFFF3E5F5);\n            public static readonly Color Lighten4 = new(0xFFE1BEE7);\n            public static readonly Color Lighten3 = new(0xFFCE93D8);\n            public static readonly Color Lighten2 = new(0xFFBA68C8);\n            public static readonly Color Lighten1 = new(0xFFAB47BC);\n            \n            public static readonly Color Medium = new(0xFF9C27B0);\n            \n            public static readonly Color Darken1 = new(0xFF8E24AA);\n            public static readonly Color Darken2 = new(0xFF7B1FA2);\n            public static readonly Color Darken3 = new(0xFF6A1B9A);\n            public static readonly Color Darken4 = new(0xFF4A148C);\n            \n            public static readonly Color Accent1 = new(0xFFEA80FC);\n            public static readonly Color Accent2 = new(0xFFE040FB);\n            public static readonly Color Accent3 = new(0xFFD500F9);\n            public static readonly Color Accent4 = new(0xFFAA00FF);\n        }\n\n        public static class DeepPurple\n        {\n            public static readonly Color Lighten5 = new(0xFFEDE7F6);\n            public static readonly Color Lighten4 = new(0xFFD1C4E9);\n            public static readonly Color Lighten3 = new(0xFFB39DDB);\n            public static readonly Color Lighten2 = new(0xFF9575CD);\n            public static readonly Color Lighten1 = new(0xFF7E57C2);\n            \n            public static readonly Color Medium = new(0xFF673AB7);\n            \n            public static readonly Color Darken1 = new(0xFF5E35B1);\n            public static readonly Color Darken2 = new(0xFF512DA8);\n            public static readonly Color Darken3 = new(0xFF4527A0);\n            public static readonly Color Darken4 = new(0xFF311B92);\n            \n            public static readonly Color Accent1 = new(0xFFB388FF);\n            public static readonly Color Accent2 = new(0xFF7C4DFF);\n            public static readonly Color Accent3 = new(0xFF651FFF);\n            public static readonly Color Accent4 = new(0xFF6200EA);\n        }\n\n        public static class Indigo\n        {\n            public static readonly Color Lighten5 = new(0xFFE8EAF6);\n            public static readonly Color Lighten4 = new(0xFFC5CAE9);\n            public static readonly Color Lighten3 = new(0xFF9FA8DA);\n            public static readonly Color Lighten2 = new(0xFF7986CB);\n            public static readonly Color Lighten1 = new(0xFF5C6BC0);\n            \n            public static readonly Color Medium = new(0xFF3F51B5);\n            \n            public static readonly Color Darken1 = new(0xFF3949AB);\n            public static readonly Color Darken2 = new(0xFF303F9F);\n            public static readonly Color Darken3 = new(0xFF283593);\n            public static readonly Color Darken4 = new(0xFF1A237E);\n            \n            public static readonly Color Accent1 = new(0xFF8C9EFF);\n            public static readonly Color Accent2 = new(0xFF536DFE);\n            public static readonly Color Accent3 = new(0xFF3D5AFE);\n            public static readonly Color Accent4 = new(0xFF304FFE);\n        }\n\n        public static class Blue\n        {\n            public static readonly Color Lighten5 = new(0xFFE3F2FD);\n            public static readonly Color Lighten4 = new(0xFFBBDEFB);\n            public static readonly Color Lighten3 = new(0xFF90CAF9);\n            public static readonly Color Lighten2 = new(0xFF64B5F6);\n            public static readonly Color Lighten1 = new(0xFF42A5F5);\n            \n            public static readonly Color Medium = new(0xFF2196F3);\n            \n            public static readonly Color Darken1 = new(0xFF1E88E5);\n            public static readonly Color Darken2 = new(0xFF1976D2);\n            public static readonly Color Darken3 = new(0xFF1565C0);\n            public static readonly Color Darken4 = new(0xFF0D47A1);\n            \n            public static readonly Color Accent1 = new(0xFF82B1FF);\n            public static readonly Color Accent2 = new(0xFF448AFF);\n            public static readonly Color Accent3 = new(0xFF2979FF);\n            public static readonly Color Accent4 = new(0xFF2962FF);\n        }\n\n        public static class LightBlue\n        {\n            public static readonly Color Lighten5 = new(0xFFE1F5FE);\n            public static readonly Color Lighten4 = new(0xFFB3E5FC);\n            public static readonly Color Lighten3 = new(0xFF81D4FA);\n            public static readonly Color Lighten2 = new(0xFF4FC3F7);\n            public static readonly Color Lighten1 = new(0xFF29B6F6);\n            \n            public static readonly Color Medium = new(0xFF03A9F4);\n            \n            public static readonly Color Darken1 = new(0xFF039BE5);\n            public static readonly Color Darken2 = new(0xFF0288D1);\n            public static readonly Color Darken3 = new(0xFF0277BD);\n            public static readonly Color Darken4 = new(0xFF01579B);\n            \n            public static readonly Color Accent1 = new(0xFF80D8FF);\n            public static readonly Color Accent2 = new(0xFF40C4FF);\n            public static readonly Color Accent3 = new(0xFF00B0FF);\n            public static readonly Color Accent4 = new(0xFF0091EA);\n        }\n\n        public static class Cyan\n        {\n            public static readonly Color Lighten5 = new(0xFFE0F7FA);\n            public static readonly Color Lighten4 = new(0xFFB2EBF2);\n            public static readonly Color Lighten3 = new(0xFF80DEEA);\n            public static readonly Color Lighten2 = new(0xFF4DD0E1);\n            public static readonly Color Lighten1 = new(0xFF26C6DA);\n            \n            public static readonly Color Medium = new(0xFF00BCD4);\n            \n            public static readonly Color Darken1 = new(0xFF00ACC1);\n            public static readonly Color Darken2 = new(0xFF0097A7);\n            public static readonly Color Darken3 = new(0xFF00838F);\n            public static readonly Color Darken4 = new(0xFF006064);\n            \n            public static readonly Color Accent1 = new(0xFF84FFFF);\n            public static readonly Color Accent2 = new(0xFF18FFFF);\n            public static readonly Color Accent3 = new(0xFF00E5FF);\n            public static readonly Color Accent4 = new(0xFF00B8D4);\n        }\n\n        public static class Teal\n        {\n            public static readonly Color Lighten5 = new(0xFFE0F2F1);\n            public static readonly Color Lighten4 = new(0xFFB2DFDB);\n            public static readonly Color Lighten3 = new(0xFF80CBC4);\n            public static readonly Color Lighten2 = new(0xFF4DB6AC);\n            public static readonly Color Lighten1 = new(0xFF26A69A);\n            \n            public static readonly Color Medium = new(0xFF009688);\n            \n            public static readonly Color Darken1 = new(0xFF00897B);\n            public static readonly Color Darken2 = new(0xFF00796B);\n            public static readonly Color Darken3 = new(0xFF00695C);\n            public static readonly Color Darken4 = new(0xFF004D40);\n            \n            public static readonly Color Accent1 = new(0xFFA7FFEB);\n            public static readonly Color Accent2 = new(0xFF64FFDA);\n            public static readonly Color Accent3 = new(0xFF1DE9B6);\n            public static readonly Color Accent4 = new(0xFF00BFA5);\n        }\n\n        public static class Green\n        {\n            public static readonly Color Lighten5 = new(0xFFE8F5E9);\n            public static readonly Color Lighten4 = new(0xFFC8E6C9);\n            public static readonly Color Lighten3 = new(0xFFA5D6A7);\n            public static readonly Color Lighten2 = new(0xFF81C784);\n            public static readonly Color Lighten1 = new(0xFF66BB6A);\n            \n            public static readonly Color Medium = new(0xFF4CAF50);\n            \n            public static readonly Color Darken1 = new(0xFF43A047);\n            public static readonly Color Darken2 = new(0xFF388E3C);\n            public static readonly Color Darken3 = new(0xFF2E7D32);\n            public static readonly Color Darken4 = new(0xFF1B5E20);\n            \n            public static readonly Color Accent1 = new(0xFFB9F6CA);\n            public static readonly Color Accent2 = new(0xFF69F0AE);\n            public static readonly Color Accent3 = new(0xFF00E676);\n            public static readonly Color Accent4 = new(0xFF00C853);\n        }\n\n        public static class LightGreen\n        {\n            public static readonly Color Lighten5 = new(0xFFF1F8E9);\n            public static readonly Color Lighten4 = new(0xFFDCEDC8);\n            public static readonly Color Lighten3 = new(0xFFC5E1A5);\n            public static readonly Color Lighten2 = new(0xFFAED581);\n            public static readonly Color Lighten1 = new(0xFF9CCC65);\n            \n            public static readonly Color Medium = new(0xFF8BC34A);\n            \n            public static readonly Color Darken1 = new(0xFF7CB342);\n            public static readonly Color Darken2 = new(0xFF689F38);\n            public static readonly Color Darken3 = new(0xFF558B2F);\n            public static readonly Color Darken4 = new(0xFF33691E);\n            \n            public static readonly Color Accent1 = new(0xFFCCFF90);\n            public static readonly Color Accent2 = new(0xFFB2FF59);\n            public static readonly Color Accent3 = new(0xFF76FF03);\n            public static readonly Color Accent4 = new(0xFF64DD17);\n        }\n\n        public static class Lime\n        {\n            public static readonly Color Lighten5 = new(0xFFF9FBE7);\n            public static readonly Color Lighten4 = new(0xFFF0F4C3);\n            public static readonly Color Lighten3 = new(0xFFE6EE9C);\n            public static readonly Color Lighten2 = new(0xFFDCE775);\n            public static readonly Color Lighten1 = new(0xFFD4E157);\n            \n            public static readonly Color Medium = new(0xFFCDDC39);\n            \n            public static readonly Color Darken1 = new(0xFFC0CA33);\n            public static readonly Color Darken2 = new(0xFFAFB42B);\n            public static readonly Color Darken3 = new(0xFF9E9D24);\n            public static readonly Color Darken4 = new(0xFF827717);\n            \n            public static readonly Color Accent1 = new(0xFFF4FF81);\n            public static readonly Color Accent2 = new(0xFFEEFF41);\n            public static readonly Color Accent3 = new(0xFFC6FF00);\n            public static readonly Color Accent4 = new(0xFFAEEA00);\n        }\n\n        public static class Yellow\n        {\n            public static readonly Color Lighten5 = new(0xFFFFFDE7);\n            public static readonly Color Lighten4 = new(0xFFFFF9C4);\n            public static readonly Color Lighten3 = new(0xFFFFF59D);\n            public static readonly Color Lighten2 = new(0xFFFFF176);\n            public static readonly Color Lighten1 = new(0xFFFFEE58);\n            \n            public static readonly Color Medium = new(0xFFFFEB3B);\n            \n            public static readonly Color Darken1 = new(0xFFFDD835);\n            public static readonly Color Darken2 = new(0xFFFBC02D);\n            public static readonly Color Darken3 = new(0xFFF9A825);\n            public static readonly Color Darken4 = new(0xFFF57F17);\n            \n            public static readonly Color Accent1 = new(0xFFFFFF8D);\n            public static readonly Color Accent2 = new(0xFFFFFF00);\n            public static readonly Color Accent3 = new(0xFFFFEA00);\n            public static readonly Color Accent4 = new(0xFFFFD600);\n        }\n\n        public static class Amber\n        {\n            public static readonly Color Lighten5 = new(0xFFFFF8E1);\n            public static readonly Color Lighten4 = new(0xFFFFECB3);\n            public static readonly Color Lighten3 = new(0xFFFFE082);\n            public static readonly Color Lighten2 = new(0xFFFFD54F);\n            public static readonly Color Lighten1 = new(0xFFFFCA28);\n            \n            public static readonly Color Medium = new(0xFFFFC107);\n            \n            public static readonly Color Darken1 = new(0xFFFFB300);\n            public static readonly Color Darken2 = new(0xFFFFA000);\n            public static readonly Color Darken3 = new(0xFFFF8F00);\n            public static readonly Color Darken4 = new(0xFFFF6F00);\n            \n            public static readonly Color Accent1 = new(0xFFFFE57F);\n            public static readonly Color Accent2 = new(0xFFFFD740);\n            public static readonly Color Accent3 = new(0xFFFFC400);\n            public static readonly Color Accent4 = new(0xFFFFAB00);\n        }\n\n        public static class Orange\n        {\n            public static readonly Color Lighten5 = new(0xFFFFF3E0);\n            public static readonly Color Lighten4 = new(0xFFFFE0B2);\n            public static readonly Color Lighten3 = new(0xFFFFCC80);\n            public static readonly Color Lighten2 = new(0xFFFFB74D);\n            public static readonly Color Lighten1 = new(0xFFFFA726);\n            \n            public static readonly Color Medium = new(0xFFFF9800);\n            \n            public static readonly Color Darken1 = new(0xFFFB8C00);\n            public static readonly Color Darken2 = new(0xFFF57C00);\n            public static readonly Color Darken3 = new(0xFFEF6C00);\n            public static readonly Color Darken4 = new(0xFFE65100);\n            \n            public static readonly Color Accent1 = new(0xFFFFD180);\n            public static readonly Color Accent2 = new(0xFFFFAB40);\n            public static readonly Color Accent3 = new(0xFFFF9100);\n            public static readonly Color Accent4 = new(0xFFFF6D00);\n        }\n\n        public static class DeepOrange\n        {\n            public static readonly Color Lighten5 = new(0xFFFBE9E7);\n            public static readonly Color Lighten4 = new(0xFFFFCCBC);\n            public static readonly Color Lighten3 = new(0xFFFFAB91);\n            public static readonly Color Lighten2 = new(0xFFFF8A65);\n            public static readonly Color Lighten1 = new(0xFFFF7043);\n            \n            public static readonly Color Medium = new(0xFFFF5722);\n            \n            public static readonly Color Darken1 = new(0xFFF4511E);\n            public static readonly Color Darken2 = new(0xFFE64A19);\n            public static readonly Color Darken3 = new(0xFFD84315);\n            public static readonly Color Darken4 = new(0xFFBF360C);\n            \n            public static readonly Color Accent1 = new(0xFFFF9E80);\n            public static readonly Color Accent2 = new(0xFFFF6E40);\n            public static readonly Color Accent3 = new(0xFFFF3D00);\n            public static readonly Color Accent4 = new(0xFFDD2C00);\n        }\n\n        public static class Brown\n        {\n            public static readonly Color Lighten5 = new(0xFFEFEBE9);\n            public static readonly Color Lighten4 = new(0xFFD7CCC8);\n            public static readonly Color Lighten3 = new(0xFFBCAAA4);\n            public static readonly Color Lighten2 = new(0xFFA1887F);\n            public static readonly Color Lighten1 = new(0xFF8D6E63);\n            \n            public static readonly Color Medium = new(0xFF795548);\n            \n            public static readonly Color Darken1 = new(0xFF6D4C41);\n            public static readonly Color Darken2 = new(0xFF5D4037);\n            public static readonly Color Darken3 = new(0xFF4E342E);\n            public static readonly Color Darken4 = new(0xFF3E2723);\n        }\n\n        public static class Grey\n        {\n            public static readonly Color Lighten5 = new(0xFFFAFAFA);\n            public static readonly Color Lighten4 = new(0xFFF5F5F5);\n            public static readonly Color Lighten3 = new(0xFFEEEEEE);\n            public static readonly Color Lighten2 = new(0xFFE0E0E0);\n            public static readonly Color Lighten1 = new(0xFFBDBDBD);\n            \n            public static readonly Color Medium = new(0xFF9E9E9E);\n            \n            public static readonly Color Darken1 = new(0xFF757575);\n            public static readonly Color Darken2 = new(0xFF616161);\n            public static readonly Color Darken3 = new(0xFF424242);\n            public static readonly Color Darken4 = new(0xFF212121);\n        }\n\n        public static class BlueGrey\n        {\n            public static readonly Color Lighten5 = new(0xFFECEFF1);\n            public static readonly Color Lighten4 = new(0xFFCFD8DC);\n            public static readonly Color Lighten3 = new(0xFFB0BEC5);\n            public static readonly Color Lighten2 = new(0xFF90A4AE);\n            public static readonly Color Lighten1 = new(0xFF78909C);\n            \n            public static readonly Color Medium = new(0xFF607D8B);\n            \n            public static readonly Color Darken1 = new(0xFF546E7A);\n            public static readonly Color Darken2 = new(0xFF455A64);\n            public static readonly Color Darken3 = new(0xFF37474F);\n            public static readonly Color Darken4 = new(0xFF263238);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/FontFeatures.cs",
    "content": "using System;\n\n#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member\n\nnamespace QuestPDF.Helpers;\n\npublic static class FontFeatures\n{\n    public const string AccessAllAlternates = \"aalt\";\n    public const string AboveBaseForms = \"abvf\";\n    public const string AboveBaseMarkPositioning = \"abvm\";\n    public const string AboveBaseSubstitutions = \"abvs\";\n    public const string AlternativeFractions = \"afrc\";\n    public const string Akhand = \"akhn\";\n    public const string KerningForAlternateProportionalWidths = \"apkn\";\n    public const string BelowBaseForms = \"blwf\";\n    public const string BelowBaseMarkPositioning = \"blwm\";\n    public const string BelowBaseSubstitutions = \"blws\";\n    public const string ContextualAlternates = \"calt\";\n    public const string CaseSensitiveForms = \"case\";\n    public const string GlyphCompositionDecomposition = \"ccmp\";\n    public const string ConjunctFormAfterRo = \"cfar\";\n    public const string ContextualHalfWidthSpacing = \"chws\";\n    public const string ConjunctForms = \"cjct\";\n    public const string ContextualLigatures = \"clig\";\n    public const string CenteredCjkPunctuation = \"cpct\";\n    public const string CapitalSpacing = \"cpsp\";\n    public const string ContextualSwash = \"cswh\";\n    public const string CursivePositioning = \"curs\";\n    public const string PetiteCapitalsFromCapitals = \"c2pc\";\n    public const string SmallCapitalsFromCapitals = \"c2sc\";\n    public const string Distances = \"dist\";\n    public const string DiscretionaryLigatures = \"dlig\";\n    public const string Denominators = \"dnom\";\n    public const string DotlessForms = \"dtls\";\n    public const string ExpertForms = \"expt\";\n    public const string FinalGlyphOnLineAlternates = \"falt\";\n    public const string TerminalForms2 = \"fin2\";\n    public const string TerminalForms3 = \"fin3\";\n    public const string TerminalForms = \"fina\";\n    public const string FlattenedAccentForms = \"flac\";\n    public const string Fractions = \"frac\";\n    public const string FullWidths = \"fwid\";\n    public const string HalfForms = \"half\";\n    public const string HalantForms = \"haln\";\n    public const string AlternateHalfWidths = \"halt\";\n    public const string HistoricalForms = \"hist\";\n    public const string HorizontalKanaAlternates = \"hkna\";\n    public const string HistoricalLigatures = \"hlig\";\n    public const string Hangul = \"hngl\";\n    public const string HalfWidths = \"hwid\";\n    public const string InitialForms = \"init\";\n    public const string IsolatedForms = \"isol\";\n    public const string Italics = \"ital\";\n    public const string JustificationAlternates = \"jalt\";\n    public const string JIS78Forms = \"jp78\";\n    public const string JIS83Forms = \"jp83\";\n    public const string JIS90Forms = \"jp90\";\n    public const string JIS2004Forms = \"jp04\";\n    public const string Kerning = \"kern\";\n    public const string LeftBounds = \"lfbd\";\n    public const string StandardLigatures = \"liga\";\n    public const string LeadingJamoForms = \"ljmo\";\n    public const string LiningFigures = \"lnum\";\n    public const string LocalizedForms = \"locl\";\n    public const string LeftToRightAlternates = \"ltra\";\n    public const string LeftToRightMirroredForms = \"ltrm\";\n    public const string MarkPositioning = \"mark\";\n    public const string MedialForms2 = \"med2\";\n    public const string MedialForms = \"medi\";\n    public const string MathematicalGreek = \"mgrk\";\n    public const string MarkToMarkPositioning = \"mkmk\";\n    public const string MarkPositioningViaSubstitution = \"mset\";\n    public const string AlternateAnnotationForms = \"nalt\";\n    public const string NlcKanjiForms = \"nlck\";\n    public const string NuktaForms = \"nukt\";\n    public const string Numerators = \"numr\";\n    public const string OldstyleFigures = \"onum\";\n    public const string OpticalBounds = \"opbd\";\n    public const string Ordinals = \"ordn\";\n    public const string Ornaments = \"ornm\";\n    public const string ProportionalAlternateWidths = \"palt\";\n    public const string PetiteCapitals = \"pcap\";\n    public const string ProportionalKana = \"pkna\";\n    public const string ProportionalFigures = \"pnum\";\n    public const string PreBaseForms = \"pref\";\n    public const string PreBaseSubstitutions = \"pres\";\n    public const string PostBaseForms = \"pstf\";\n    public const string PostBaseSubstitutions = \"psts\";\n    public const string ProportionalWidths = \"pwid\";\n    public const string QuarterWidths = \"qwid\";\n    public const string Randomize = \"rand\";\n    public const string RequiredContextualAlternates = \"rclt\";\n    public const string RakarForms = \"rkrf\";\n    public const string RequiredLigatures = \"rlig\";\n    public const string RephForm = \"rphf\";\n    public const string RightBounds = \"rtbd\";\n    public const string RightToLeftAlternates = \"rtla\";\n    public const string RightToLeftMirroredForms = \"rtlm\";\n    public const string RubyNotationForms = \"ruby\";\n    public const string RequiredVariationAlternates = \"rvrn\";\n    public const string StylisticAlternates = \"salt\";\n    public const string ScientificInferiors = \"sinf\";\n    public const string OpticalSize = \"size\";\n    public const string SmallCapitals = \"smcp\";\n    public const string SimplifiedForms = \"smpl\";\n    public const string MathScriptStyleAlternates = \"ssty\";\n    public const string StretchingGlyphDecomposition = \"stch\";\n    public const string Subscript = \"subs\";\n    public const string Superscript = \"sups\";\n    public const string Swash = \"swsh\";\n    public const string Titling = \"titl\";\n    public const string TrailingJamoForms = \"tjmo\";\n    public const string TraditionalNameForms = \"tnam\";\n    public const string TabularFigures = \"tnum\";\n    public const string TraditionalForms = \"trad\";\n    public const string ThirdWidths = \"twid\";\n    public const string Unicase = \"unic\";\n    public const string AlternateVerticalMetrics = \"valt\";\n    public const string KerningForAlternateProportionalVerticalMetrics = \"vapk\";\n    public const string VattuVariants = \"vatu\";\n    public const string VerticalContextualHalfWidthSpacing = \"vchw\";\n    public const string VerticalAlternates = \"vert\";\n    public const string AlternateVerticalHalfMetrics = \"vhal\";\n    public const string VowelJamoForms = \"vjmo\";\n    public const string VerticalKanaAlternates = \"vkna\";\n    public const string VerticalKerning = \"vkrn\";\n    public const string ProportionalAlternateVerticalMetrics = \"vpal\";\n    public const string VerticalAlternatesAndRotation = \"vrt2\";\n    public const string VerticalAlternatesForRotation = \"vrtr\";\n    public const string SlashedZero = \"zero\";\n\n    /// <summary>\n    /// (JIS X 0212-1990 Kanji Forms)\n    /// </summary>\n    public const string HojoKanjiForms  = \"hojo\";\n    \n    public static string CharacterVariant(int value)\n    {\n        if (value < 1 || value > 99)\n            throw new ArgumentOutOfRangeException(nameof(value), \"Character Variant value must be between 1 and 99.\");\n        \n        return $\"cv{value:00}\";\n    }\n    \n    public static string StylisticSet(int value)\n    {\n        if (value < 1 || value > 20)\n            throw new ArgumentOutOfRangeException(nameof(value), \"Character Variant value must be between 1 and 20.\");\n        \n        return $\"ss{value:00}\";\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/Fonts.cs",
    "content": "﻿#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member\n\nnamespace QuestPDF.Helpers\n{\n    /// <summary>\n    /// Contains a collection of fonts defined by the PDF standard.\n    /// </summary>\n    public static class Fonts\n    {\n        public const string Arial = \"Arial\";\n        public const string Calibri = \"Calibri\";\n        public const string Cambria = \"Cambria\";\n        public const string Candara = \"Candara\";\n        public const string ComicSans = \"Comic Sans MS\";\n        public const string Consolas = \"Consolas\";\n        public const string Corbel = \"Corbel\";\n        public const string Courier = \"Courier\";\n        public const string CourierNew = \"Courier New\";\n        public const string Georgia = \"Georgia\";\n        public const string Impact = \"Impact\";\n        public const string Lato = \"Lato\";\n        public const string LucidaConsole = \"Lucida Console\";\n        public const string SegoeSD = \"Segoe SD\";\n        public const string SegoeUI = \"Segoe UI\";\n        public const string Tahoma = \"Tahoma\";\n        public const string TimesNewRoman = \"Times New Roman\";\n        public const string TimesRoman = \"Times Roman\";\n        public const string Trebuchet = \"Trebuchet MS\";\n        public const string Verdana = \"Verdana\";\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/Helpers.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing System.Text.RegularExpressions;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing static QuestPDF.Skia.SkSvgImageSize.Unit;\n\nnamespace QuestPDF.Helpers\n{\n    internal static class Helpers\n    {\n        static Helpers()\n        {\n            SkNativeDependencyCompatibilityChecker.Test();\n        }\n        \n        internal static string PrettifyName(this string text)\n        {\n            return Regex.Replace(text, @\"([a-z])([A-Z])\", \"$1 $2\", RegexOptions.Compiled);\n        }\n\n        internal static void VisitChildren(this Element? root, Action<Element?> handler)\n        {\n            Traverse(root);\n\n            void Traverse(Element? element)\n            {\n                if (element == null)\n                    return;\n                \n                if (element is ContainerElement containerElement)\n                {\n                    Traverse(containerElement.Child);\n                }\n                else\n                {\n                    foreach (var child in element.GetChildren())\n                        Traverse(child);  \n                }\n            \n                handler(element);\n            }\n        }\n\n        internal static void ReleaseDisposableChildren(this Element? element)\n        {\n            element.VisitChildren(x => (x as IDisposable)?.Dispose());\n        }\n        \n        internal static bool IsGreaterThan(this float first, float second)\n        {\n            return first > second + Size.Epsilon;\n        }\n        \n        internal static bool IsLessThan(this float first, float second)\n        {\n            return first < second - Size.Epsilon;\n        }\n        \n        public static bool AreClose(double a, double b)\n        {\n            return Math.Abs(a - b) <= Size.Epsilon;\n        }\n\n        internal static bool IsNegative(this Size size)\n        {\n            return size.Width < -Size.Epsilon || size.Height < -Size.Epsilon;\n        }\n        \n        internal static bool IsCloseToZero(this Size size)\n        {\n            return Math.Abs(size.Width) < Size.Epsilon && Math.Abs(size.Height) < Size.Epsilon;\n        }\n\n        internal static bool IsEmpty(this Element element)\n        {\n            return element.Measure(Size.Zero).Type == SpacePlanType.Empty;\n        }\n        \n        internal static int ToQualityValue(this ImageCompressionQuality quality)\n        {\n            return quality switch\n            {\n                ImageCompressionQuality.Best => 100,\n                ImageCompressionQuality.VeryHigh => 90,\n                ImageCompressionQuality.High => 75,\n                ImageCompressionQuality.Medium => 50,\n                ImageCompressionQuality.Low => 25,\n                ImageCompressionQuality.VeryLow => 10,\n                _ => throw new ArgumentOutOfRangeException(nameof(quality), quality, null)\n            };\n        }\n        \n        internal static bool ToDownsamplingStrategy(this ImageCompressionQuality quality)\n        {\n            return quality switch\n            {\n                ImageCompressionQuality.Best => false,\n                ImageCompressionQuality.VeryHigh => false,\n                ImageCompressionQuality.High => true,\n                ImageCompressionQuality.Medium => true,\n                ImageCompressionQuality.Low => true,\n                ImageCompressionQuality.VeryLow => true,\n                _ => throw new ArgumentOutOfRangeException(nameof(quality), quality, null)\n            };\n        }\n        \n        internal static SkImage CompressImage(this SkImage image, ImageCompressionQuality compressionQuality)\n        {\n            return image.ResizeAndCompress(image.Width, image.Height, compressionQuality.ToQualityValue(), compressionQuality.ToDownsamplingStrategy());\n        }\n\n        internal static SkImage ResizeAndCompressImage(this SkImage image, ImageSize targetResolution, ImageCompressionQuality compressionQuality)\n        {\n            if (targetResolution.Width == 0 || targetResolution.Height == 0)\n                targetResolution = new ImageSize(1, 1);\n            \n            return image.ResizeAndCompress(targetResolution.Width, targetResolution.Height, compressionQuality.ToQualityValue(), compressionQuality.ToDownsamplingStrategy());\n        }\n\n        internal static SkImage GetImageWithSmallerSize(SkImage one, SkImage second)\n        {\n            return one.EncodedDataSize < second.EncodedDataSize\n                ? one\n                : second;\n        }\n        \n        internal static void OpenFileUsingDefaultProgram(string filePath)\n        {\n            var process = new Process\n            {\n                StartInfo = new ProcessStartInfo(filePath)\n                {\n                    UseShellExecute = true\n                }\n            };\n\n            process.Start();\n            process.WaitForExit();\n        }\n\n        internal static string ApplicationFilesPath\n        {\n            get\n            {\n                var baseDirectory = AppContext.BaseDirectory;\n\n                if (string.IsNullOrWhiteSpace(baseDirectory) || baseDirectory == \"/\")\n                    return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n\n                return baseDirectory;\n            }\n        }\n        \n        internal static (float widthScale, float heightScale) CalculateSpaceScale(this SkSvgImage image, Size availableSpace)\n        {\n            var widthScale = CalculateDimensionScale(availableSpace.Width, image.Size.Width, image.Size.WidthUnit);\n            var heightScale = CalculateDimensionScale(availableSpace.Height, image.Size.Height, image.Size.HeightUnit);\n\n            return (widthScale, heightScale);\n        \n            float CalculateDimensionScale(float availableSize, float imageSize, SkSvgImageSize.Unit unit)\n            {\n                if (unit == Percentage)\n                    return 1;\n\n                if (unit is Centimeters or Millimeters or Inches or Points or Picas)\n                    return availableSize / ConvertToPoints(imageSize, unit);   \n            \n                return availableSize / imageSize;\n            }\n        \n            float ConvertToPoints(float value, SkSvgImageSize.Unit unit)\n            {\n                const float inchToCentimetre = 2.54f;\n                const float inchToPoints = 72;\n        \n                var points =  unit switch\n                {\n                    Centimeters => value / inchToCentimetre * inchToPoints,\n                    Millimeters => value / 10 / inchToCentimetre * inchToPoints,\n                    Inches => value * inchToPoints,\n                    Points => value,\n                    Picas => value * 12,\n                    _ => throw new ArgumentOutOfRangeException()\n                };\n        \n                // different naming schema: SVG pixel = PDF point\n                return points * GetScalingFactor();\n            }\n\n            float GetScalingFactor()\n            {\n                // in CSS dpi is set to 96, but Skia uses more traditional 90\n                // when the SVG ViewBox attribute is present, Skia uses legacy/traditional 90 DPI\n                // otherwise, we should assume modern CSS-based 96 DPI for better compatibility\n                var targetDpi = HasViewBox() ? 90f : 96f;\n                return targetDpi / 72;\n            }\n\n            bool HasViewBox()\n            {\n                return image.ViewBox is not\n                {\n                    Left : 0f, \n                    Top : 0f, \n                    Width : 0f, \n                    Height : 0f\n                };\n            }\n        }\n\n        public static string FormatAsCompanionNumber(this float value)\n        {\n            return value.ToString(\"0.#\", CultureInfo.InvariantCulture);\n        }\n        \n        public static bool Is<T>(this IDrawingCanvas canvas) where T : IDrawingCanvas\n        {\n            var canvasUnderTest = canvas;\n\n            while (canvasUnderTest is ProxyDrawingCanvas proxy)\n                canvasUnderTest = proxy.Target;\n\n            return canvasUnderTest is T;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/IsExternalInit.cs",
    "content": "// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\nusing System.ComponentModel;\n\nnamespace System.Runtime.CompilerServices\n{\n    /// <summary>\n    /// Reserved to be used by the compiler for tracking metadata.\n    /// This class should not be used by developers in source code.\n    /// </summary>\n    [EditorBrowsable(EditorBrowsableState.Never)]\n    internal static class IsExternalInit\n    {\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/LicenseChecker.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Helpers;\n\nstatic class LicenseChecker\n{\n    private static bool IsLicenseValidated { get; set; } = false; \n    \n    public static void ValidateLicense()\n    {\n        if (IsLicenseValidated)\n            return;\n        \n        if (Settings.License == LicenseType.Evaluation)\n            PrintLicenseEvaluationWarning();\n        \n        if (Settings.License is null)\n            ThrowExceptionWithWelcomeMessage();\n        \n        IsLicenseValidated = true;\n    }\n\n    private static void PrintLicenseEvaluationWarning()\n    {\n        var warningMessage =\n            \"[QuestPDF] The library is running in Evaluation Mode. \" +\n            \"This mode is fully functional and intended only for product evaluation and internal testing. \" +\n            \"Commercial and production use requires an appropriate license. \" +\n            \"For licensing details and pricing, please visit: https://www.questpdf.com/license\";\n\n        try\n        {\n            if (TraceHasListeners())\n                Trace.TraceWarning(warningMessage);\n            \n            else\n                Console.WriteLine($\"\\n{warningMessage}\\n\");\n        }\n        catch\n        {\n            \n        }\n    }\n\n    private static bool TraceHasListeners()\n    {\n        if (Trace.Listeners.Count == 0)\n            return false;\n        \n        if (Trace.Listeners.Count == 1 && Trace.Listeners[0] is DefaultTraceListener)\n            return false;\n        \n        return true;\n    }\n    \n    private static void ThrowExceptionWithWelcomeMessage()\n    {\n        const string newParagraph = \"\\n\\n\";\n\n        var exceptionMessage = \n            $\"{newParagraph}{newParagraph}Thank you for choosing QuestPDF 👋{newParagraph}\" +\n            $\"Before you continue, please take a moment to configure your license. This step helps ensure correct license compliance.{newParagraph}\" +\n            $\"QuestPDF requires a Commercial License for production use by organizations with more than $1M USD in annual gross revenue. \" +\n            $\"Individuals, non-profits, open-source projects, and smaller companies qualify for the free Community license.{newParagraph}\" +\n            $\"If you are not the decision-maker for software purchases, please share the licensing and pricing details with your team lead or manager: https://www.questpdf.com/license {newParagraph}\" +\n            $\"Available license options:\\n\" +\n            $\"- Community: free,\\n\" +\n            $\"- Evaluation: intended solely for evaluation before choosing an appropriate license; not suitable for production use,\\n\" +\n            $\"- Professional: paid, for teams up to 10 developers with dedicated support,\\n\" +\n            $\"- Enterprise: paid, for unlimited developers with prioritized dedicated support.{newParagraph}\" +\n            $\"Set the license once at application startup. By doing so, you confirm that the selected tier matches your usage:\\n\" +\n            $\"> QuestPDF.Settings.License = LicenseType.Evaluation; // or Community / Professional / Enterprise{newParagraph}\" +\n            $\"No license key or activation is required — we trust you to select the correct option. \" +\n            $\"By choosing the right license, you help ensure QuestPDF remains sustainable and continuously improving for everyone. {newParagraph}\" +\n            $\"We wish you a great experience! 🚀{newParagraph}{newParagraph}\";\n\n        throw new Exception(exceptionMessage)\n        {\n            HelpLink = \"https://www.questpdf.com/license\"\n        };\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/NativeDependencyCompatibilityChecker.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Helpers\n{\n    internal sealed class NativeDependencyCompatibilityChecker\n    {\n        private static readonly Version RequiredGlibcVersionOnLinux = Version.Parse(\"2.29\");\n        \n        private bool IsCompatibilityChecked { get; set; } = false;\n\n        public Action ExecuteNativeCode { get; set; } = () => { };\n        public Func<bool> CheckNativeLibraryVersion { get; set; } = () => true;\n        public Func<string> ExceptionHint { get; set; } = () => string.Empty;\n        \n        public void Test()\n        {\n            if (IsCompatibilityChecked)\n                return;\n\n            TestOnce();\n            IsCompatibilityChecked = true;\n        }\n        \n        private void TestOnce()\n        {\n            if (IsCompatibilityChecked)\n                return;\n            \n            const string exceptionBaseMessage = \"The QuestPDF library has encountered an issue while loading one of its dependencies.\";\n            const string paragraph = \"\\n\\n\";\n                \n            // test with dotnet-based mechanism where native files are provided\n            // in the \"runtimes/{rid}/native\" folder on Core, or by the targets file on .NET Framework\n            var innerException = CheckIfExceptionIsThrownWhenLoadingNativeDependencies();\n\n            if (innerException == null)\n            {\n                EnsureNativeVersionCompatibility();\n                return;\n            }\n\n            if (!NativeDependencyProvider.IsCurrentPlatformSupported())\n                ThrowCompatibilityException(innerException);\n            \n            // detect platform, copy appropriate native files and test compatibility again\n            NativeDependencyProvider.EnsureNativeFileAvailability();\n            \n            innerException = CheckIfExceptionIsThrownWhenLoadingNativeDependencies();\n\n            if (innerException == null)\n            {\n                EnsureNativeVersionCompatibility();\n                return;\n            }\n\n            ThrowCompatibilityException(innerException);\n            \n            void ThrowCompatibilityException(Exception innerException)\n            {\n                var supportedRuntimes = string.Join(\", \", NativeDependencyProvider.SupportedPlatforms);\n                var currentRuntime = NativeDependencyProvider.GetRuntimePlatform();\n                var isRuntimeSupported = NativeDependencyProvider.SupportedPlatforms.Contains(currentRuntime);\n\n                var message = $\"{exceptionBaseMessage}\";\n                \n                if (!isRuntimeSupported)\n                {\n                    message += $\"{paragraph}Your runtime is not supported by QuestPDF. \" +\n                                $\"The following runtimes are supported: {supportedRuntimes}. \" +\n                                $\"Your current runtime is detected as '{currentRuntime}'. \";\n                }\n                \n                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                    message += $\"{paragraph}Please always set the 'Platform target' to either 'X86' or 'X64' in your startup project settings. Please do not use the 'Any CPU' option.\";\n                \n                if (RuntimeInformation.ProcessArchitecture is Architecture.Arm)\n                    message += $\"{paragraph}Please consider setting the 'Platform target' property to 'Arm64' in your project settings.\";\n\n                var hint = ExceptionHint.Invoke();\n                \n                if (!string.IsNullOrEmpty(hint))\n                    message += $\"{paragraph}{hint}\";\n\n                if (isRuntimeSupported)\n                {\n                    var glibcVersion = NativeDependencyProvider.GetGlibcVersion();\n\n                    if (glibcVersion != null && glibcVersion < RequiredGlibcVersionOnLinux)\n                    {\n                        message += $\"{paragraph}Please consider updating your operating system distribution. \" +\n                                   $\"Current GLIBC version: {glibcVersion}. \" +\n                                   $\"The minimum required version is {RequiredGlibcVersionOnLinux}. \";\n                    }\n                    else\n                    {\n                        message += $\"{paragraph}If the problem persists, it may mean that your current operating system distribution is outdated. For optimal compatibility, please consider updating it to a more recent version.\";\n                    }\n                }\n                \n                throw new Exception(message, innerException);\n            }\n\n            void EnsureNativeVersionCompatibility()\n            {\n                if (!CheckNativeLibraryVersion())\n                    throw new Exception($\"{exceptionBaseMessage}{paragraph}The loaded native library version is incompatible with the current QuestPDF version. To resolve this issue, please: 1) Clean and rebuild your solution, 2) Remove the bin and obj folders, and 3) Ensure all projects in your solution use the same QuestPDF NuGet package version.\");\n            }\n        }\n    \n        private Exception? CheckIfExceptionIsThrownWhenLoadingNativeDependencies()\n        {\n            try\n            {\n                ExecuteNativeCode();\n                return null;\n            }\n            catch (Exception exception)\n            {\n                return exception;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Helpers/NativeDependencyProvider.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text.RegularExpressions;\n\nnamespace QuestPDF.Helpers;\n\ninternal static class NativeDependencyProvider\n{\n    public static readonly string[] SupportedPlatforms =\n    {\n        \"win-x86\",\n        \"win-x64\",\n        \"linux-x64\",\n        \"linux-arm64\",\n        \"linux-musl-x64\",\n        \"osx-x64\",\n        \"osx-arm64\"\n    };\n    \n    public static void EnsureNativeFileAvailability()\n    {\n        var nativeFilesPath = GetNativeFileSourcePath();\n        \n        if (nativeFilesPath == null)\n            return;\n\n        foreach (var nativeFilePath in Directory.GetFiles(nativeFilesPath))\n        {\n            var targetDirectory = new FileInfo(nativeFilePath)\n                .Directory\n                .Parent // native\n                .Parent // platform\n                .Parent // runtimes\n                .FullName;\n            \n            var targetPath = Path.Combine(targetDirectory, Path.GetFileName(nativeFilePath));\n            CopyFileIfNewer(nativeFilePath, targetPath);\n        }\n    }\n    \n    public static bool IsCurrentPlatformSupported()\n    {\n        var currentRuntime = GetRuntimePlatform();\n        return SupportedPlatforms.Contains(currentRuntime);\n    }\n    \n    static string? GetNativeFileSourcePath()\n    {\n        var platform = GetRuntimePlatform();\n\n        var availableLocations = new[]\n        {\n            AppDomain.CurrentDomain.RelativeSearchPath, \n            AppDomain.CurrentDomain.BaseDirectory,\n            Environment.CurrentDirectory,\n            AppContext.BaseDirectory,\n            Directory.GetCurrentDirectory(),\n            new FileInfo(typeof(NativeDependencyProvider).Assembly.Location).Directory?.FullName\n        };\n        \n        foreach (var location in availableLocations)\n        {\n            if (string.IsNullOrEmpty(location))\n                continue;\n\n            var nativeFileSourcePath = Path.Combine(location, \"runtimes\", platform, \"native\");\n\n            if (Directory.Exists(nativeFileSourcePath))\n                return nativeFileSourcePath;\n        }\n\n        return null;\n    }\n        \n    public static string GetRuntimePlatform()\n    {\n#if NET6_0_OR_GREATER\n        if (RuntimeInformation.ProcessArchitecture == Architecture.Wasm)\n            return \"browser-wasm\";\n#endif\n        \n        return $\"{GetSystemIdentifier()}-{GetProcessArchitecture()}\";\n\n        static string GetSystemIdentifier()\n        {\n            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                return \"win\";\n                \n            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\n                return IsLinuxMusl() ? \"linux-musl\" : \"linux\";\n                \n            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\n                return \"osx\";\n\n            return \"other\";\n        }\n\n        static string GetProcessArchitecture()\n        {\n            return RuntimeInformation.ProcessArchitecture.ToString().ToLower();\n        }\n    }\n    \n    private static string? ExecuteLddCommand()\n    {\n        if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\n            return null;\n        \n        try\n        {\n            var processStartInfo = new ProcessStartInfo\n            {\n                FileName = \"ldd\",\n                Arguments = \"--version\",\n                RedirectStandardOutput = true,\n                RedirectStandardError = true,\n                UseShellExecute = false,\n                CreateNoWindow = true\n            };\n                \n            using var process = Process.Start(processStartInfo);\n                \n            if (process == null)\n                return null;\n                \n            var standardOutputText = process.StandardOutput.ReadToEnd();\n            var standardErrorText = process.StandardError.ReadToEnd();\n                \n            process.WaitForExit();\n                \n            return standardOutputText + standardErrorText;\n        }\n        catch\n        {\n            return null;\n        }\n    }\n\n    private static bool IsLinuxMusl()\n    {\n        var lddCommandOutput = ExecuteLddCommand() ?? string.Empty;\n        var containsMuslText = lddCommandOutput.IndexOf(\"musl\", StringComparison.InvariantCultureIgnoreCase) >= 0;\n        return containsMuslText;\n    }\n\n    public static Version? GetGlibcVersion()\n    {\n        var lddCommandOutput = ExecuteLddCommand() ?? string.Empty;\n        var match = Regex.Match(lddCommandOutput, @\"ldd \\(.+\\) (?<version>[1-9]\\.[0-9]{2})\");\n    \n        if (!match.Success)\n            return null;\n\n        var versionGroup = match.Groups[\"version\"];\n        \n        if (!versionGroup.Success)\n            return null;\n    \n        return Version.TryParse(versionGroup.Value, out var parsedVersion) ? parsedVersion : null;\n    }\n\n    private static void CopyFileIfNewer(string sourcePath, string targetPath)\n    {\n        if (!File.Exists(sourcePath))\n            throw new FileNotFoundException($\"Source file not found: {sourcePath}\");\n\n        if (!File.Exists(targetPath) || File.GetLastWriteTime(sourcePath) > File.GetLastWriteTime(targetPath))\n            File.Copy(sourcePath, targetPath, true);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/PageSizes.cs",
    "content": "﻿using System;\nusing QuestPDF.Infrastructure;\n\n#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member\n\nnamespace QuestPDF.Helpers\n{\n    /// <summary>\n    /// Defines the physical dimensions (width and height) of a page.\n    /// </summary>\n    /// <remarks>\n    /// <para>Commonly used page sizes are available in the <see cref=\"PageSizes\"/> class.</para>\n    /// <para>Change page orientation with the <see cref=\"PageSizeExtensions.Portrait\">Portrait</see> and <see cref=\"PageSizeExtensions.Landscape\">Landscape</see> extension methods.</para>\n    /// </remarks>\n    /// <example>\n    /// <c>PageSizes.A4.Landscape();</c>\n    /// </example>\n    public sealed class PageSize\n    {\n        public readonly float Width;\n        public readonly float Height;\n        \n        public PageSize(float width, float height, Unit unit = Unit.Point)\n        {\n            if (width < 0)\n                throw new ArgumentOutOfRangeException(nameof(width), \"Page width must be greater than 0.\");\n            \n            if (height < 0)\n                throw new ArgumentOutOfRangeException(nameof(height), \"Page height must be greater than 0.\");\n            \n            Width = width.ToPoints(unit);\n            Height = height.ToPoints(unit);\n        }\n\n        public static implicit operator Size(PageSize pageSize) => new Size(pageSize.Width, pageSize.Height);\n    }\n\n    /// <summary>\n    /// Contains a collection of predefined, common and standard page sizes, such as A4 with dimensions of 595 points in width and 842 points in height.\n    /// </summary>\n    public static class PageSizes\n    {\n        public const int PointsPerInch = 72;\n        \n        public static PageSize A0 { get; } = new(2384, 3370);\n        public static PageSize A1 { get; } = new(1684, 2384);\n        public static PageSize A2 { get; } = new(1191, 1684);\n        public static PageSize A3 { get; } = new(842, 1191);\n        public static PageSize A4 { get; } = new(595, 842);\n        public static PageSize A5 { get; } = new(420, 595);\n        public static PageSize A6 { get; } = new(298, 420);\n        public static PageSize A7 { get; } = new(210, 298);\n        public static PageSize A8 { get; } = new(147, 210);\n        public static PageSize A9 { get; } = new(105, 147);\n        public static PageSize A10 { get; } = new(74, 105);\n\n        public static PageSize B0 { get; } = new(2835, 4008);\n        public static PageSize B1 { get; } = new(2004, 2835);\n        public static PageSize B2 { get; } = new(1417, 2004);\n        public static PageSize B3 { get; } = new(1001, 1417);\n        public static PageSize B4 { get; } = new(709, 1001);\n        public static PageSize B5 { get; } = new(499, 709);\n        public static PageSize B6 { get; } = new(354, 499);\n        public static PageSize B7 { get; } = new(249, 354);\n        public static PageSize B8 { get; } = new(176, 249);\n        public static PageSize B9 { get; } = new(125, 176);\n        public static PageSize B10 { get; } = new(88, 125);\n\n        public static PageSize C0 { get; } = new(2599, 3677);\n        public static PageSize C1 { get; } = new(1837, 2599);\n        public static PageSize C2 { get; } = new(1298, 1837);\n        public static PageSize C3 { get; } = new(918, 1298);\n        public static PageSize C4 { get; } = new(649, 918);\n        public static PageSize C5 { get; } = new(459, 649);\n        public static PageSize C6 { get; } = new(323, 459);\n        public static PageSize C7 { get; } = new(230, 323);\n        public static PageSize C8 { get; } = new(162, 230);\n        public static PageSize C9 { get; } = new(113, 162);\n        public static PageSize C10 { get; } = new(79, 113);\n\n        public static PageSize Env10 { get; } = new(297, 684);\n        public static PageSize EnvC4 { get; } = new(649, 918);\n        public static PageSize EnvDL { get; } = new(312, 624);\n\n        public static PageSize Postcard { get; } = new(284, 419);\n        public static PageSize Executive { get; } = new(522, 756);\n        public static PageSize Letter { get; } = new(612, 792);\n        public static PageSize Legal { get; } = new(612, 1008);\n        public static PageSize Ledger { get; } = new(792, 1224);\n        public static PageSize Tabloid { get; } = new(1224, 792);\n\n        public static PageSize ARCH_A { get; } = new(648, 864);\n        public static PageSize ARCH_B { get; } = new(864, 1296);\n        public static PageSize ARCH_C { get; } = new(1296, 1728);\n        public static PageSize ARCH_D { get; } = new(1728, 2592);\n        public static PageSize ARCH_E { get; } = new(2592, 3456);\n        public static PageSize ARCH_E1 { get; } = new(2160, 3024);\n        public static PageSize ARCH_E2 { get; } = new(1872, 2736);\n        public static PageSize ARCH_E3 { get; } = new(1944, 2808);\n    }\n\n    public static class PageSizeExtensions\n    {\n        /// <summary>\n        /// Sets page size to a portrait orientation, making the width smaller than the height.\n        /// </summary>\n        public static PageSize Portrait(this PageSize size)\n        {\n            return new PageSize(Math.Min(size.Width, size.Height), Math.Max(size.Width, size.Height));\n        }\n\n        /// <summary>\n        /// Sets page size to a landscape orientation, making the width bigger than the height.\n        /// </summary>\n        public static PageSize Landscape(this PageSize size)\n        {\n            return new PageSize(Math.Max(size.Width, size.Height), Math.Min(size.Width, size.Height));\n        }\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Helpers/Placeholders.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Helpers\n{\n    public static class Placeholders\n    {\n        static Placeholders()\n        {\n            SkNativeDependencyCompatibilityChecker.Test();\n        }\n        \n        public static readonly Random Random = new Random();\n        \n        #region Word Cache\n\n        private const string CommonParagraph =\n            \"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod \" +\n            \"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim \" +\n            \"veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea \" +\n            \"commodo consequat. Duis aute irure dolor in reprehenderit in voluptate \" +\n            \"velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint \" +\n            \"occaecat cupidatat non proident, sunt in culpa qui officia deserunt \" +\n            \"mollit anim id est laborum.\";\n\n        private static readonly string[] LatinWords = LoadLatinWords();\n        \n        private static readonly string[] LongLatinWords = LatinWords.Where(x => x.Length > 8).ToArray();\n\n        private static string[] LoadLatinWords()\n        {\n            using var stream = Assembly\n                .GetExecutingAssembly()\n                .GetManifestResourceStream(\"QuestPDF.Resources.LatinWords.txt\");\n        \n            using var streamReader = new StreamReader(stream);\n            var text = streamReader.ReadToEnd();\n\n            return text.Split('\\n').ToArray();\n        }\n        \n        #endregion\n\n        #region Text\n\n        private static string RandomWord()\n        {\n            var index = Random.Next(0, LatinWords.Length);\n            return LatinWords[index];\n        }\n        \n        private static string LongRandomWord()\n        {\n            var index = Random.Next(0, LongLatinWords.Length);\n            return LongLatinWords[index];\n        }\n\n        private static string RandomWords(int min, int max)\n        {\n            var length = Random.Next(min, max + 1);\n\n            var words = Enumerable\n                .Range(0, length)\n                .Select(x => RandomWord());\n\n            return string.Join(\" \", words);\n        }\n\n        /// <summary>\n        /// Returns the commonly used 'Lorem ipsum dolor sit amet' placeholder text.\n        /// </summary>\n        public static string LoremIpsum()\n        {\n            return CommonParagraph;\n        }\n\n        /// <summary>\n        /// Generates a random text ideal for concise labels like product names.\n        /// </summary>\n        /// <example>\n        /// \"Beatae dolor\" <br />\n        /// \"Rerum quibusdam perspiciatis\" <br />\n        /// \"Fugiat aperiam officiis\"\n        /// </example>\n        public static string Label()\n        {\n            return RandomWords(2, 3).FirstCharToUpper();\n        }\n\n        /// <summary>\n        /// Generates random text ideal for single sentences, like product description.\n        /// </summary>\n        /// <example>\n        /// Vero a id optio consequuntur dignissimos repellendus provident blanditiis.\n        /// </example>\n        public static string Sentence()\n        {\n            return RandomWords(6, 12).FirstCharToUpper() + \".\";\n        }\n\n        /// <summary>\n        /// Generates random text formatted as a question.\n        /// </summary>\n        /// <example>\n        /// Sequi enim voluptas quasi modi aspernatur dolorem?\n        /// </example>\n        public static string Question()\n        {\n            return RandomWords(4, 8).FirstCharToUpper() + \"?\";\n        }\n\n        /// <summary>\n        /// Generates random text suited for paragraphs, like detailed product description.\n        /// </summary>\n        public static string Paragraph()\n        {\n            var length = Random.Next(3, 6);\n\n            var sentences = Enumerable\n                .Range(0, length)\n                .Select(x => Sentence());\n\n            return string.Join(\" \", sentences);\n        }\n        \n        /// <summary>\n        /// Generates random text ideal for multiple paragraphs, resembling an article.\n        /// </summary>\n        public static string Paragraphs()\n        {\n            var length = Random.Next(2, 5);\n\n            var sentences = Enumerable\n                .Range(0, length)\n                .Select(x => Paragraph());\n\n            return string.Join(\"\\n\", sentences);\n        }\n        \n        /// <summary>\n        /// Generates random text in the format of an email address.\n        /// </summary>\n        /// <example>\n        /// consequuntur35@blanditiis.com\n        /// </example>\n        public static string Email()\n        {\n            return $\"{LongRandomWord()}{Random.Next(10, 99)}@{LongRandomWord()}.com\";\n        }\n\n        /// <summary>\n        /// Generates random text looking like a two-word name, with capitalized initials.\n        /// </summary>\n        /// <example>\n        /// \"Voluptates Inventore\" <br />\n        /// \"Praesentium Consectetur\" <br />\n        /// \"Voluptatibus Molestias\" <br />\n        /// </example>\n        public static string Name()\n        {\n            return LongRandomWord().FirstCharToUpper() + \" \" + LongRandomWord().FirstCharToUpper();\n        }\n        \n        /// <summary>\n        /// Generates random text in the format of a phone number.\n        /// </summary>\n        /// <example>\n        /// 180-204-1358\n        /// </example>\n        public static string PhoneNumber()\n        {\n            return $\"{Random.Next(100, 999)}-{Random.Next(100, 999)}-{Random.Next(1000, 9999)}\";\n        }\n        \n        /// <summary>\n        /// Generates random text resembling a webpage address.\n        /// </summary>\n        /// <example>\n        /// www.libero.com\n        /// </example>\n        public static string WebpageUrl()\n        {\n            return $\"www.{LongRandomWord()}.com\";\n        }\n        \n        /// <summary>\n        /// Generates random text resembling a price value.\n        /// </summary>\n        /// <example>\n        /// $12.99\n        /// </example>\n        public static string Price()\n        {\n            var price = (decimal) Math.Round(Random.NextDouble() * 100) + 0.99m;\n            return $\"{price:C}\";\n        }\n        \n        private static string FirstCharToUpper(this string text)\n        {\n            return text.First().ToString().ToUpper() + text.Substring(1);\n        }\n\n        #endregion\n        \n        #region Time\n\n        private static DateTime RandomDate()\n        {\n            var dayOffset = (Random.NextDouble() - 0.5) * 1000;\n            return System.DateTime.Now - TimeSpan.FromDays(dayOffset);\n        }\n\n        /// <summary>\n        /// Generates random text representation of a random time.\n        /// </summary>\n        /// <example>\n        /// 18:34:47\n        /// </example>\n        public static string Time()\n        {\n            return RandomDate().ToString(\"T\");\n        }\n\n        /// <summary>\n        /// Generates random text that resembles a date value using short formatting.\n        /// </summary>\n        /// <example>\n        /// 04/09/2023\n        /// </example>\n        public static string ShortDate()\n        {\n            return RandomDate().ToString(\"d\");\n        }\n\n        /// <summary>\n        /// Generates random text that resembles a full date value.\n        /// </summary>\n        /// <example>\n        /// Monday, 18 November 2024\n        /// </example>\n        public static string LongDate()\n        {\n            return RandomDate().ToString(\"D\");\n        }\n\n        /// <summary>\n        /// Generates random text that resembles a datetime value.\n        /// </summary>\n        /// <example>\n        /// 04/03/2024 20:43:15\n        /// </example>\n        public static string DateTime()\n        {\n            return RandomDate().ToString(\"G\");\n        }\n\n        #endregion\n\n        #region Numbers\n\n        /// <summary>\n        /// Generates random text mimicking an integer value, ranging from 0 to 10,000.\n        /// </summary>\n        public static string Integer()\n        {\n            return Random.Next(0, 10_000).ToString();\n        }\n\n        /// <summary>\n        /// Generates random text in the style of a local-formatted decimal, values from 0 to 100 with two decimal points precision.\n        /// </summary>\n        /// <example>\n        /// 1,28 <br />\n        /// 7,94 <br />\n        /// 67,30\n        /// </example>\n        public static string Decimal()\n        {\n            return (Random.NextDouble() * Random.Next(0, 100)).ToString(\"N2\");\n        }\n\n        /// <summary>\n        /// Generates random text resembling a percentage value.\n        /// </summary>\n        /// <example>\n        /// 48% <br />\n        /// 14% <br />\n        /// 23%\n        /// </example>\n        public static string Percent()\n        {\n            return (Random.NextDouble() * 100).ToString(\"N0\") + \"%\";\n        }\n\n        #endregion\n\n        #region Visual\n\n        private static readonly Color[] BackgroundColors =\n        {\n            Colors.Red.Lighten3,\n            Colors.Pink.Lighten3,\n            Colors.Purple.Lighten3,\n            Colors.DeepPurple.Lighten3,\n            Colors.Indigo.Lighten3,\n            Colors.Blue.Lighten3,\n            Colors.LightBlue.Lighten3,\n            Colors.Cyan.Lighten3,\n            Colors.Teal.Lighten3,\n            Colors.Green.Lighten3,\n            Colors.LightGreen.Lighten3,\n            Colors.Lime.Lighten3,\n            Colors.Yellow.Lighten3,\n            Colors.Amber.Lighten3,\n            Colors.Orange.Lighten3,\n            Colors.DeepOrange.Lighten3,\n            Colors.Brown.Lighten3,\n            Colors.Grey.Lighten3,\n            Colors.BlueGrey.Lighten3\n        };\n        \n        /// <summary>\n        /// Returns a random bright color from the Material Design palette.\n        /// </summary>\n        /// <example>\n        /// #ffab91 <br />\n        /// #bcaaa4 <br />\n        /// #ffab91\n        /// </example>\n        public static Color BackgroundColor()\n        {\n            var index = Random.Next(0, BackgroundColors.Length);\n            return BackgroundColors[index];\n        }\n        \n        /// <summary>\n        /// Returns a random color from the Material Design palette.\n        /// </summary>\n        /// <example>\n        /// #9e9e9e <br />\n        /// #f44336 <br />\n        /// #9c27b0\n        /// </example>\n        public static Color Color()\n        {\n            var colors = new[]\n            {\n                Colors.Red.Medium,\n                Colors.Pink.Medium,\n                Colors.Purple.Medium,\n                Colors.DeepPurple.Medium,\n                Colors.Indigo.Medium,\n                Colors.Blue.Medium,\n                Colors.LightBlue.Medium,\n                Colors.Cyan.Medium,\n                Colors.Teal.Medium,\n                Colors.Green.Medium,\n                Colors.LightGreen.Medium,\n                Colors.Lime.Medium,\n                Colors.Yellow.Medium,\n                Colors.Amber.Medium,\n                Colors.Orange.Medium,\n                Colors.DeepOrange.Medium,\n                Colors.Brown.Medium,\n                Colors.Grey.Medium,\n                Colors.BlueGrey.Medium\n            };\n\n            var index = Random.Next(0, colors.Length);\n            return colors[index];\n        }\n\n        /// <summary>\n        /// Generates a random image with a soft color gradient with provided <paramref name=\"width\" /> and <paramref name=\"height\" />.\n        /// </summary>\n        /// <remarks>\n        /// Caution: using this method may significantly reduce document generation performance. Please do not use it when performing benchmarks.\n        /// </remarks>\n        /// <returns>Random image encoded in the JPEG format.</returns>\n        public static byte[] Image(int width, int height)\n        {\n            return Image(new ImageSize(width, height));\n        }\n        \n        /// <summary>\n        /// Generates a random image with a soft color gradient.\n        /// </summary>\n        /// <remarks>\n        /// For performance reasons, this method may reduce the <paramref name=\"size\" /> argument to at most 64 pixels, while preserving its aspect ratio.\n        /// </remarks>\n        /// <returns>Random image encoded in the JPEG format.</returns>\n        public static byte[] Image(ImageSize size)\n        {\n            size = LimitSize(size);\n            \n            var colors = BackgroundColors\n                .OrderBy(_ => Random.Next())\n                .Take(2)\n                .ToArray();\n            \n            using var placeholderImage = SkImage.GeneratePlaceholder(size.Width, size.Height, colors[0], colors[1]);\n            using var imageData = placeholderImage.GetEncodedData();\n            return imageData.ToBytes();\n\n            static ImageSize LimitSize(ImageSize size, int maxSize = 64)\n            {\n                if (size.Width < maxSize && size.Height < maxSize)\n                    return size;\n\n                return size.Width > size.Height\n                    ? new ImageSize(maxSize, maxSize * size.Height / size.Width)\n                    : new ImageSize(maxSize * size.Width / size.Height, maxSize);\n            }\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Helpers/TemporaryStorage.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\n\nnamespace QuestPDF.Helpers;\n\ninternal static class TemporaryStorage\n{\n    private static string? TemporaryStoragePath { get; set; }\n\n    internal static string GetPath()\n    {\n        var path = TryGetPath();\n\n        if (path == null)\n        {\n            throw new InvalidOperationException(\n                \"Unable to find a suitable temporary storage location. \" +\n                \"Please specify it using the Settings.TemporaryStoragePath setting and ensure that the application has permissions to read and write to that location.\");\n        }\n        \n        return path;\n    }\n    \n    internal static string? TryGetPath()\n    {\n        if (TemporaryStoragePath != null)\n            return TemporaryStoragePath;\n            \n        var candidates = new[]\n        {\n            Settings.TemporaryStoragePath,\n            Path.Combine(Path.GetTempPath(), \"QuestPDF\", \"temp\"),\n            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), \"QuestPDF\", \"temp\"),\n            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), \"QuestPDF\", \"temp\")\n        };\n\n        TemporaryStoragePath = candidates\n            .Where(x => x != null)\n            .FirstOrDefault(HasPermissionsToAlterPath);\n        \n        return TemporaryStoragePath;\n    }\n        \n    private static bool HasPermissionsToAlterPath(string path)\n    {\n        try\n        {\n            if (!Directory.Exists(path))\n                Directory.CreateDirectory(path);\n                \n            var testFile = Path.Combine(path, Path.GetRandomFileName());\n                \n            using (var fileStream = File.Create(testFile))\n            {\n                fileStream.WriteByte(123); // write anything\n            }\n                \n            File.Delete(testFile);\n                \n            return true;\n        }\n        catch\n        {\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/AspectRatioOption.cs",
    "content": "﻿using QuestPDF.Fluent;\n\nnamespace QuestPDF.Infrastructure\n{\n    public enum AspectRatioOption\n    {\n        /// <summary>\n        /// Adjusts content to occupy the full width available.\n        /// </summary>\n        /// <remarks>\n        /// Used as the default setting in the library.\n        /// </remarks>\n        FitWidth,\n        \n        /// <summary>\n        /// Adjusts content to fill the available height.\n        /// </summary>\n        /// <remarks>\n        /// Often used with height-constraining elements such as: <see cref=\"ConstrainedExtensions.Height\">Height</see>, <see cref=\"ConstrainedExtensions.MaxHeight\">MaxHeight</see>, etc.\n        /// </remarks>\n        FitHeight,\n        \n        /// <summary>\n        /// Adjusts content to fill the available area while maintaining its aspect ratio. This may result in the content fully occupying either the width or height, depending on its dimensions.\n        /// </summary>\n        /// <remarks>\n        /// Often used with constraining elements such as: <see cref=\"ConstrainedExtensions.Width\">Width</see>, <see cref=\"ConstrainedExtensions.MaxWidth\">MaxWidth</see>, <see cref=\"ConstrainedExtensions.Height\">Height</see>, <see cref=\"ConstrainedExtensions.MaxHeight\">MaxHeight</see>, etc.\n        /// </remarks>\n        FitArea\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/BoxShadowStyle.cs",
    "content": "using System;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.Infrastructure;\n\n/// <summary>\n/// Represents the visual styling properties for a box shadow effect.\n/// </summary>\npublic sealed class BoxShadowStyle\n{\n    /// <summary>\n    /// Gets or sets the horizontal offset of the shadow in pixels.\n    /// Positive values move the shadow to the right, negative values move it to the left.\n    /// </summary>\n    public float OffsetX { get; set; }\n    \n    /// <summary>\n    /// Gets or sets the vertical offset of the shadow in pixels.\n    /// Positive values move the shadow downward, negative values move it upward.\n    /// </summary>\n    public float OffsetY { get; set; }\n    \n    /// <summary>\n    /// Gets or sets the spread radius of the shadow in pixels.\n    /// Positive values cause the shadow to expand, negative values cause it to contract.\n    /// </summary>\n    public float Spread { get; set; }\n    \n    /// <summary>\n    /// Gets or sets the blur radius of the shadow in pixels.\n    /// Higher values produce a more diffused shadow with softer edges.\n    /// A value of 0 results in a sharp, unblurred shadow.\n    /// </summary>\n    /// <remarks>\n    /// Values different from 0 may significantly impact performance and enlarge the output file size.\n    /// Use with caution, especially in large documents or when rendering complex shadows.\n    /// </remarks>\n    public float Blur { get; set; }\n    \n    /// <summary>\n    /// Gets or sets the color of the shadow.\n    /// </summary>\n    public Color Color { get; set; } = Colors.Grey.Medium;\n\n    internal void Validate()\n    {\n        if (Blur < 0)\n            throw new ArgumentException(\"Shadow blur radius cannot be negative.\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/Color.cs",
    "content": "using System;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.Infrastructure;\n\npublic readonly struct Color\n{\n    public uint Hex { get; }\n    \n    public byte Alpha => (byte) ((Hex & 0xFF000000) >> 24);\n    public byte Red => (byte) ((Hex & 0xFF0000) >> 16);\n    public byte Green => (byte) ((Hex & 0x00FF00) >> 8);\n    public byte Blue => (byte) (Hex & 0x0000FF);\n\n    /// <summary>\n    /// Creates a new color from a hex value following the ARGB format.\n    /// For example 0xFF0000FF represents a fully opaque blue color.\n    /// </summary>\n    public Color(uint hex)\n    {\n        Hex = hex;\n    }\n\n\n    /// <summary>\n    /// Creates a new color instance with the specified alpha transparency value.\n    /// The alpha value should be within the range 0 to 255, where 0 represents fully transparent\n    /// and 255 represents fully opaque.\n    /// </summary>\n    /// <returns>A new color instance with the adjusted alpha transparency.</returns>\n    public Color WithAlpha(byte alpha)\n    {\n        var newHex = (Hex & 0x00FFFFFF) | ((uint)alpha << 24);\n        return new Color(newHex);\n    }\n    \n    /// <summary>\n    /// Creates a new color instance with the specified alpha transparency value.\n    /// The alpha value should be within the range 0 to 1, where 0 represents fully transparent\n    /// and 1 represents fully opaque.\n    /// </summary>\n    /// <returns>A new color instance with the adjusted alpha transparency.</returns>\n    public Color WithAlpha(float alpha)\n    {\n        if (alpha < 0 || alpha > 1)\n            throw new ArgumentOutOfRangeException(nameof(alpha), \"Alpha value must be between 0 and 1.\");\n        \n        var newAlpha = (byte)(255 * alpha);\n        return WithAlpha(newAlpha);\n    }\n\n    /// <summary>\n    /// Creates a new color instance from a hex string representation.\n    /// The string should follow the formats: #RGB, #ARGB, #RRGGBB, or #AARRGGBB.\n    /// The hash sign is optional; for example: RGB, ARGB, RRGGBB, or AARRGGBB are also valid.\n    /// </summary>\n    /// <param name=\"hex\">The hex string representing the color.</param>\n    /// <returns>A new color instance created from the hex string.</returns>\n    public static Color FromHex(string hex)\n    {\n        return ColorParser.ParseColorHex(hex);\n    }\n\n    /// <summary>\n    /// Creates a new color instance given the red, green, and blue component values.\n    /// Each component should be within the range 0 to 255.\n    /// </summary>\n    public static Color FromRGB(byte red, byte green, byte blue)\n    {\n        return FromARGB(255, red, green, blue);\n    }\n\n    /// <summary>\n    /// Creates a new color instance from the specified alpha, red, green, and blue component values.\n    /// Each component should be within the range 0 to 255.\n    /// </summary>\n    public static Color FromARGB(byte alpha, byte red, byte green, byte blue)\n    {\n        return new Color((uint) (alpha << 24 | red << 16 | green << 8 | blue));\n    }\n    \n    public static implicit operator string(Color color)\n    {\n        return color.ToString();\n    }\n    \n    public static implicit operator Color(string hex)\n    {\n        return FromHex(hex);\n    }\n    \n    public static implicit operator uint(Color color)\n    {\n        return color.Hex;\n    }\n    \n    public static implicit operator Color(uint hex)\n    {\n        if (hex <= 0x00FFFFFF) \n            hex |= 0xFF000000;\n        \n        return new Color(hex);\n    }\n\n    public override string ToString()\n    {\n        if (Alpha == 0xFF)\n            return $\"#{Red:X2}{Green:X2}{Blue:X2}\";\n        \n        return $\"#{Alpha:X2}{Red:X2}{Green:X2}{Blue:X2}\";\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/ContainerElement.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal abstract class ContainerElement : Element, IContainer\n    {\n        internal Element Child { get; set; } = Empty.Instance;\n\n        IElement IContainer.Child\n        {\n            get => Child;\n            set => Child = value as Element;\n        }\n\n        internal override IEnumerable<Element> GetChildren()\n        {\n            yield return Child;\n        }\n\n        internal override void CreateProxy(Func<Element, Element> create)\n        {\n            Child = create(Child);\n        }\n\n        internal override SpacePlan Measure(Size availableSpace)\n        {\n            var measurement = Child.Measure(availableSpace);\n            \n            if (measurement.Type == SpacePlanType.Wrap)\n                return SpacePlan.Wrap(\"Forwarded from child\");\n\n            return measurement;\n        }\n        \n        internal override void Draw(Size availableSpace)\n        {\n            Child?.Draw(availableSpace);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/ContentDirection.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    public enum ContentDirection\n    {\n        /// <summary>\n        /// Sets the left-to-right (LTR) content direction.\n        /// <a href=\"https://www.questpdf.com/api-reference/content-direction.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"contentDirection.ltr.remarks\"]/*' />\n        LeftToRight,\n        \n        /// <summary>\n        /// Sets the right-to-left (RTL) content direction.\n        /// <a href=\"https://www.questpdf.com/api-reference/content-direction.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"contentDirection.rtl.remarks\"]/*' />\n        RightToLeft\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/DocumentMetadata.cs",
    "content": "using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace QuestPDF.Infrastructure\n{\n    public sealed class DocumentMetadata\n    {\n        /// <summary>\n        /// Represents the main heading or name of the document, often displayed as a prominent identifier or label in PDF metadata.\n        /// </summary>\n        public string? Title { get; set; }\n\n        /// <summary>\n        /// Specifies the individual or entity responsible for creating the document.\n        /// </summary>\n        public string? Author { get; set; }\n\n        /// <summary>\n        /// Provides a brief description or main topic related to the document content.\n        /// </summary>\n        public string? Subject { get; set; }\n\n        /// <summary>\n        /// Defines a collection of terms or phrases that describe the document's content or purpose.\n        /// Improves categorization and searchability of the document.\n        /// </summary>\n        public string? Keywords { get; set; }\n\n        /// <summary>\n        /// Identifies the software or system that generated the document.\n        /// </summary>\n        public string? Creator { get; set; }\n\n        /// <summary>\n        /// Specifies the name of the application or library that generated the document.\n        /// </summary>\n        public string? Producer { get; set; }\n\n        /// <summary>\n        /// Specifies the language of the document content, defined using language tags such as \"en-US\" for American English.\n        /// </summary>\n        public string? Language { get; set; }\n        \n        /// <summary>\n        /// Represents the date and time when the document was created.\n        /// This property is used to specify the creation timestamp.\n        /// </summary>\n        public DateTimeOffset CreationDate { get; set; } = DateTimeOffset.Now;\n\n        /// <summary>\n        /// Stores the most recent date and time when the content or metadata of the document was updated.\n        /// It is used to provide metadata information about the last revision of the document.\n        /// </summary>\n        public DateTimeOffset ModifiedDate { get; set; } = DateTimeOffset.Now;\n\n        public static DocumentMetadata Default => new DocumentMetadata();\n        \n        #region Deprecated properties\n        \n        [Obsolete(\"This API has been moved since version 2022.9. Please use the QuestPDF.Settings.DocumentLayoutExceptionThreshold static property.\")]\n        [ExcludeFromCodeCoverage]\n        public int DocumentLayoutExceptionThreshold\n        {\n            get => Settings.DocumentLayoutExceptionThreshold;\n            set => Settings.DocumentLayoutExceptionThreshold = value;\n        }\n\n        [Obsolete(\"This API has been moved since version 2022.9. Please use the QuestPDF.Settings.EnableCaching static property.\")]\n        [ExcludeFromCodeCoverage]\n        public bool ApplyCaching\n        {\n            get => Settings.EnableCaching;\n            set => Settings.EnableCaching = value;\n        }\n        \n        [Obsolete(\"This API has been moved since version 2022.9. Please use the QuestPDF.Settings.EnableDebugging static property.\")]\n        [ExcludeFromCodeCoverage]\n        public bool ApplyDebugging\n        {\n            get => Settings.EnableDebugging;\n            set => Settings.EnableDebugging = value;\n        }\n        \n        [Obsolete(\"This API has been moved since version 2023.5. Please use the QuestPDF.Infrastructure.DocumentSettings API.\")]\n        [ExcludeFromCodeCoverage]\n        public int? ImageQuality { get; set; }\n        \n        [Obsolete(\"This API has been moved since version 2023.5. Please use the QuestPDF.Infrastructure.DocumentSettings API.\")]\n        [ExcludeFromCodeCoverage]\n        public int? RasterDpi { get; set; }\n        \n        [Obsolete(\"This API has been moved since version 2023.5. Please use the QuestPDF.Infrastructure.DocumentSettings API.\")]\n        [ExcludeFromCodeCoverage]\n        public bool? PdfA { get; set; }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/DocumentSettings.cs",
    "content": "﻿using System;\n\nnamespace QuestPDF.Infrastructure\n{\n    public sealed class DocumentSettings\n    {\n        public const int DefaultRasterDpi = 72;\n\n        [Obsolete(\"Please use the ConformanceLevel property instead.\")]\n        public bool PdfA\n        {\n            get => PDFA_Conformance != PDFA_Conformance.None;\n            set => PDFA_Conformance = value ? PDFA_Conformance.PDFA_3B : PDFA_Conformance.None;\n        }\n\n        /// <summary>\n        /// Gets or sets the PDF/A conformance level for the document.\n        /// This property determines the adherence of the generated PDF to specific archival standards.\n        /// </summary>\n        public PDFA_Conformance PDFA_Conformance { get; set; } = PDFA_Conformance.None;\n\n        /// <summary>\n        /// Gets or sets the conformance level for PDF/UA (Universal Accessibility) compliance.\n        /// Warning: this setting makes the document non-reproducable.\n        /// </summary>\n        public PDFUA_Conformance PDFUA_Conformance { get; set; } = PDFUA_Conformance.None;\n        \n        /// <summary>\n        /// Gets or sets a value indicating whether the generated document should be additionally compressed. May greatly reduce file size with a small increase in generation time.\n        /// </summary>\n        public bool CompressDocument { get; set; } = true;\n        \n        /// <summary>\n        /// Encoding quality controls the trade-off between size and quality.\n        /// When the image is opaque, it will be encoded using the JPEG format with the selected quality setting.\n        /// When the image contains an alpha channel, it is always encoded using the PNG format and this option is ignored.\n        /// The default value is \"high quality\".\n        /// </summary>\n\n        /// <remarks>\n        /// This setting is taken into account only when the image is in the JPG format, otherwise it is ignored.\n        /// </remarks>\n        public ImageCompressionQuality ImageCompressionQuality { get; set; } = ImageCompressionQuality.High;\n\n        /// <summary>\n        /// The DPI (pixels-per-inch) at which images and features without native PDF support will be rasterized.\n        /// A larger DPI would create a PDF that reflects the original intent with better fidelity, but it can make for larger PDF files too, which would use more memory while rendering, and it would be slower to be processed or sent online or to printer.\n        /// When generating images, this parameter also controls the resolution of the generated content.\n        /// Default value is 288.\n        /// </summary>\n        public int ImageRasterDpi { get; set; } = DefaultRasterDpi * 4;\n \n        public ContentDirection ContentDirection { get; set; } = ContentDirection.LeftToRight;\n        \n        public static DocumentSettings Default => new DocumentSettings();\n    }\n    \n    public enum PDFA_Conformance\n    {\n        None = 0,\n        // PDFA_1A = 1,\n        // PDFA_1B = 2,\n        PDFA_2A = 3,\n        PDFA_2B = 4,\n        PDFA_2U = 5,\n        PDFA_3A = 6,\n        PDFA_3B = 7,\n        PDFA_3U = 8\n    }\n    \n    public enum PDFUA_Conformance\n    {\n        None = 0,\n        PDFUA_1 = 1\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/Element.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing QuestPDF.Drawing;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal abstract class Element : IElement\n    {\n        internal IPageContext PageContext { get; set; }\n        internal IDrawingCanvas Canvas { get; set; }\n        internal SourceCodePath? CodeLocation { get; set; }\n        \n        internal virtual IEnumerable<Element?> GetChildren()\n        {\n            yield break;\n        }\n\n        internal virtual void CreateProxy(Func<Element?, Element?> create)\n        {\n            \n        }\n        \n        internal abstract SpacePlan Measure(Size availableSpace);\n        internal abstract void Draw(Size availableSpace);\n\n        internal virtual string? GetCompanionHint() => null;\n        internal virtual string? GetCompanionSearchableContent() => null;\n        internal virtual IEnumerable<KeyValuePair<string, string>>? GetCompanionProperties() => null;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/EmptyContainer.cs",
    "content": "using QuestPDF.Elements;\n\nnamespace QuestPDF.Infrastructure;\n\npublic static class EmptyContainer\n{\n    /// <summary>\n    /// Creates an empty IContainer instance.\n    /// </summary>\n    public static IContainer Create() => new Container();\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/FontPosition.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    internal enum FontPosition\n    {\n        Normal,\n        Subscript,\n        Superscript,\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/FontWeight.cs",
    "content": "﻿#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member\n\nnamespace QuestPDF.Infrastructure\n{\n    public enum FontWeight\n    {\n        Thin = 100,\n        ExtraLight = 200,\n        Light = 300,\n        Normal = 400,\n        Medium = 500,\n        SemiBold = 600,\n        Bold = 700,\n        ExtraBold = 800,\n        Black = 900,\n        ExtraBlack = 1000\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/HorizontalAlignment.cs",
    "content": "namespace QuestPDF.Infrastructure\n{\n    public enum HorizontalAlignment\n    {\n        Left,\n        Center,\n        Right\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IComponent.cs",
    "content": "namespace QuestPDF.Infrastructure\n{\n    /// <summary>\n    /// <para>This interface represents a reusable document fragment.</para>\n    /// <para>\n    /// Components serve as modular building blocks for abstracting document layouts. \n    /// They promote code reusability across multiple sections or types of documents. \n    /// Using a component, you can generate content based on its internal state.\n    /// </para>\n    /// </summary>\n    /// <example>\n    /// Consider the scenario of a company-wide page header.\n    /// Instead of replicating the same header design across various documents, a single component can be created and referenced wherever needed.\n    /// </example>\n    public interface IComponent\n    {\n        /// <summary>\n        /// Method invoked by the library to compose document content. \n        /// </summary>\n        void Compose(IContainer container);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IContainer.cs",
    "content": "﻿using QuestPDF.Elements;\n\nnamespace QuestPDF.Infrastructure\n{\n    /// <summary>\n    /// Represents a layout structure with exactly one child element.\n    /// </summary>\n    /// <remarks>\n    /// The main purpose of this interface is to facilitate the Fluent API's construction.\n    /// It's not intended to allow external creation of new container kinds or layout designs.\n    /// </remarks>\n    public interface IContainer\n    {\n        IElement? Child { get; set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IContentDirectionAware.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    internal interface IContentDirectionAware\n    {\n        public ContentDirection ContentDirection { get; set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IDocument.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    /// <summary>\n    /// Represents the document abstraction, including its content, metadata, and configuration settings.\n    /// <a href=\"https://www.questpdf.com/getting-started.html\">Learn more</a>\n    /// </summary>\n    /// <remarks>\n    /// <para>Implement this interface to centralize your entire document's structure within a single class for easy management.</para>\n    /// <para>For a different approach, consider the <a href=\"https://www.questpdf.com/quick-start.html\">Minimal API</a> pathway.</para>\n    /// </remarks>\n    public interface IDocument\n    {\n#if NETCOREAPP3_0_OR_GREATER\n        /// <summary>\n        /// Provides metadata values like author and keywords used in PDF creation.\n        /// </summary>\n        /// <remarks>\n        /// Override this method to customize document's metadata.\n        /// </remarks>\n        public DocumentMetadata GetMetadata() => DocumentMetadata.Default; \n\n        /// <summary>\n        /// Provides document generation settings, such as default image DPI and compression rate.\n        /// </summary>\n        /// <remarks>\n        /// Override this to customize default configurations.\n        /// </remarks>\n        public DocumentSettings GetSettings() => DocumentSettings.Default;\n#else\n        DocumentMetadata GetMetadata();\n        DocumentSettings GetSettings();\n#endif\n        \n        /// <summary>\n        /// Configures the document content by specifying its layout structure and visual element.\n        /// </summary>\n        /// <param name=\"container\">The document container used for defining content via the FluentAPI.</param>\n        void Compose(IDocumentContainer container);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IDocumentCanvas.cs",
    "content": "﻿using QuestPDF.Drawing;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal interface IDocumentCanvas\n    {\n        void SetSemanticTree(SemanticTreeNode? semanticTree);\n        \n        void BeginDocument();\n        void EndDocument();\n        \n        void BeginPage(Size size);\n        void EndPage();\n        \n        IDrawingCanvas GetDrawingCanvas();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IDocumentContainer.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    /// <summary>\n    /// Represents the primary container encapsulating the entire content of the document.\n    /// </summary>\n    public interface IDocumentContainer\n    {\n                \n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IDrawingCanvas.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal interface IDrawingCanvas\n    {\n        DocumentPageSnapshot GetSnapshot();\n        void DrawSnapshot(DocumentPageSnapshot snapshot);\n        \n        void Save();\n        void Restore();\n\n        void SetZIndex(int index);\n        int GetZIndex();\n        \n        SkCanvasMatrix GetCurrentMatrix();\n        void SetMatrix(SkCanvasMatrix matrix);\n        \n        void Translate(Position vector);\n        void Scale(float scaleX, float scaleY);\n        void Rotate(float angle);\n        \n        void DrawLine(Position start, Position end, SkPaint paint);\n        void DrawRectangle(Position vector, Size size, SkPaint paint);\n        void DrawComplexBorder(SkRoundedRect innerRect, SkRoundedRect outerRect, SkPaint paint);\n        void DrawShadow(SkRoundedRect shadowRect, SkBoxShadow shadow);\n        void DrawParagraph(SkParagraph paragraph, int lineFrom, int lineTo);\n        void DrawImage(SkImage image, Size size);\n        void DrawPicture(SkPicture picture);\n        void DrawSvgPath(string path, Color color);\n        void DrawSvg(SkSvgImage svgImage, Size size);\n\n        void DrawOverflowArea(SkRect area);\n        void ClipOverflowArea(SkRect availableSpace, SkRect requiredSpace);\n        void ClipRectangle(SkRect clipArea);\n        void ClipRoundedRectangle(SkRoundedRect clipArea);\n        \n        void DrawHyperlink(Size size, string url, string? description);\n        void DrawSectionLink(Size size, string sectionName, string? description);\n        void DrawSection(string sectionName);\n        \n        int GetSemanticNodeId();\n        void SetSemanticNodeId(int nodeId);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IDynamicComponent.cs",
    "content": "using System;\nusing QuestPDF.Elements;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal sealed class DynamicComponentProxy\n    {\n        internal Action<object> SetState { get; private set; }\n        internal Func<object> GetState { get; private set; }\n        internal Func<DynamicContext, DynamicComponentComposeResult> Compose { get; private set; }\n        \n        internal static DynamicComponentProxy CreateFrom<TState>(IDynamicComponent<TState> component) where TState : struct\n        {\n            return new DynamicComponentProxy\n            {\n                GetState = () => component.State,\n                SetState = x => component.State = (TState)x,\n                Compose = component.Compose\n            };\n        }\n        \n        internal static DynamicComponentProxy CreateFrom(IDynamicComponent component)\n        {\n            return new DynamicComponentProxy\n            {\n                GetState = () => null,\n                SetState = _ => { },\n                Compose = component.Compose\n            };\n        }\n    }\n\n    /// <summary>\n    /// Represents the output from the DynamicComponent describing what should be rendered on the current page.\n    /// </summary>\n    public sealed class DynamicComponentComposeResult\n    {\n        /// <summary>\n        /// Any content created with the <see cref=\"DynamicContext.CreateElement\" /> method that should be drawn on the currently rendered page.\n        /// </summary>\n        public IElement Content { get; set; }\n        \n        /// <summary>\n        /// Set to true if the dynamic component has additional content for the next page.\n        /// Set to false if all content from the dynamic component has been rendered.\n        /// </summary>\n        public bool HasMoreContent { get; set; }\n    }\n    \n    /// <summary>\n    /// Represents a dynamically generated section of the document.\n    /// Components are page-aware, understand their positioning, can dynamically construct other content elements, and assess their dimensions, enabling complex layout creations.\n    /// </summary>\n    /// <remarks>\n    /// Though dynamic components offer great flexibility, be cautious of potential performance impacts.\n    /// </remarks>\n    public interface IDynamicComponent\n    {\n        /// <summary>\n        /// Method invoked by the library to plan and create new content for each page. \n        /// </summary>\n        /// <remarks>\n        /// Remember, the QuestPDF library can invoke the Compose method more than once for each page and might adjust the state internally.\n        /// </remarks>\n        /// <param name=\"context\">Context offering additional information (like current page number, entire document size) and the capability to produce dynamic content elements.</param>\n        /// <returns>Representation of content that should be placed on the current page.</returns>\n        DynamicComponentComposeResult Compose(DynamicContext context);\n    }\n    \n    /// <summary>\n    /// Represents a section of the document dynamically created based on its inner state.\n    /// Components are page-aware, understand their positioning, can dynamically construct other content elements, and assess their dimensions, enabling complex layout creations.\n    /// </summary>\n    /// <remarks>\n    /// Though dynamic components offer great flexibility, be cautious of potential performance impacts.\n    /// </remarks>\n    /// <typeparam name=\"TState\">Structure type representing the internal state of the component.</typeparam>\n    public interface IDynamicComponent<TState> : IDynamicComponent where TState : struct\n    {\n        /// <summary>\n        /// Represents the component's current state.\n        /// </summary>\n        /// <remarks>\n        /// <para>\n        /// The state should remain read-only.\n        /// Avoid direct state modifications.\n        /// For any alterations, generate a new struct instance and reassign the State property.\n        /// </para>\n        /// <para>Remember, the QuestPDF library can invoke the Compose method more than once for each page and might adjust the state internally.</para>\n        /// </remarks>\n        TState State { get; set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IElement.cs",
    "content": "namespace QuestPDF.Infrastructure\n{\n    /// <summary>\n    /// Represents an element within the document content, for example: <br/>\n    /// - visual elements (text, image, canvas), <br/>\n    /// - positional elements (padding, aspect ratio), <br/>\n    /// - flow-control elements (page break, conditional displays), <br/>\n    /// - layout elements (table, column), <br/>\n    /// - and other element types (section, hyperlink, content direction). \n    /// </summary>\n    public interface IElement\n    {\n        \n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IMergedDocument.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal enum MergedDocumentPageNumberStrategy\n    {\n        Original,\n        Continuous,\n    }\n\n    public sealed class MergedDocument : IDocument\n    {\n        internal IReadOnlyList<IDocument> Documents { get; }\n        internal MergedDocumentPageNumberStrategy PageNumberStrategy { get; private set; } = MergedDocumentPageNumberStrategy.Original;\n        \n        internal DocumentMetadata Metadata { get; private set; } = DocumentMetadata.Default;\n        internal DocumentSettings Settings { get; private set; } = DocumentSettings.Default;\n\n        internal MergedDocument(IEnumerable<IDocument> documents)\n        {\n            Documents = documents?.ToList() ?? throw new NullReferenceException(nameof(documents));\n        }\n\n        public void Compose(IDocumentContainer container)\n        {\n            foreach (var document in Documents)\n            {\n                document.Compose(container);\n            }\n        }\n\n        public DocumentMetadata GetMetadata()\n        {\n            return Metadata;\n        }\n        \n        public DocumentSettings GetSettings()\n        {\n            return Settings;\n        }\n\n        /// <summary>\n        /// Documents maintain their own page numbers upon merging, without continuity between them.\n        /// As a result, APIs related to page numbers reflect individual documents, not the cumulative count.\n        /// All documents are simply be merged together.\n        /// </summary>\n        /// <example>\n        /// Merging a two-page document with a three-page document results in a sequence: 1, 2, 1, 2, 3.\n        /// </example>\n        public MergedDocument UseOriginalPageNumbers()\n        {\n            PageNumberStrategy = MergedDocumentPageNumberStrategy.Original;\n            return this;\n        }\n\n        /// <summary>\n        /// Consolidates the content from every document, creating a continuous seamless one.\n        /// Page number APIs return a consecutive numbering for this unified document.\n        /// </summary>\n        /// <example>\n        /// Merging a two-page document with a three-page document results in a sequence: 1, 2, 3, 4, 5.\n        /// </example>\n        public MergedDocument UseContinuousPageNumbers()\n        {\n            PageNumberStrategy = MergedDocumentPageNumberStrategy.Continuous;\n            return this;\n        }\n\n        public MergedDocument WithMetadata(DocumentMetadata metadata)\n        {\n            Metadata = metadata ?? Metadata;\n            return this;\n        }\n\n        public MergedDocument WithSettings(DocumentSettings settings)\n        {\n            Settings = settings ?? Settings;\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IPageContext.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Numerics;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal sealed class DocumentLocation\n    {\n        public int DocumentId { get; set; }\n        public string Name { get; set; }\n        public int PageStart { get; set; }\n        public int PageEnd { get; set; }\n        public int Length => PageEnd - PageStart + 1;\n    }\n    \n    public class PageElementLocation\n    {\n        public string Id { get; set; }\n\n        public int PageNumber { get; set; }\n\n        public float Width { get; set; }\n        public float Height { get; set; }\n\n        public float X { get; set; }\n        public float Y { get; set; }\n        \n        public Matrix4x4 Transform { get; set; } = Matrix4x4.Identity;\n    }\n    \n    internal interface IPageContext\n    {\n        bool IsInitialRenderingPhase { get; }\n        int DocumentLength { get; }\n        int CurrentPage { get; }\n        void SetSectionPage(string name);\n        DocumentLocation? GetLocation(string name);\n        string GetDocumentLocationName(string locationName);\n        \n        void CaptureContentPosition(PageElementLocation location);\n        ICollection<PageElementLocation> GetContentCapturedPositions(string id);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/ISemanticAware.cs",
    "content": "using QuestPDF.Drawing;\n\nnamespace QuestPDF.Infrastructure;\n\ninternal interface ISemanticAware\n{\n    public SemanticTreeManager? SemanticTreeManager { get; set; }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/IStateful.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    internal interface IStateful\n    {\n        void ResetState(bool hardReset = true);\n        object GetState();\n        void SetState(object state);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/Image.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Helpers;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal record GetImageVersionRequest\n    {\n        internal ImageSize Resolution { get; set; }\n        internal ImageCompressionQuality CompressionQuality { get; set; }\n    }\n    \n    /// <summary>\n    /// <para>Caches the image in local memory for efficient reuse.</para>\n    /// <para>Optimizes the generation process, especially:</para>\n    /// <para>- For images repeated in a single document to enhance performance and reduce output file size (e.g., an image used as list bullet icon).</para>\n    /// <para>- When an image appears on multiple document types for increased generation performance (e.g., a company logo).</para>\n    /// </summary>\n    /// <remarks>\n    /// This class is thread safe.\n    /// </remarks>\n    public sealed class Image : IDisposable\n    {\n        static Image()\n        {\n            SkNativeDependencyCompatibilityChecker.Test();\n        }\n\n        internal bool IsShared { get; set; } = true;\n        internal SkImage SkImage { get; }\n        internal ImageSize Size { get; }\n\n        internal LinkedList<(GetImageVersionRequest request, SkImage image)> ScaledImageCache { get; } = new();\n \n        internal Image(SkImage image)\n        {\n            SkImage = image;\n            Size = new ImageSize(image.Width, image.Height);\n        }\n        \n        ~Image()\n        {\n            this.WarnThatFinalizerIsReached();\n            Dispose();\n        }\n        \n        public void Dispose()\n        {\n            SkImage?.Dispose();\n            \n            foreach (var cacheKey in ScaledImageCache)\n                cacheKey.image?.Dispose();\n            \n            GC.SuppressFinalize(this);\n        }\n\n        #region Scaling Image\n\n        internal SkImage GetVersionOfSize(GetImageVersionRequest request)\n        {\n            foreach (var cacheKey in ScaledImageCache)\n            {\n                if (cacheKey.request == request)\n                    return cacheKey.image;\n            }\n\n            var result = SkImage.ResizeAndCompressImage(request.Resolution, request.CompressionQuality);\n            ScaledImageCache.AddLast((request, result));\n            return result;\n        }\n\n        #endregion\n\n        #region public constructors\n\n        /// <summary>\n        /// Loads the image from binary data.\n        /// <a href=\"https://www.questpdf.com/api-reference/image/basics.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.remarks\"]/*' />\n        public static Image FromBinaryData(byte[] imageBytes)\n        {\n            using var imageData = SkData.FromBinary(imageBytes);\n            return StaticImageCache.DecodeImage(imageData, isShared: true);\n        }\n\n        /// <summary>\n        /// Loads the image from a file with specified path.\n        /// <a href=\"https://www.questpdf.com/api-reference/image/basics.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.remarks\"]/*' />\n        public static Image FromFile(string filePath)\n        {\n            return StaticImageCache.DirectlyLoadFromFile(filePath, isShared: true);\n        }\n\n        /// <summary>\n        /// Loads the image from a stream.\n        /// <a href=\"https://www.questpdf.com/api-reference/image/basics.html\">Learn more</a>\n        /// </summary>\n        /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.remarks\"]/*' />\n        public static Image FromStream(Stream stream)\n        {\n            using var imageData = SkData.FromStream(stream);\n            return StaticImageCache.DecodeImage(imageData, isShared: true);\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/ImageCompressionQuality.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    public enum ImageCompressionQuality\n    {\n        /// <summary>\n        /// JPEG format with target quality set to 100 out of 100\n        /// </summary>\n        Best,\n\n        /// <summary>\n        /// JPEG format with target quality set to 90 out of 100\n        /// </summary>\n        VeryHigh,\n\n        /// <summary>\n        /// JPEG format with target quality set to 75 out of 100\n        /// </summary>\n        High,\n\n        /// <summary>\n        /// JPEG format with target quality set to 50 out of 100\n        /// </summary>\n        Medium,\n\n        /// <summary>\n        /// JPEG format with target quality set to 25 out of 100\n        /// </summary>\n        Low,\n\n        /// <summary>\n        /// JPEG format with target quality set to 10 out of 100\n        /// </summary>\n        VeryLow\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/ImageFormat.cs",
    "content": "namespace QuestPDF.Infrastructure\n{\n    public enum ImageFormat\n    {\n        Jpeg,\n        Png,\n        Webp\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/ImageGenerationSettings.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    public sealed class ImageGenerationSettings\n    {\n        /// <summary>\n        /// The file format used to encode the image(s).\n        /// </summary>\n        public ImageFormat ImageFormat { get; set; } = ImageFormat.Png;\n\n        /// <summary>\n        /// Encoding quality controls the trade-off between size and quality.\n        /// The default value is \"high\".\n        /// </summary>\n        public ImageCompressionQuality ImageCompressionQuality { get; set; } = ImageCompressionQuality.High;\n\n        /// <summary>\n        /// The DPI (pixels-per-inch) at which the document will be rasterized. This parameter controls the resolution of produced images.\n        /// Higher DPI results in superior image quality but may increase the output file size.\n        /// Default value is 288.\n        /// </summary>\n        /// <example>\n        /// Consider a document of dimensions 3x4 inches. Using a DPI value of 300, the final image resolution translates to 900x1200 pixels.\n        /// </example>\n        public int RasterDpi { get; set; } = DocumentSettings.DefaultRasterDpi * 4;\n\n\n        public static ImageGenerationSettings Default => new ImageGenerationSettings();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/ImageScaling.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    public enum ImageScaling\n    {\n        FitWidth,\n        FitHeight,\n        FitArea,\n        Resize\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/ImageSize.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    public readonly struct ImageSize\n    {\n        public readonly int Width;\n        public readonly int Height;\n\n        public ImageSize(int width, int height)\n        {\n            Width = width;\n            Height = height;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/LicenseType.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    /// <summary>\n    /// The QuestPDF library is available under a hybrid license favorable to both community and business users.\n    /// For a comprehensive overview, please visit the <a href=\"https://www.questpdf.com/license\">License and Pricing details webpage</a>.\n    /// </summary>\n    public enum LicenseType\n    {\n        /// <summary>\n        /// The QuestPDF Evaluation License is intended solely for evaluation before choosing an appropriate license.\n        /// It is not suitable for production use.\n        /// <a href=\"https://www.questpdf.com/license\">Learn more</a>\n        /// </summary>\n        Evaluation,\n\n        /// <summary>\n        /// The QuestPDF Community MIT License is applicable mainly for companies and individuals with less than $1M USD annual gross revenue.\n        /// <a href=\"https://www.questpdf.com/license\">Learn more</a>\n        /// </summary>\n        Community,\n        \n        /// <summary>\n        /// The QuestPDF Professional License is applicable for individuals and companies with at most 10 software developers.\n        /// <a href=\"https://www.questpdf.com/license\">Learn more</a>\n        /// </summary>\n        Professional,\n        \n        /// <summary>\n        /// The QuestPDF Enterprise License is applicable for individuals and companies with any number of software developers.\n        /// <a href=\"https://www.questpdf.com/license\">Learn more</a>\n        /// </summary>\n        Enterprise\n    }\n} "
  },
  {
    "path": "Source/QuestPDF/Infrastructure/PageContext.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal sealed class PageContext : IPageContext\n    {\n        public bool IsInitialRenderingPhase { get; private set; } = true;\n        public int DocumentLength { get; private set; }\n        private List<DocumentLocation> Locations { get; } = new();\n        \n        public int CurrentDocumentId { get; private set; }\n        public int CurrentPage { get; private set; }\n\n        internal void SetDocumentId(int id)\n        {\n            CurrentDocumentId = id;\n        }\n        \n        internal void ProceedToNextRenderingPhase()\n        {\n            IsInitialRenderingPhase = false;\n            CurrentPage = 0;\n        }\n        \n        internal void DecrementPageNumber()\n        {\n            CurrentPage--;\n        }\n        \n        internal void IncrementPageNumber()\n        {\n            CurrentPage++;\n            DocumentLength = Math.Max(DocumentLength, CurrentPage);\n        }\n\n        public void SetSectionPage(string name)\n        {\n            var location = GetLocation(name);\n\n            if (location == null)\n            {\n                location = new DocumentLocation\n                {\n                    DocumentId = CurrentDocumentId,\n                    Name = name,\n                    PageStart = CurrentPage,\n                    PageEnd = CurrentPage\n                };\n                \n                Locations.Add(location);\n            }\n\n            if (location.PageEnd < CurrentPage)\n                location.PageEnd = CurrentPage;\n        }\n\n        public DocumentLocation? GetLocation(string name)\n        {\n            return Locations.Find(x => x.DocumentId == CurrentDocumentId && x.Name == name);\n        }\n        \n        public string GetDocumentLocationName(string locationName)\n        {\n            return $\"{CurrentDocumentId} | {locationName}\";\n        }\n        \n        private List<PageElementLocation> ContentCapturedPositions { get; } = new();\n\n        public void CaptureContentPosition(PageElementLocation location)\n        {\n            ContentCapturedPositions.Add(location);\n        }\n\n        public ICollection<PageElementLocation> GetContentCapturedPositions(string id)\n        {\n            return ContentCapturedPositions.Where(x => x.Id == id).ToList();\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/Position.cs",
    "content": "﻿using System;\n\nnamespace QuestPDF.Infrastructure\n{\n    internal readonly struct Position\n    {\n        public readonly float X;\n        public readonly float Y;\n\n        public static Position Zero => new Position(0, 0);\n        \n        public Position(float x, float y)\n        {\n            X = x;\n            Y = y;\n        }\n\n        public Position Reverse()\n        {\n            return new Position(-X, -Y);\n        }\n        \n        public static bool Equal(Position first, Position second)\n        {\n            if (Math.Abs(first.X - second.X) > Size.Epsilon)\n                return false;\n            \n            if (Math.Abs(first.Y - second.Y) > Size.Epsilon)\n                return false;\n\n            return true;\n        }\n        \n        public override string ToString() => $\"(Left: {X:N3}, Top: {Y:N3})\";\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/Size.cs",
    "content": "﻿using System;\n\nnamespace QuestPDF.Infrastructure\n{\n    public readonly struct Size\n    {\n        public const float Epsilon = 0.01f;\n        public const float Infinity = 14_400;\n\n        public readonly float Width;\n        public readonly float Height;\n        \n        public static Size Zero { get; } = new Size(0, 0);\n        public static Size Max { get; } = new Size(Infinity, Infinity);\n\n        public Size(float width, float height)\n        {\n            Width = width;\n            Height = height;\n        }\n        \n        internal static bool Equal(Size first, Size second)\n        {\n            if (Math.Abs(first.Width - second.Width) > Size.Epsilon)\n                return false;\n            \n            if (Math.Abs(first.Height - second.Height) > Size.Epsilon)\n                return false;\n\n            return true;\n        }\n        \n        public override string ToString() => $\"(Width: {Width:N3}, Height: {Height:N3})\";\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/SourceCodePath.cs",
    "content": "using System.Diagnostics;\nusing System.Linq;\nusing QuestPDF.Companion;\n\nnamespace QuestPDF.Infrastructure;\n\ninternal readonly struct SourceCodePath(StackFrame frame)\n{\n    public readonly string FilePath = frame.GetFileName() ?? string.Empty;\n    public readonly int LineNumber = frame.GetFileLineNumber();\n\n    internal static SourceCodePath? CreateFromCurrentStackTrace()\n    {\n        #if NET6_0_OR_GREATER\n        \n        if (!CompanionService.IsCompanionAttached)\n            return null;\n\n        // for dotnet 6, 7, 8:\n        // - after hot-reload, the stack trace does not contain correct source code path\n        // - the operation of collecting stack trace slows down generation process significantly\n        // TODO: revise for dotnet 9\n        if (CompanionService.IsDocumentHotReloaded)\n            return null;\n        \n        #else\n        \n        return null;\n        \n        #endif\n\n        var stackTrace = new StackTrace(true);\n\n        var frame = stackTrace.GetFrames().FirstOrDefault(x => x.HasSource() && x.HasMethod());\n\n        if (frame == null)\n            return null;\n\n        return new SourceCodePath(frame);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/StaticImageCache.cs",
    "content": "using System.Collections.Concurrent;\nusing System.IO;\nusing System.Linq;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Infrastructure;\n\nstatic class StaticImageCache\n{\n    private static bool CacheIsEnabled { get; set; } = true;\n    private static ConcurrentDictionary<string, Image> Items { get; set; } = new();\n\n    private const int MaxCacheSize = 25_000_000;\n    private const int MaxItemSize = 1_000_000;\n    \n    public static Image LoadFromCache(string filePath)\n    {\n        // check fallback path\n        filePath = AdjustPath(filePath);\n\n        // check if the image is already in cache\n        if (Items.TryGetValue(filePath, out var cacheItem))\n            return cacheItem;\n        \n        // check file size\n        var fileInfo = new FileInfo(filePath);\n        \n        if (fileInfo.Length > MaxItemSize)\n            return DirectlyLoadFromFile(filePath, false);\n        \n        // if cache is larger than expected, the usage might be different from loading static images\n        if (!CacheIsEnabled)\n            return DirectlyLoadFromFile(filePath, false);\n        \n        // create new cache item and add it to the cache\n        var image = DirectlyLoadFromFile(filePath, true);\n        Items.TryAdd(filePath, image);\n        \n        // check cache size\n        CacheIsEnabled = Items.Values.Sum(x => x.SkImage.EncodedDataSize) < MaxCacheSize;\n        \n        // return cached value\n        return image;\n    }\n\n    public static string AdjustPath(string filePath)\n    {\n        if (File.Exists(filePath))\n            return filePath;\n        \n        if (Path.IsPathRooted(filePath))\n            throw new DocumentComposeException($\"Cannot load an image under the provided absolute path, file not found: {filePath}\");\n\n        var fallbackPath = Path.Combine(Helpers.Helpers.ApplicationFilesPath, filePath);\n\n        if (!File.Exists(fallbackPath))\n            throw new DocumentComposeException($\"Cannot load an image under the provided relative path, file not found: {filePath}\");\n\n        return fallbackPath;\n    }\n    \n    public static Image DirectlyLoadFromFile(string filePath, bool isShared)\n    {\n        filePath = AdjustPath(filePath);\n        \n        using var imageData = SkData.FromFile(filePath);\n        return DecodeImage(imageData, isShared);\n    }\n    \n    public static Image DecodeImage(SkData imageData, bool isShared)\n    {\n        try\n        {\n            var skImage = SkImage.FromData(imageData);\n            var image = new Image(skImage);\n            image.IsShared = isShared;\n            \n            return image;\n        }\n        catch\n        {\n            throw new DocumentComposeException(\"Cannot decode the provided image.\");\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/SvgImage.cs",
    "content": "using System;\nusing System.IO;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Infrastructure;\n\n/// <summary>\n/// Caches the SVG image in local memory for efficient reuse.\n/// </summary>\n/// <remarks>\n/// This class is thread safe.\n/// </remarks>\npublic sealed class SvgImage : IDisposable\n{\n    internal SkSvgImage SkSvgImage { get; }\n    internal bool IsShared { get; set; } = true;\n    \n    private SvgImage(string content)\n    {\n        SkSvgImage = new SkSvgImage(content, SkResourceProvider.CurrentResourceProvider, FontManager.CurrentFontManager);    \n    }\n\n    ~SvgImage()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n        \n    public void Dispose()\n    {\n        SkSvgImage?.Dispose();\n        GC.SuppressFinalize(this);\n    }\n\n    /// <summary>\n    /// Loads the SVG image from a file with specified path.\n    /// <a href=\"https://www.questpdf.com/api-reference/image/svg.html\">Learn more</a>\n    /// </summary>\n    /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.remarks\"]/*' />\n    public static SvgImage FromFile(string filePath)\n    {\n        if (!File.Exists(filePath))\n        {\n            var fallbackPath = Path.Combine(Helpers.Helpers.ApplicationFilesPath, filePath);\n                \n            if (!File.Exists(fallbackPath))\n                throw new DocumentComposeException($\"Cannot load an SVG image under the provided path, file not found: ${filePath}\");\n                \n            filePath = fallbackPath;\n        }\n            \n        var svg = File.ReadAllText(filePath);\n        return new SvgImage(svg);\n    }\n\n    /// <summary>\n    /// Loads the SVG image from a stream.\n    /// <a href=\"https://www.questpdf.com/api-reference/image/svg.html\">Learn more</a>\n    /// </summary>\n    /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for=\"image.remarks\"]/*' />\n    public static SvgImage FromText(string svg)\n    {\n        return new SvgImage(svg);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/TextDirection.cs",
    "content": "﻿namespace QuestPDF.Infrastructure\n{\n    internal enum TextDirection\n    {\n        Auto,\n        LeftToRight,\n        RightToLeft\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/TextHorizontalAlignment.cs",
    "content": "namespace QuestPDF.Infrastructure;\n\npublic enum TextHorizontalAlignment\n{\n    Left,\n    Center,\n    Right,\n    Justify,\n    Start,\n    End\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/TextInjectedElementAlignment.cs",
    "content": "namespace QuestPDF.Infrastructure;\n\npublic enum TextInjectedElementAlignment\n{\n    /// <summary>\n    /// Aligns the bottom edge of the injected element with the text baseline. The injected element sits on top of the baseline.\n    /// </summary>\n    AboveBaseline,\n\n    /// <summary>\n    /// Aligns the top edge of the injected element with the text baseline. The injected element hangs below the baseline.\n    /// </summary>\n    BelowBaseline,\n\n    /// <summary>\n    /// Aligns the top edge of the injected element with the top edge of the font. If the injected element is very tall, the extra space will hang from the top and extend through the bottom of the line.\n    /// </summary>\n    Top,\n\n    /// <summary>\n    /// Aligns the bottom edge of the injected element with the top edge of the font. If the injected element is very tall, the extra space will rise from the bottom and extend through the top of the line.\n    /// </summary>\n    Bottom,\n\n    /// <summary>\n    /// Aligns the middle of the injected element with the middle of the text. If the injected element is very tall, the extra space will grow equally from the top and bottom of the line.\n    /// </summary>\n    Middle\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/TextStyle.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Helpers;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\n\nusing TextStyleFontFeature = (string Name, bool Enabled);\n\nnamespace QuestPDF.Infrastructure\n{\n    public record TextStyle\n    {\n        internal const float NormalLineHeightCalculatedFromFontMetrics = 0;\n        \n        internal int Id { get; set; }\n        \n        internal Color? Color { get; set; }\n        internal Color? BackgroundColor { get; set; }\n        internal Color? DecorationColor { get; set; }\n        internal string[]? FontFamilies { get; set; }\n        internal TextStyleFontFeature[]? FontFeatures { get; set; }\n        internal float? Size { get; set; }\n        internal float? LineHeight { get; set; }\n        internal float? LetterSpacing { get; set; }\n        internal float? WordSpacing { get; set; }\n        internal FontWeight? FontWeight { get; set; }\n        internal FontPosition? FontPosition { get; set; }\n        internal bool? IsItalic { get; set; }\n        internal bool? HasStrikethrough { get; set; }\n        internal bool? HasUnderline { get; set; }\n        internal bool? HasOverline { get; set; }\n        internal TextStyleConfiguration.TextDecorationStyle? DecorationStyle { get; set; }\n        internal float? DecorationThickness { get; set; }\n        internal TextDirection? Direction { get; set; }\n\n        ~TextStyle()\n        {\n            // TextStyle is meant to be an object spanning the entire application lifetime\n            // It does not require the IDisposable pattern\n            SkTextStyleCache?.Dispose();\n        }\n\n        public static TextStyle Default { get; } = new()\n        {\n            Id = 0\n        };\n        \n        internal static TextStyle  LibraryDefault { get; } = new()\n        {\n            Id = 1,\n            Color = Colors.Black,\n            BackgroundColor = Colors.Transparent,\n            DecorationColor = Colors.Black,\n            FontFamilies = [ Fonts.Lato ],\n            FontFeatures = [],\n            Size = 12,\n            LineHeight = NormalLineHeightCalculatedFromFontMetrics,\n            LetterSpacing = 0,\n            WordSpacing = 0f,\n            FontWeight = Infrastructure.FontWeight.Normal,\n            FontPosition = Infrastructure.FontPosition.Normal,\n            IsItalic = false,\n            HasStrikethrough = false,\n            HasUnderline = false,\n            HasOverline = false,\n            DecorationStyle = TextStyleConfiguration.TextDecorationStyle.Solid,\n            DecorationThickness = 1f,\n            Direction = TextDirection.Auto\n        };\n        \n        internal static TextStyle ParagraphSpacing { get; } = LibraryDefault with\n        {\n            Id = 2,\n            Size = 0,\n            LineHeight = 1\n        };\n\n        private volatile SkTextStyle? SkTextStyleCache;\n        private readonly object SkTextStyleCacheLock = new();\n        \n        internal SkTextStyle GetSkTextStyle()\n        {\n            if (SkTextStyleCache != null)\n                return SkTextStyleCache;\n\n            lock (SkTextStyleCacheLock)\n            {\n                if (SkTextStyleCache != null)\n                    return SkTextStyleCache;\n\n                var temp = CreateSkTextStyle();\n                SkTextStyleCache = temp;\n                return temp;\n            }\n        }\n\n        private SkTextStyle CreateSkTextStyle()\n        {\n            var fontFamilyTexts = FontFamilies.Select(x => new SkText(x)).ToList();\n\n            var result = new SkTextStyle(new TextStyleConfiguration\n            {\n                FontSize = CalculateTargetFontSize(),\n                FontWeight = (TextStyleConfiguration.FontWeights?)FontWeight ?? TextStyleConfiguration.FontWeights.Normal,\n                IsItalic = IsItalic ?? false,\n                \n                FontFamilies = GetFontFamilyPointers(fontFamilyTexts),\n                FontFeatures = GetFontFeatures(),\n                \n                ForegroundColor = Color ?? Colors.Black,\n                BackgroundColor = BackgroundColor ?? Colors.Transparent,\n                DecorationColor = DecorationColor ?? Colors.Black,\n                DecorationType = CreateDecoration(),\n                \n                DecorationMode = TextStyleConfiguration.TextDecorationMode.Through,\n                DecorationStyle = DecorationStyle ?? TextStyleConfiguration.TextDecorationStyle.Solid,\n                DecorationThickness = DecorationThickness ?? 1,\n                \n                LineHeight = LineHeight ?? NormalLineHeightCalculatedFromFontMetrics,\n                LetterSpacing = (LetterSpacing ?? 0) * (Size ?? 1),\n                WordSpacing = (WordSpacing ?? 0) * (Size ?? 1),\n                BaselineOffset = CalculateBaselineOffset(),\n            });\n            \n            fontFamilyTexts.ForEach(x => x.Dispose());\n            return result;\n\n            IntPtr[] GetFontFamilyPointers(IList<SkText> texts)\n            {\n                var result = new IntPtr[TextStyleConfiguration.FONT_FAMILIES_LENGTH];\n                \n                for (var i = 0; i < Math.Min(result.Length, texts.Count); i++)\n                    result[i] = texts[i].Instance;\n                \n                return result;\n            }\n            \n            TextStyleConfiguration.FontFeature[] GetFontFeatures(params (string name, int value)[] features)\n            {\n                var result = new TextStyleConfiguration.FontFeature[TextStyleConfiguration.FONT_FEATURES_LENGTH];\n\n                foreach (var (feature, index) in FontFeatures.Take(TextStyleConfiguration.FONT_FEATURES_LENGTH).Select((x, i) => (x, i)))\n                {\n                    result[index].Name = feature.Name;\n                    result[index].Value = feature.Enabled ? 1 : 0;\n                }\n                \n                return result;\n            }\n\n            TextStyleConfiguration.TextDecoration CreateDecoration()\n            {\n                var result = TextStyleConfiguration.TextDecoration.NoDecoration;\n                \n                if (HasUnderline == true)\n                    result |= TextStyleConfiguration.TextDecoration.Underline;\n                \n                if (HasStrikethrough == true)\n                    result |= TextStyleConfiguration.TextDecoration.LineThrough;\n                \n                if (HasOverline == true)\n                    result |= TextStyleConfiguration.TextDecoration.Overline;\n                \n                return result;\n            }\n\n            float CalculateTargetFontSize()\n            {\n                var fontSize = Size ?? 0;\n                \n                if (FontPosition is Infrastructure.FontPosition.Subscript or Infrastructure.FontPosition.Superscript)\n                    return fontSize * 0.6f;\n   \n                return fontSize;\n            }\n            \n            float CalculateBaselineOffset()\n            {\n                if (FontPosition == Infrastructure.FontPosition.Subscript)\n                    return Size.Value * 0.25f;\n                \n                if (FontPosition == Infrastructure.FontPosition.Superscript)\n                    return -Size.Value * 0.35f;\n\n                return 0;\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/TextStyleManager.cs",
    "content": "﻿using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Reflection;\n\nusing TextStyleFontFeature = (string Name, bool Enabled);\n\nnamespace QuestPDF.Infrastructure\n{\n    internal enum TextStyleProperty\n    {\n        Color,\n        BackgroundColor,\n        DecorationColor,\n        FontFamilies,\n        FontFeatures,\n        Size,\n        LineHeight,\n        LetterSpacing,\n        WordSpacing,\n        FontWeight,\n        FontPosition,\n        IsItalic,\n        HasStrikethrough,\n        HasUnderline,\n        HasOverline,        \n        DecorationStyle,   \n        DecorationThickness,\n        Direction\n    }\n\n    // C# does not have proper equality members for arrays\n    // this struct is a wrapper that allows to use an array as part of dictionary key\n    internal struct ArrayContainer<T>\n    {\n        public T[] Items { get; }\n\n        public ArrayContainer(object array)\n        {\n            Items = (array as T[]) ?? Array.Empty<T>();\n        }\n        \n        public bool Equals(ArrayContainer<T> other)\n        {\n            return Items.SequenceEqual(other.Items);\n        }\n        \n        public override bool Equals(object obj)\n        {\n            return obj is ArrayContainer<T> other && Equals(other);\n        }\n        \n        public override int GetHashCode()\n        {\n            if (Items.Length == 1)\n                return Items[0].GetHashCode();\n            \n            unchecked\n            {\n                var hash = 19;\n                \n                foreach (var item in Items)\n                    hash = hash * 31 + item.GetHashCode();\n                \n                return hash;\n            }\n        }\n    }\n    \n    internal static class TextStyleManager\n    {\n        private static readonly List<TextStyle> TextStyles = new()\n        {\n            TextStyle.Default,\n            TextStyle.LibraryDefault,\n            TextStyle.ParagraphSpacing\n        };\n\n        private static readonly ConcurrentDictionary<(int originId, TextStyleProperty property, object value), TextStyle> TextStyleMutateCache = new();\n        private static readonly ConcurrentDictionary<(int originId, int parentId), TextStyle> TextStyleApplyInheritedCache = new();\n        private static readonly ConcurrentDictionary<int, TextStyle> TextStyleApplyGlobalCache = new();\n        private static readonly ConcurrentDictionary<(int originId, int parentId), TextStyle> TextStyleOverrideCache = new();\n        \n        private static readonly object MutationLock = new();\n\n        public static TextStyle Mutate(this TextStyle origin, TextStyleProperty property, object value)\n        {\n            if (property is TextStyleProperty.FontFamilies)\n                value = new ArrayContainer<string>(value);\n            \n            if (property is TextStyleProperty.FontFeatures)\n                value = new ArrayContainer<TextStyleFontFeature>(value);\n            \n            var cacheKey = (origin.Id, property, value);\n            \n            return TextStyleMutateCache.GetOrAdd(cacheKey, x =>\n            {\n                var newValue = x.value;\n                \n                if (x.value is ArrayContainer<string> fontFamilies)\n                    newValue = fontFamilies.Items;\n                \n                if (x.value is ArrayContainer<TextStyleFontFeature> fontFeatures)\n                    newValue = fontFeatures.Items;\n   \n                return MutateStyle(TextStyles[x.originId], x.property, newValue, overrideValue: true);\n            });\n        }\n\n        private static TextStyle MutateStyle(this TextStyle origin, TextStyleProperty targetProperty, object? newValue, bool overrideValue)\n        {\n            if (targetProperty == TextStyleProperty.FontFamilies)\n                return MutateFontFamily(origin, newValue as string[], overrideValue);\n            \n            if (targetProperty == TextStyleProperty.FontFeatures)\n                return MutateFontFeatures(origin, newValue as TextStyleFontFeature[], overrideValue);\n \n            lock (MutationLock)\n            {\n                if (overrideValue && newValue is null)\n                    return origin;\n                \n                var property = typeof(TextStyle).GetProperty(targetProperty.ToString(), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n                Debug.Assert(property != null);\n                \n                var oldValue = property.GetValue(origin);\n                \n                if (!overrideValue && oldValue is not null)\n                    return origin;\n\n                if (oldValue == newValue) \n                    return origin;\n                \n                var newIndex = TextStyles.Count;\n                var newTextStyle = origin with { Id = newIndex };\n                property.SetValue(newTextStyle, newValue);\n\n                TextStyles.Add(newTextStyle);\n                return newTextStyle;\n            }\n        }\n        \n        private static TextStyle MutateFontFamily(this TextStyle origin, string[]? newValue, bool overrideValue)\n        {\n            lock (MutationLock)\n            {\n                if (overrideValue && newValue is null)\n                    return origin;\n                \n                newValue ??= Array.Empty<string>();\n                var oldValue = origin.FontFamilies ?? Array.Empty<string>();\n                \n                if (origin.FontFamilies?.SequenceEqual(newValue) == true)\n                    return origin;\n                \n                var newIndex = TextStyles.Count;\n                var newTextStyle = origin with { Id = newIndex };\n                \n                newTextStyle.FontFamilies = overrideValue \n                    ? newValue \n                    : oldValue.Concat(newValue).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToArray();\n\n                TextStyles.Add(newTextStyle);\n                return newTextStyle;\n            }\n        }\n        \n        private static TextStyle MutateFontFeatures(this TextStyle origin, TextStyleFontFeature[]? newValue, bool overrideValue)\n        {\n            lock (MutationLock)\n            {\n                if (overrideValue && newValue is null)\n                    return origin;\n                \n                newValue ??= [];\n                var oldValue = origin.FontFeatures ?? [];\n                \n                if (origin.FontFeatures?.SequenceEqual(newValue) == true)\n                    return origin;\n\n                var extendedSet = overrideValue\n                    ? newValue.Concat(oldValue)\n                    : oldValue.Concat(newValue);\n                \n                var newIndex = TextStyles.Count;\n                var newTextStyle = origin with { Id = newIndex };\n                \n                newTextStyle.FontFeatures = extendedSet\n                    .GroupBy(x => x.Name)\n                    .Select(x => x.First())\n                    .ToArray();\n\n                TextStyles.Add(newTextStyle);\n                return newTextStyle;\n            }\n        }\n        \n        internal static TextStyle ApplyInheritedStyle(this TextStyle style, TextStyle parent)\n        {\n            return TextStyleApplyInheritedCache.GetOrAdd((style.Id, parent.Id), key => ApplyStyleProperties(key.originId, key.parentId, overrideStyle: false));\n        }\n        \n        internal static TextStyle ApplyGlobalStyle(this TextStyle style)\n        {\n            return TextStyleApplyGlobalCache.GetOrAdd(style.Id, key => ApplyStyleProperties(key, TextStyle.LibraryDefault.Id, overrideStyle: false));\n        }\n\n        internal static TextStyle OverrideStyle(this TextStyle style, TextStyle parent)\n        {\n            return TextStyleOverrideCache.GetOrAdd((style.Id, parent.Id), key => ApplyStyleProperties(key.originId, key.parentId, overrideStyle: true));\n        }\n        \n        private static TextStyle ApplyStyleProperties(int styleId, int parentId, bool overrideStyle)\n        {\n            var style = TextStyles[styleId];\n            var parent = TextStyles[parentId];\n            \n            return Enum\n                .GetValues(typeof(TextStyleProperty))\n                .Cast<TextStyleProperty>()\n                .Aggregate(style, (mutableStyle, nextProperty) =>\n                {\n                    var getParentProperty = typeof(TextStyle).GetProperty(nextProperty.ToString(), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n                    Debug.Assert(getParentProperty != null);\n                    \n                    var newValue = getParentProperty.GetValue(parent);\n\n                    return mutableStyle.MutateStyle(nextProperty, newValue, overrideStyle);\n                });\n        }\n        \n        internal static TextStyle GetTextStyle(int id)\n        {\n            return TextStyles[id];\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/Unit.cs",
    "content": "﻿using System;\nusing static QuestPDF.Infrastructure.Unit;\n\nnamespace QuestPDF.Infrastructure\n{\n    public enum Unit\n    {\n        /// <summary>\n        /// Point is a standard unit for all PDF documents.\n        /// 72 points equal 1 inch\n        /// </summary>\n        Point,\n            \n        Meter,\n            \n        Centimetre,\n        Millimetre,\n        \n        Feet,\n        Inch,\n        \n        /// <summary>\n        /// 1/1000th of inch\n        /// </summary>\n        Mil\n    }\n\n    internal static class UnitExtensions\n    {\n        private const float InchToCentimetre = 2.54f;\n        private const float InchToPoints = 72;\n        \n        public static float ToPoints(this float value, Unit unit)\n        {\n            return value * GetConversionFactor();\n            \n            float GetConversionFactor()\n            {\n                return unit switch\n                {\n                    Point => 1,\n                    Meter => 100 / InchToCentimetre * InchToPoints,\n                    Centimetre => 1 / InchToCentimetre * InchToPoints,\n                    Millimetre => 0.1f / InchToCentimetre * InchToPoints,\n                    Feet => 12 * InchToPoints,\n                    Inch => InchToPoints,\n                    Mil => InchToPoints / 1000f,\n                    _ => throw new ArgumentOutOfRangeException(nameof(unit), unit, null)\n                };\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Infrastructure/VerticalAlignment.cs",
    "content": "namespace QuestPDF.Infrastructure\n{\n    public enum VerticalAlignment\n    {\n        Top,\n        Middle,\n        Bottom\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/LatoFont/OFL.txt",
    "content": "Copyright (c) 2010-2014 by tyPoland Lukasz Dziedzic (team@latofonts.com) with Reserved Font Name \"Lato\"\n\nThis Font Software is licensed under the SIL Open Font License, Version 1.1.\nThis license is copied below, and is also available with a FAQ at:\nhttp://scripts.sil.org/OFL\n\n\n-----------------------------------------------------------\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n-----------------------------------------------------------\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded, \nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE.\n"
  },
  {
    "path": "Source/QuestPDF/Qpdf/JobConfiguration.cs",
    "content": "using System.Collections.Generic;\n\nnamespace QuestPDF.Qpdf;\n\nusing Name = SimpleJsonPropertyNameAttribute;\n\nsealed class JobConfiguration\n{\n    [Name(\"inputFile\")] public string InputFile { get; set; }\n    [Name(\"password\")] public string? Password { get; set; }\n    \n    [Name(\"outputFile\")] public string OutputFile { get; set; }\n    \n    [Name(\"pages\")] public ICollection<PageConfiguration>? Pages { get; set; }\n    [Name(\"overlay\")] public ICollection<LayerConfiguration>? Overlay { get; set; }\n    [Name(\"underlay\")] public ICollection<LayerConfiguration>? Underlay { get; set; }\n\n    [Name(\"extendMetadata\")] public string? ExtendMetadata { get; set; }\n    [Name(\"addAttachment\")] public ICollection<AddDocumentAttachment>? AddAttachment { get; set; }\n    \n    [Name(\"encrypt\")] public EncryptionSettings? Encrypt { get; set; } \n    [Name(\"allowWeakCrypto\")] public string AllowWeakCrypto { get; set; } = string.Empty;\n    [Name(\"decrypt\")] public string? Decrypt { get; set; } \n    [Name(\"removeRestrictions\")] public string? RemoveRestrictions { get; set; } \n    [Name(\"linearize\")] public string? Linearize { get; set; }\n    [Name(\"newlineBeforeEndstream\")] public string? NewlineBeforeEndstream { get; set; } = string.Empty;\n    \n    [Name(\"keepFilesOpen\")] public string? KeepFilesOpen { get; set; } = \"n\";\n    \n    internal sealed class PageConfiguration\n    {\n        [Name(\"file\")] public string File { get; set; }\n        [Name(\"range\")] public string Range { get; set; }\n    }\n    \n    internal sealed class LayerConfiguration\n    {\n        [Name(\"file\")] public string File { get; set; }\n        [Name(\"to\")] public string? To { get; set; }\n        [Name(\"from\")] public string? From { get; set; }\n        [Name(\"repeat\")] public string? Repeat { get; set; }\n    }\n    \n    public sealed class AddDocumentAttachment\n    {\n        [Name(\"key\")] public string Key { get; set; }\n        [Name(\"file\")] public string File { get; set; }\n        [Name(\"filename\")] public string? FileName { get; set; }\n        [Name(\"creationdate\")] public string? CreationDate { get; set; }\n        [Name(\"moddate\")] public string? ModificationDate { get; set; }\n        [Name(\"mimetype\")] public string? MimeType { get; set; }\n        [Name(\"description\")] public string? Description { get; set; }\n        [Name(\"replace\")] public string? Replace { get; set; }\n        [Name(\"relationship\")] public string? Relationship { get; set; }\n    }\n\n    public sealed class EncryptionSettings\n    {\n        [Name(\"userPassword\")] public string? UserPassword { get; set; }\n        [Name(\"ownerPassword\")] public string OwnerPassword { get; set; }\n        \n        [Name(\"40bit\")] public Encryption40Bit? Options40Bit { get; set; }\n        [Name(\"128bit\")] public Encryption128Bit? Options128Bit { get; set; }\n        [Name(\"256bit\")] public Encryption256Bit? Options256Bit { get; set; }\n    }\n    \n    public sealed class Encryption40Bit\n    {\n        [Name(\"annotate\")] public string Annotate { get; set; }\n        [Name(\"extract\")] public string Extract { get; set; } \n        [Name(\"modify\")] public string Modify { get; set; }\n        [Name(\"print\")] public string Print { get; set; }\n    }\n\n    public sealed class Encryption128Bit\n    {\n        [Name(\"annotate\")] public string Annotate { get; set; }\n        [Name(\"assemble\")] public string Assemble { get; set; }\n        [Name(\"extract\")] public string Extract { get; set; }\n        [Name(\"form\")] public string Form { get; set; }\n        [Name(\"print\")] public string? Print { get; set; }\n        [Name(\"useAes\")] public string? UseAES { get; set; } = \"y\";\n        [Name(\"cleartextMetadata\")] public string? CleartextMetadata { get; set; }\n    }\n\n    public sealed class Encryption256Bit\n    {\n        [Name(\"annotate\")] public string Annotate { get; set; }\n        [Name(\"assemble\")] public string Assemble { get; set; }\n        [Name(\"extract\")] public string Extract { get; set; }\n        [Name(\"form\")] public string Form { get; set; }\n        [Name(\"print\")] public string? Print { get; set; }\n        [Name(\"cleartextMetadata\")] public string? CleartextMetadata { get; set; }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Qpdf/MimeHelper.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace QuestPDF.Qpdf;\n\nstatic class MimeHelper\n{\n    public static readonly IReadOnlyDictionary<string, string> FileExtensionToMimeConversionTable = LoadMimeMapping();\n\n    private static IReadOnlyDictionary<string, string> LoadMimeMapping()\n    {\n        using var stream = Assembly\n            .GetExecutingAssembly()\n            .GetManifestResourceStream(\"QuestPDF.Resources.MimeTypes.csv\");\n        \n        using var streamReader = new StreamReader(stream);\n        var text = streamReader.ReadToEnd();\n\n        return text\n            .Split('\\n')\n            .Select(x => x.Split(','))\n            .ToDictionary(x => x.First(), x => x.Last());\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Qpdf/QpdfAPI.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.Qpdf;\n\nstatic class QpdfAPI\n{\n    public static string? GetQpdfVersion()\n    {\n        var ptr = API.qpdf_get_qpdf_version();\n        return Marshal.PtrToStringAnsi(ptr);\n    }\n    \n    public static void ExecuteJob(string jobJson)\n    {\n        QpdfNativeDependencyCompatibilityChecker.Test();\n        \n        // create StringBuilder that will store the error message\n        var error = new StringBuilder();\n        var errorHandle = GCHandle.Alloc(error);\n        var errorPtr = GCHandle.ToIntPtr(errorHandle);\n        \n        // create logger\n        var logger = API.qpdflogger_create();\n        API.qpdflogger_set_error(logger, 4, LoggingCallbackPointer, errorPtr); // 4 = custom logger\n        \n        // perform the job\n        var jobHandle = API.qpdfjob_init();\n        API.qpdfjob_set_logger(jobHandle, logger);\n        API.qpdfjob_initialize_from_json(jobHandle, jobJson);\n        var jobResultId = API.qpdfjob_run(jobHandle);\n        API.qpdfjob_cleanup(jobHandle);\n        \n        // logger cleanup\n        API.qpdflogger_cleanup(logger);\n        \n        // check errors\n        var isError = jobResultId is 2; // 0 = success, 1 = undefined, 2 = error, 3 = warning\n        \n        var errorMessage = error.ToString();\n        errorHandle.Free();\n        \n        if (isError)\n            throw new Exception($\"QuestPDF could not perform document operation:\\n\\n{errorMessage}\");\n    }\n    \n    #region Logging\n    \n    private static int LoggingCallback(IntPtr data, int length, IntPtr udata)\n    {\n        var bytes = new byte[length];\n        Marshal.Copy(data, bytes, 0, length);\n\n        var handle = GCHandle.FromIntPtr(udata);\n        var stringBuilder = (StringBuilder)handle.Target;\n        stringBuilder?.Append(Encoding.ASCII.GetString(bytes));\n\n        return 0;\n    }\n    \n    private delegate int CallbackDelegate(IntPtr data, int length, IntPtr udata);\n    private static readonly CallbackDelegate LoggingCallbackDelegate = LoggingCallback;\n    private static readonly IntPtr LoggingCallbackPointer = Marshal.GetFunctionPointerForDelegate(LoggingCallbackDelegate);\n    \n    #endregion\n    \n    private static class API\n    {\n        const string LibraryName = \"qpdf\";\n        \n        /* GENERAL */\n        \n        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr qpdf_get_qpdf_version();\n    \n        /* JOBS */\n        \n        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr qpdfjob_init();\n    \n        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void qpdfjob_cleanup(IntPtr jobHandle);\n    \n        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern int qpdfjob_initialize_from_json(IntPtr jobHandle, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string json);\n\n        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern int qpdfjob_run(IntPtr jobHandle);\n        \n        /* LOGGING */\n        \n        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = nameof(qpdflogger_create))]\n        public static extern IntPtr qpdflogger_create();\n\n        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = nameof(qpdflogger_cleanup))]\n        public static extern void qpdflogger_cleanup(IntPtr loggerHandle);\n        \n        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = nameof(qpdflogger_set_error))]\n        public static extern void qpdflogger_set_error(IntPtr loggerHandle, int destination, IntPtr callBackHandler, IntPtr udata);\n        \n        [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl, EntryPoint = nameof(qpdfjob_set_logger))]\n        public static extern void qpdfjob_set_logger(IntPtr jobHandle, IntPtr loggerHandle);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Qpdf/QpdfNativeDependencyCompatibilityChecker.cs",
    "content": "using System;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.Qpdf;\n\ninternal static class QpdfNativeDependencyCompatibilityChecker\n{\n    private static NativeDependencyCompatibilityChecker Instance { get; } = new()\n    {\n        ExecuteNativeCode = ExecuteNativeCode,\n        ExceptionHint = GetHint\n    };\n    \n    public static void Test()\n    {\n        Instance.Test();\n    }\n    \n    private static void ExecuteNativeCode()\n    {\n        var qpdfVersion = QpdfAPI.GetQpdfVersion();\n        \n        if (string.IsNullOrEmpty(qpdfVersion))\n            throw new Exception();\n    }\n\n    private static string GetHint()\n    {\n        return $\"Please do NOT install the qpdf package.\";\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Qpdf/SimpleJsonSerializer.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\n\nnamespace QuestPDF.Qpdf;\n\nsealed class SimpleJsonPropertyNameAttribute(string name) : Attribute\n{\n    public string Name { get; } = name;\n}\n\n/// <summary>\n/// Never use in performance critical scenarios!\n/// </summary>\nstatic class SimpleJsonSerializer\n{\n    public static string Serialize(object obj)\n    {\n        if (obj == null) \n            return \"null\";\n\n        var type = obj.GetType();\n        var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);\n        \n        var stringBuilder = new StringBuilder();\n        stringBuilder.Append('{');\n\n        foreach (var property in properties)\n        {\n            var value = property.GetValue(obj);\n            \n            if (value == default)\n                continue;\n            \n            var name = property.GetCustomAttribute<SimpleJsonPropertyNameAttribute>().Name;\n            stringBuilder.Append($\"\\\"{name}\\\": {SerializeValue(value)}\");\n            stringBuilder.Append(\", \");\n        }\n        \n        if (properties.Length > 1) \n            stringBuilder.Length -= 2;\n\n        stringBuilder.Append('}');\n        return stringBuilder.ToString();\n    }\n\n    private static string SerializeValue(object value)\n    {\n        if (value == null) \n            return \"null\";\n        \n        if (value is string text) \n            return $\"\\\"{EscapeStringForJson(text)}\\\"\";\n        \n        if (value is bool)\n            return value.ToString().ToLower();\n        \n        if (value is IEnumerable<object> enumerable)\n        {\n            var stringBuilder = new StringBuilder();\n            stringBuilder.Append('[');\n\n            foreach (var item in enumerable)\n                stringBuilder.Append($\"{SerializeValue(item)}, \");\n            \n            // remove trailing comma and space\n            if (enumerable.Any()) \n                stringBuilder.Length -= 2;\n            \n            stringBuilder.Append(']');\n            return stringBuilder.ToString();\n        }\n        \n        if (!value.GetType().IsPrimitive)\n            return Serialize(value);\n        \n        return value.ToString();\n    }\n\n    private static string EscapeStringForJson(string input)\n    {\n        if (string.IsNullOrEmpty(input))\n            return input;\n\n        var builder = new StringBuilder(input.Length);\n\n        foreach (char c in input)\n        {\n            if (c == '\\\\')\n                builder.Append(\"\\\\\\\\\");\n            \n            else if (c == '\"')\n                builder.Append(\"\\\\\\\"\");\n            \n            else if (c == '\\b')\n                builder.Append(\"\\\\b\");\n            \n            else if (c == '\\f')\n                builder.Append(\"\\\\f\");\n            \n            else if (c == '\\n')\n                builder.Append(\"\\\\n\");\n            \n            else if (c == '\\r')\n                builder.Append(\"\\\\r\");\n            \n            else if (c == '\\t')\n                builder.Append(\"\\\\t\");\n            \n            else\n                builder.Append(c);\n        }\n\n        return builder.ToString();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/QuestPDF.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n    <PropertyGroup>\n        <Authors>MarcinZiabek</Authors>\n        <Company>CodeFlint</Company>\n        <PackageId>QuestPDF</PackageId>\n        <Version>2026.2.4</Version>\n        <PackageDescription>QuestPDF is a modern library for PDF document generation. Its fluent C# API lets you design complex layouts with clean, readable code. Create invoices, reports, and documents using a flexible, component-based approach.</PackageDescription>\n        <PackageReleaseNotes>$([System.IO.File]::ReadAllText(\"$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt\"))</PackageReleaseNotes>\n        <LangVersion>13</LangVersion>\n        <Deterministic>true</Deterministic>\n        <EnablePackageValidation>true</EnablePackageValidation>\n        <PackageIcon>Logo.png</PackageIcon>\n        <PackageIconUrl>https://www.questpdf.com/logo.webp</PackageIconUrl>\n        <PackageProjectUrl>https://www.questpdf.com/</PackageProjectUrl>\n        <PackageLicenseFile>PackageLicense.md</PackageLicenseFile>\n        <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>\n        <PackageReadmeFile>README.md</PackageReadmeFile>\n        <RepositoryUrl>https://github.com/QuestPDF/library.git</RepositoryUrl>\n        <RepositoryType>git</RepositoryType>\n        <Copyright>Marcin Ziąbek, QuestPDF contributors</Copyright>\n        <PackageTags>pdf generation creation export merge edit html</PackageTags>\n        <Nullable>enable</Nullable>\n        <TargetFrameworks>net10.0;net8.0;net6.0;netstandard2.0</TargetFrameworks>\n        <IncludeSymbols>true</IncludeSymbols>\n        <SymbolPackageFormat>snupkg</SymbolPackageFormat>\n        <GenerateDocumentationFile>True</GenerateDocumentationFile>\n        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n    </PropertyGroup>\n\n    <PropertyGroup Condition=\"'$(BUILD_PACKAGE)' == 'true'\">\n        <GeneratePackageOnBuild>true</GeneratePackageOnBuild>\n        <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>\n        <SignAssembly>true</SignAssembly>\n        <AssemblyOriginatorKeyFile>NugetStrongNameSigningKeyForQuestPDF.snk</AssemblyOriginatorKeyFile>\n    </PropertyGroup>\n    \n    <ItemGroup Condition=\"'$(BUILD_PACKAGE)' == ''\">\n        <InternalsVisibleTo Include=\"DynamicProxyGenAssembly2\" />\n        <InternalsVisibleTo Include=\"QuestPDF.UnitTests\" />\n        <InternalsVisibleTo Include=\"QuestPDF.LayoutTests\" />\n        <InternalsVisibleTo Include=\"QuestPDF.VisualTests\" />\n        <InternalsVisibleTo Include=\"QuestPDF.ConformanceTests\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <None Include=\"Resources\\**\\*.*\">\n            <Pack>true</Pack>\n            <PackagePath>%(RecursiveDir)\\%(Filename)%(Extension)</PackagePath>\n        </None>\n        \n        <None Include=\"LatoFont\\*.*\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n            <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n            <Pack>true</Pack>\n            <PackagePath>LatoFont</PackagePath>\n        </None>\n        \n        <None Include=\"Runtimes\\**\\*.*\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n            <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n            <Pack>true</Pack>\n            <TargetPath>runtimes\\%(RecursiveDir)%(Filename)%(Extension)</TargetPath>\n            <PackagePath>runtimes\\%(RecursiveDir)%(Filename)%(Extension)</PackagePath>\n        </None>\n\n        <None Include=\"Build\\**\\*.*\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n            <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>\n            <Pack>true</Pack>\n            <PackagePath>build\\%(RecursiveDir)%(Filename)%(Extension);buildTransitive\\%(RecursiveDir)%(Filename)%(Extension)</PackagePath>\n        </None>\n        \n        <None Include=\"Resources\\Description.md\" Pack=\"true\" PackagePath=\"README.md\" />\n\n        <EmbeddedResource Include=\"Resources/MimeTypes.csv\" />\n        <EmbeddedResource Include=\"Resources/LatinWords.txt\" />\n    </ItemGroup>\n    \n    <ItemGroup Condition=\"'$(TargetFramework)' == 'netstandard2.0'\">\n      <PackageReference Include=\"System.Numerics.Vectors\" Version=\"4.6.1\" />\n    </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF/Resources/Contributors.md",
    "content": "The QuestPDF library is a community-driven project. We are truly thankful for everyone who has helped improve it, whether by contributing code or through other valuable means, such as offering assistance to others, participating in discussions, and testing. Your efforts are greatly appreciated and play a key role in our ongoing development.\n\n\n\nQuestPDF Contributors:\n- MarcinZiabek\n- girlpunk\n- bennetbo\n- AntonyCorbett\n- Lehonti\n- knoxyz\n- maartenba\n- loxsmoke\n- jnyrup\n- wieslawsoltes\n- thomasstevens89\n- sclarke81\n- simusr2\n- danielchalmers\n- fredericoregateiro\n- emanueleguastella\n- CollinAlpert\n- rstm-sf\n- warrantyvoids\n- SvizelPritula\n- avobelk\n- ceee\n- tinohager\n- schulz3000\n- ruyut\n- marcmognol\n- donmurta\n- jcl-aadlab\n- lmingle\n- JeremyVm\n- ebarnard\n- MercinaM\n- rima1098\n- JerryZingg\n\n\nYou can always find the most up-to-date list at: https://github.com/QuestPDF/QuestPDF/graphs/contributors\n\n\n\nQuestPDF.Documentation Contributors:\n- MarcinZiabek\n- AntonyCorbett\n- Thorinos\n- jerone\n- enricobenedos\n- Ducki\n- jnyrup\n- Scarso327\n- jz5\n- jordansrowles\n- Tvde1\n- pablopioli\n\nYou can always find the most up-to-date list at: https://github.com/QuestPDF/QuestPDF-Documentation/graphs/contributors\n\n\n\nIf you notice that our list is out of date or if someone should be added, please let us know by emailing us at contact@questpdf.com. We aim to keep it accurate and will make updates as quickly as we can. Thank you for your help!\n"
  },
  {
    "path": "Source/QuestPDF/Resources/Description.md",
    "content": "## QuestPDF - Modern PDF library for C# developers\n\nQuestPDF is a production-ready library that lets you design documents the way you design software: with clean, maintainable, strong-typed C# code.\nStop fighting with HTML-to-PDF conversion. Build pixel-perfect reports, invoices, and exports using the language and tools you already love.\n\n[![GitHub Stars and Stargazers](https://img.shields.io/github/stars/QuestPDF/QuestPDF?style=for-the-badge&label=GitHub%20Stars&logo=github&color=FFEB3B&logoColor=white)](https://github.com/QuestPDF/QuestPDF)\n\n[![Nuget package download](https://img.shields.io/nuget/dt/QuestPDF?style=for-the-badge&label=NuGet%20downloads&logo=nuget&color=0277BD&logoColor=white)](https://www.nuget.org/packages/QuestPDF/)\n\n[![QuestPDF License](https://img.shields.io/badge/LICENSE-Community%20and%20commercial-2E7D32?style=for-the-badge&logo=googledocs&logoColor=white)](https://www.questpdf.com/license.html)\n\n---\n\n[Home Page](https://www.questpdf.com)\n\n[Quick Start](https://www.questpdf.com/quick-start.html)\n\n[Real-world Invoice Tutorial](https://www.questpdf.com/invoice-tutorial.html)\n\n[Features Overview](https://www.questpdf.com/features-overview.html)\n\n[License](https://www.questpdf.com/license/)\n\n[NuGet](https://www.nuget.org/packages/QuestPDF)\n\n---\n\n## 🚀 Quick start\n\nLearn how easy it is to design, implement and generate PDF documents using QuestPDF.\nEffortlessly create documents of all types such as invoices and reports.\n\n```c#\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\n// set your license here:\n// QuestPDF.Settings.License = LicenseType.Community;\n\nDocument.Create(container =>\n{\n    container.Page(page =>\n    {\n        page.Size(PageSizes.A4);\n        page.Margin(2, Unit.Centimetre);\n        page.PageColor(Colors.White);\n        page.DefaultTextStyle(x => x.FontSize(20));\n        \n        page.Header()\n            .Text(\"Hello PDF!\")\n            .SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);\n        \n        page.Content()\n            .PaddingVertical(1, Unit.Centimetre)\n            .Column(x =>\n            {\n                x.Spacing(20);\n                \n                x.Item().Text(Placeholders.LoremIpsum());\n                x.Item().Image(Placeholders.Image(200, 100));\n            });\n        \n        page.Footer()\n            .AlignCenter()\n            .Text(x =>\n            {\n                x.Span(\"Page \");\n                x.CurrentPageNumber();\n            });\n    });\n})\n.GeneratePdf(\"hello.pdf\");\n```\n\nThe code above produces the following PDF document:\n\n![Preview of a PDF document showing the Hello World example](https://raw.githubusercontent.com/QuestPDF/QuestPDF-Documentation/f6b28c965e26fe43630316f589339db465c8197e/docs/public/nuget/hello-world.png)\n\n[![Quick Start Tutorial](https://img.shields.io/badge/read-tutorial-0288D1?style=for-the-badge)](https://www.questpdf.com/quick-start.html)\n\n> The library is free for individuals, non-profits, all FOSS projects, and organizations under $1M in annual revenue.\n> Read more about licensing [here](https://www.questpdf.com/license/)\n\n\n## Everything you need to generate PDFs\n\nFrom layout and styling to production features, QuestPDF gives you the flexibility to create documents of any complexity.\n\n### 🎨 Visual Content:\n- Page attributes (header, footer, background, watermark, margin),\n- Text (font style, paragraph style, page numbers),\n- Styled containers (background, border, rounded corners, colors and gradients, shadows),\n- Lines (vertical and horizontal, colors and gradients, dash pattern)\n- Images (PNG, JPG, WEBP, SVG),\n\n### 🔀 Layout:\n- Tables,\n- Lists,\n- Layers,\n- Column / Row,\n- Inlined,\n\n### 📐 Positional:\n- Alignment,\n- Size Controls (width / height),\n- Padding,\n\n### 🛠️ Other:\n- Page Breaking Control,\n- Aspect Ratio,\n- Integrations (maps, charts, barcodes, QR codes),\n- Hyperlinks,\n- Z-index,\n\n[![Explore All QuestPDF Features](https://img.shields.io/badge/explore%20all%20features-0288D1?style=for-the-badge)](https://www.questpdf.com/features-overview.html)\n\n\n## Familiar Programming Patterns\n\nUse your existing programming language and patterns to ship faster with less training.\n\nLoops, conditionals, functions are natively supported. Leverage IntelliSense, inspections, navigation, and safe refactoring.\n\n```csharp\ncontainer.Column(column =>\n{\n    column.Item().Text(\"Order Items\").Bold();\n\n    if (Model.ShowSummary)\n        column.Item().Element(ComposeOrderSummary);\n\n    foreach (var item in Model.Items)\n        column.Item().Element(c => ComposeItem(c, item));\n});\n```\n\nReview document changes like any other code. Get clean diffs, PR approvals, and traceable history.\n\n```diff\nvoid ComposeItem(IContainer container, OrderItem item)\n{\n    container\n        .Border(1, Colors.Grey.Darken2)\n        .Background(item.HighlightColor)\n-       .Padding(12)\n+       .Padding(16)\n        .Row(row =>\n        {\n            row.RelativeItem().Text(item.Name);\n            row.AutoItem().Text($\"{item.Price:F2} USD\");\n        });\n}\n```\n\n\n## Companion App\n\nAccelerate development with live document preview and hot-reload capability. See your changes instantly without recompiling.\n\n- Explore PDF document hierarchy and navigate its structure\n- Quickly magnify and measure content\n- Debug runtime exceptions with stack traces and code snippets\n- Identify, understand and solve layout errors\n\n![Screenshot showing the QuestPDF Companion App](https://raw.githubusercontent.com/QuestPDF/QuestPDF-Documentation/f6b28c965e26fe43630316f589339db465c8197e/docs/public/nuget/companion-light.png)\n\n[![Learn about QuestPDF Companion App](https://img.shields.io/badge/learn%20more-0288D1?style=for-the-badge)]([https://www.questpdf.com/companion/features.html](https://www.questpdf.com/companion/usage.html))\n\n[![Learn about QuestPDF Companion App](https://img.shields.io/badge/features-666666?style=for-the-badge)](https://www.questpdf.com/companion/features.html)\n\n\n## Enterprise-grade foundations\n\n- **Predictable Development** — Eliminate CSS debugging, browser quirks, and layout surprises common with HTML-to-PDF tools. What you code is what you get.\n\n- **Source-available** - Entire QuestPDF source code is available for review and customization, ensuring transparency and compliance with your organization's requirements.\n\n- **Complete Data Privacy** - QuestPDF runs entirely within your infrastructure with no external API calls, internet requirement, or background data collection. As a company, we do not access, collect, store, or process your private data.\n\n- **Comprehensive Layout Engine** - A powerful layout engine built specifically for PDF generation. Gain full control over document structure, precise content positioning, and automatic pagination.\n\n- **Advanced Language Support** - Create multilingual documents with full RTL language support, advanced text shaping, and bi-directional layout handling.\n\n- **High Performance** - Generate thousands of pages per second while maintaining minimal CPU and memory usage. Perfect for high-throughput enterprise applications.\n\n- **Optimized File Size** - Drastically reduce file sizes without compromising quality. Benefit from automatic font subsetting, optimal image compression, and efficient file compression.\n\n\n\n## Perform common PDF operations\n\nLeverage a powerful C# Fluent API to create, customize, and manage your PDF documents with ease.\n- Merge documents\n- Attach files\n- Extract pages\n- Encrypt / decrypt\n- Extend metadata\n  – Limit access\n- Optimize for Web\n- Overlay / underlay\n\n```c#\nDocumentOperation\n    .LoadFile(\"input.pdf\")\n    .TakePages(\"1-10\")\n    .MergeFile(\"appendix.pdf\", \"1-z\") // all pages\n    .AddAttachment(new DocumentAttachment\n    {\n        FilePath = \"metadata.xml\"\n    })\n    .Encrypt(new Encryption256Bit\n    {\n        OwnerPassword = \"mypassword\",\n        AllowPrinting = true,\n        AllowContentExtraction = false\n    })\n    .Save(\"final-document.pdf\");\n```\n\n[![Learn Document Operation API](https://img.shields.io/badge/learn%20more-0288D1?style=for-the-badge)](https://www.questpdf.com/concepts/document-operations.html)\n\n\n## Works everywhere you do\n\nDeploy on any major operating system and integrate seamlessly with your favorite IDEs, cloud platforms, and development tools.\n\n| Platform | Support |\n|----------|---------|\n| **Operating Systems** | Windows, Linux, macOS |\n| **Frameworks** | .NET 6+ and .NET Framework 4.6.2+ |\n| **Cloud** | Azure, AWS, Google Cloud, Others |\n| **Containers** | Docker, Kubernetes |\n| **IDEs** | Visual Studio, VS Code, JetBrains Rider, Others |\n\n\n\n## Industry-standard PDF compliance\n\nGenerate PDF documents that meet the strictest archival and accessibility requirements. Every build is automatically validated using the open-source veraPDF and Mustang tools.\n\n- PDF/A (Archival):\n    - Purpose: ISO 19005 standard for long-term preservation. Ensures PDFs remain readable and visually identical for decades without external dependencies.\n    - Supported Standards: `PDF/A-2b`, `PDF/A-2u`, `PDF/A-2a`, `PDF/A-3b`, `PDF/A-3u`, `PDF/A-3a`\n\n- PDF/UA (Accessibility):\n    - Purpose: ISO 14289 standard for universal accessibility. Includes full support for screen readers and assistive technologies for people with disabilities.\n    - Supported Standards: `PDF/UA-1`\n\n- EN 16931 (E-Invoicing):\n    - Purpose: European standard for electronic invoicing. Embeds structured invoice data (XML) within PDF documents for automated processing.\n    - Supported Standards: `ZUGFeRD`, `Factur-X`\n\n\n\n## Fair and Sustainable License\n\nA model that benefits everyone. Commercial licensing provides businesses with legal safety and long-term stability, while funding a feature-complete, unrestricted library for the open-source community.\n\n- Actively maintained with regular feature, quality, and security updates\n- Full source code available on GitHub\n- All features included in every tier without restrictions\n- Predictable pricing: no per-seat, per-server, or usage fees\n\n> The library is free for individuals, non-profits, all FOSS projects, and organizations under $1M in annual revenue.\n\n[![QuestPDF Pricing](https://img.shields.io/badge/view%20pricing-388E3C?style=for-the-badge)](https://www.questpdf.com/license.html)\n\n[![QuestPDF License Terms](https://img.shields.io/badge/license%20terms-666666?style=for-the-badge)](https://www.questpdf.com/license/guide.html)\n\n\n\n## See a real-world example\n\nFollow our detailed tutorial and see how easy it is to generate a fully functional invoice with fewer than 250 lines of C# code.\n\n- Step-by-step guidance\n- Production-ready code\n- Best practices included\n\n![Preview of a PDF document being an output of the Real-World Invoice tutorial](https://raw.githubusercontent.com/QuestPDF/QuestPDF-Documentation/f6b28c965e26fe43630316f589339db465c8197e/docs/public/nuget/invoice.jpg)\n\n[![Read Real-world Invoice Tutorial](https://img.shields.io/badge/read%20tutorial-0288D1?style=for-the-badge)](https://www.questpdf.com/invoice-tutorial.html)\n\n\n## Community QuestPDF\n\nWe are incredibly grateful to our .NET Community for their positive reviews and recommendations of the QuestPDF library.\nYour support and feedback are invaluable and motivate us to keep improving and expanding this project.\nThank you for helping us grow and reach more developers!\n\n### Nick Chapsas: The Easiest Way to Create PDFs in .NET\n\n[![Nick Chapsas The Easiest Way to Create PDFs in .NET](https://raw.githubusercontent.com/QuestPDF/QuestPDF-Documentation/f6b28c965e26fe43630316f589339db465c8197e/docs/public/nuget/youtube-nick-chapsas.jpg)](https://www.youtube.com/watch?v=_M0IgtGWnvE)\n\n### JetBrains: OSS Power-Ups: QuestPDF\n\n[![JetBrains OSS Power-Ups: QuestPDF](https://raw.githubusercontent.com/QuestPDF/QuestPDF-Documentation/f6b28c965e26fe43630316f589339db465c8197e/docs/public/nuget/youtube-jetbrains.jpg)](https://www.youtube.com/watch?v=-iYvZvpLX0g)\n"
  },
  {
    "path": "Source/QuestPDF/Resources/Documentation.xml",
    "content": "<documentation>\n    <!-- SHARED -->\n    \n    <doc for=\"colorParam\">\n        <param name=\"color\">Color in a <a href=\"https://www.questpdf.com/concepts/colors.html\">valid format</a> (like <c>#FF8800</c> for orange) or from the predefined <see cref=\"Colors\"/> set (like <c>Colors.Red.Lighten1</c>).</param>\n    </doc>\n\n    <doc for=\"param.sectionName\">\n        <param name=\"sectionName\">The text key corresponding to the value used when defining the <see cref=\"ElementExtensions.Section\">Section</see> element.</param>\n    </doc>\n\n    <doc for=\"param.url\">\n        <param name=\"url\">The URL of the webpage to which the user will be redirected.</param>\n    </doc>\n    \n    <!-- SCALE -->\n    \n    <doc for=\"scale.remarks\">\n        <remarks>\n            <para>Although this adjustment modifies the space available to its inner content, some elements might use their own strategies to fill that space.</para>\n            <para>For example, an Image with the <see cref=\"Infrastructure.ImageScaling.FitWidth\" /> setting may retain its size, but its quality could vary based on the DPI setting.</para>\n            <para>In contrast, text will not only appear smaller or bigger; but also a different number of words may fit each line.</para>\n        </remarks>\n    </doc>\n    \n    <doc for=\"scale.factorParam\">\n        <param name=\"factor\">The scaling factor. Values greater than one enlarge the content, while values less than one reduce it.</param>\n    </doc>\n\n    <!-- IMAGE -->\n    \n    <doc for=\"image.remarks\">\n        <remarks>\n            <para>\n                Please note that there is a significant difference between image resolution (number of pixels vertically and horizontally) and its physical size described in points.\n                Therefore, the resolution of an image is not used for determining its physical size on the document.\n            </para>\n\n            <para>\n                Multiple strategies exist for the Image element to determine its final size. \n                By default, the image fills all the available width. \n                This behavior can be customized using options within the <see cref=\"Fluent.ImageDescriptor\">descriptor</see> class.\n            </para>\n            \n            <para>\n                Images are automatically resized and compressed based on the descriptor's setup.\n                It defaults to <see cref=\"DocumentSettings\">global document's settings</see>.\n            </para>\n            \n            <para>Supported formats: PNG, JPEG and WEBP.</para>\n        </remarks>\n    </doc>\n\n    <doc for=\"image.useOriginalImage\">\n        <summary>\n            When enabled, the library does not resize the image to achieve the target DPI, nor compress it with target image quality.\n        </summary>\n    </doc>\n    \n    <doc for=\"image.rasterDPI\">\n        <summary>\n            <para>\n                Specifies the DPI (dots-per-inch) for rasterizing images, which is a measure of an image's resolution that indicates how many individual dots (or pixels) fit into one inch of a printed image. \n                Higher DPI values result in greater detail and sharpness, making images appear clearer when printed, while lower DPI values can cause images to look blurry or pixelated.\n            </para>\n            <para>The target resolution is computed by multiplying the DPI with the physical image size on the document.</para>\n            <para>Default DPI value is 288 DPI.</para>\n        </summary>\n        \n        <remarks>\n            If the image has lower resolution that the one calculated from the DPI setting, it will NOT be rescaled.\n        </remarks>\n        \n        <example>\n            Consider an image of dimensions 3x4 inches. Using a DPI value of 300, the final resolution translates to 900x1200 pixels.\n        </example>\n    </doc>\n\n    <doc for=\"image.compressionQuality\">\n        <summary>\n            <para>\n                Controls the balance between an image's file size and its visual fidelity during compression.\n                Higher quality values preserve more detail with larger file sizes, while lower values reduce file size at the cost of potential image degradation, such as blurriness or artifacts.\n            </para>\n            <para>Opaque images are JPEG-encoded based on this setting, while images with an alpha channel default to PNG format, disregarding this option.</para>\n            <para>Default is set to \"high quality\".</para>\n        </summary>\n    </doc>\n\n    <doc for=\"image.descriptor\">\n        <returns>Descriptor allowing adjustments to image attributes, such as scaling behavior, compression quality, and target DPI.</returns>\n    </doc>\n\n    <!-- SVG -->\n\n    <doc for=\"svg.remarks\">\n        <remarks>\n            Multiple strategies exist for the Image element to determine its final size.\n            By default, the image fills all the available width.\n            This behavior can be customized using options within the <see cref=\"Fluent.SvgImageDescriptor\">descriptor</see> class.\n        </remarks>\n    </doc>\n\n    <doc for=\"svg.descriptor\">\n        <returns>Descriptor allowing adjustments to the SVG image scaling behavior.</returns>\n    </doc>\n\n\n    <!-- CONTENT DIRECTION -->\n    \n    <doc for=\"contentDirection.ltr.remarks\">\n        <remarks>\n            <para>This writing system is used by most of modern languages.</para>\n            \n            <para>\n                The content direction affects various layout structures. In LTR mode, items are typically aligned to the left.\n                This mode also influences the direction of items in certain layouts. For instance, in a row element with LTR mode,\n                the first item is positioned on the left, while the last item is on the right.\n            </para>\n        </remarks>\n    </doc>\n\n    <doc for=\"contentDirection.rtl.remarks\">\n        <remarks>\n            <para>This writing system is used by languages such as Hebrew, Arabic, and Persian.</para>\n            \n            <para>\n                The content direction affects various layout structures. In RTL mode, items are typically aligned to the right.\n                This mode also influences the direction of items in certain layouts. For instance, in a row element with RTL mode,\n                the first item is positioned on the right, while the last item is on the left.\n            </para>\n        </remarks>\n    </doc>\n    \n    <!-- TEXT ELEMENT -->\n\n    <doc for=\"text.returns.spanDescriptor\">\n        <returns>Handler for adjusting the appearance of the text span, including attributes like color, size, and background.</returns>\n    </doc>\n\n    <doc for=\"text.returns.pageNumberDescriptor\">\n        <returns>\n            <para>Handler for adjusting the appearance of the text span, including attributes like color, size, and background.</para>\n            <para>Additionally, it provides formatting options, like displaying the page number in custom text format (e.g. Roman numerals).</para>\n        </returns>\n    </doc>\n\n    <doc for=\"text.clampLines\">\n        <summary>\n            Limits the number of visible lines in a paragraph, truncating overflow text with an ellipsis or by hiding it to maintain layout consistency.\n        </summary>\n    </doc>\n\n    <!-- TEXT ELEMENT -->\n\n    <doc for=\"text.alignment.left\">\n        <summary>\n        Aligns text horizontally to the left side.\n        </summary>\n    </doc>\n\n    <doc for=\"text.alignment.center\">\n        <summary>\n            Aligns text horizontally to the center, ensuring equal space on both left and right sides.\n        </summary>\n    </doc>\n\n    <doc for=\"text.alignment.right\">\n        <summary>\n            Aligns content horizontally to the right side.\n        </summary>\n    </doc>\n\n    <doc for=\"text.alignment.start\">\n        <summary>\n            Aligns the text horizontally to the start of the container.\n            This method sets the horizontal alignment of the text to the start (left for left-to-right languages, right for right-to-left languages).\n        </summary>\n    </doc>\n\n    <doc for=\"text.alignment.end\">\n        <summary>\n            Aligns the text horizontally to the end of the container.\n            This method sets the horizontal alignment of the text to the end (right for left-to-right languages, left for right-to-left languages).\n        </summary>\n    </doc>\n\n    <doc for=\"text.alignment.justify\">\n        <summary>\n            <para>\n            Justifies the text within its container.\n            </para>\n            \n            <para>\n            This method sets the horizontal alignment of the text to be justified, meaning it aligns along both the left and right margins.\n            This is achieved by adjusting the spacing between words and characters as necessary so that each line of text stretches from one end of the text column to the other.\n            This creates a clean, block-like appearance for the text.\n            </para>\n        </summary>\n    </doc>\n    \n    <!-- TEXT ATTRIBUTES -->\n\n    <doc for=\"text.fontColor\">\n        <summary>\n            Sets the font color.\n            The font color determines the color applied to text characters, affecting their visual appearance.\n        </summary>\n\n        <remarks>\n            It also influences the default color of text decorations, such as underlines.\n        </remarks>\n    </doc>\n\n    <doc for=\"text.backgroundColor\">\n        <summary>\n            Sets a solid background color for the text.\n            This color fills the area behind the text or other elements, enhancing contrast and providing visual emphasis.\n        </summary>\n    </doc>\n    \n    <doc for=\"text.fontFamily\">\n        <summary>\n            Sets the font family of the text.\n            A font family is a collection of related fonts that share a consistent design style but may vary in weight, style, or width.\n            Examples of font families include Arial, Times New Roman, and Calibri.\n        </summary>\n        \n        <remarks>\n            <para>By default, the library searches all fonts available in the runtime environment.</para>\n            <para>This may work well on the development environment but may fail in the cloud where fonts are usually not installed.</para>\n            <para>It is safest deploy font files along with the application and then register them using the <see cref=\"Drawing.FontManager\">FontManager</see> class.</para>\n        </remarks>\n        \n        <param name=\"value\">Actual font family (e.g. \"Times New Roman\", \"Calibri\", \"Lato\") or custom identifier used when invoking the <see cref=\"Drawing.FontManager.RegisterFontWithCustomName\">FontManager</see> method.</param>\n    </doc>\n\n    <doc for=\"text.fontFeatures\">\n        <summary>\n            <para>Enables or disables font features defined by the OpenType standard, e.g. kernig, ligatures.</para>\n            \n            <para>\n                Font features are always encoded as 4-character long strings. For example, the ligatures feature is encode as <c>liga</c>, while the kernig feature as <c>kern</c>.\n                For a list of available features, refer to the <see cref=\"QuestPDF.Helpers.FontFeatures\">FontFeatures</see> class.\n            </para>\n        </summary>\n\n        <remarks>\n            <para>To better understand what font features are, please consider example definitions. Please note that there are many more various font features. Most fonts support only a handful of them, having some of them enabled by default:</para>\n            <para>Ligatures in typography are specific character combinations that are designed to improve the aesthetics and readability of certain letter pairs. For example, in some fonts, when you type certain combinations of letters like 'fi' or 'fl', they will be replaced with a single, joined glyph.</para>\n            <para>Kerning in typography refers to the adjustment of space between characters in a proportional font. It's used to achieve a visually pleasing result by adjusting the spacing of specific character pairs. For example, in many fonts, the pair 'AV' is kerned so that the 'A' and 'V' are closer together than they would be by default.</para>\n        </remarks>\n\n        <example>\n            <para>TextStyle.Default.EnableFontFeature(FontFeatures.StandardLigatures);</para>\n            <para>TextStyle.Default.DisableFontFeature(FontFeatures.Kerning);</para>\n        </example>\n        \n        <param name=\"value\">Provide font feature name or use the <see cref=\"QuestPDF.Helpers.FontFeatures\">FontFeatures</see> class.</param>\n    </doc>\n    \n    <doc for=\"text.fontSize\">\n        <summary>\n            Sets font size for the text.\n            Font size measures the height of text characters, determining how large or small the text appears.\n        </summary>\n\n        <remarks>\n            It's worth noting that different fonts may render text with distinct visual sizes, even when assigned the same numerical font size.\n        </remarks>\n    </doc>\n\n    <doc for=\"text.wrapAnywhere\">\n        <summary>\n            Allows text to wrap at any character, not just spaces.\n        </summary>\n    </doc>\n    \n    <doc for=\"text.lineHeight\">\n        <summary>\n            Adjusts the vertical spacing between lines of text, affecting readability and overall text layout.\n            The added space is proportional to the text size. \n            A <paramref name=\"factor\"/> value of 1 retains the original spacing.\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#line-height\">Learn more</a>\n        </summary>\n\n        <param name=\"factor\">\n            <para>Sets the proportion of vertical spacing relative to the font size.</para>\n            <para>A value greater than 1 increases the spacing, while a value less than 1 decreases it. The value must be greater than 0.</para>\n            <para>A value of <c>1</c> sets the line height equal to the font size. This setting may result in insufficient vertical spacing around the text.</para>\n            <para>A value of <c>default</c> indicates that the font metrics should be used to calculate the line spacing, which is the default behavior.</para>\n        </param>\n    </doc>\n\n    <doc for=\"text.letterSpacing\">\n        <summary>\n            Adjusts the horizontal spacing between characters in the text, affecting readability and overall visual style.\n            The adjustment is proportional to the text size.\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#letter-spacing\">Learn more</a>\n        </summary>\n\n        <param name=\"factor\">\n            <para>Sets the proportion by which the horizontal space between characters is changed.</para>\n            <para>A value of 0 maintains the original spacing. When the value is positive, the text is more spread out. When it is negative, the text is more condensed.</para>\n        </param>\n    </doc>\n\n    <doc for=\"text.wordSpacing\">\n        <summary>\n            Adjusts the horizontal spacing between words in the text, affecting readability and overall visual style.\n            The adjustment is proportional to the text size.\n        </summary>\n\n        <param name=\"factor\">\n            <para>Sets the proportion by which the horizontal space between words is changed.</para>\n            <para>A value of 0 maintains the original spacing. When the value is positive, the text is more spread out. When it is negative, the text is more condensed.</para>\n        </param>\n    </doc>\n\n    <doc for=\"text.paragraph.spacing\">\n        <summary>\n            Adjusts the vertical gap between successive paragraphs (separated by line breaks),\n            helping to visually separate blocks of text for improved readability.\n        </summary>\n    </doc>\n\n    <doc for=\"text.paragraph.firstLineIndentation\">\n        <summary>\n            Specifies the horizontal offset of the first line in a paragraph.\n            Commonly used to visually separate paragraphs in a block of text.\n        </summary>\n    </doc>\n    \n    <!-- TEXT EFFECTS -->\n\n    <doc for=\"text.italic\">\n        <summary>\n            Renders text with an italic effect, where letters are slightly slanted to the right.\n            Commonly used for emphasis or to distinguish specific words.\n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.strikethrough\">\n        <summary>\n            Draws a line through the middle of the text. \n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.underline\">\n        <summary>\n            Draws a line under the text.\n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.overline\">\n        <summary>\n            Draws a line above the text.\n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.remarks\">\n        <remarks>\n            You can control the decoration visuals by setting color and style (solid, double, wavy, dotted, dashed) of the line.\n        </remarks>\n    </doc>\n\n    <doc for=\"text.decoration.applicability\">\n        <remarks>\n            Applies for the following text decorations: striketrough, underline, overline.\n        </remarks>\n    </doc>\n\n    <doc for=\"text.decoration.color\">\n        <summary>\n            Sets the color of the text decoration.\n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.thickness\">\n        <summary>\n            Changess thickness of decoration line proportionally to the provided argument. \n            Value equal to 1 is the default thickness. \n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.solid\">\n        <summary>\n            Sets the decoration line to a solid straight line.\n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.double\">\n        <summary>\n            Sets the decoration line to a solid double line.\n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.wavy\">\n        <summary>\n            Sets the decoration line to wave.\n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.dotted\">\n        <summary>\n            Sets the decoration line to dots.\n        </summary>\n    </doc>\n\n    <doc for=\"text.decoration.dashed\">\n        <summary>\n            Sets the decoration line to dashes.\n        </summary>\n    </doc>\n    \n    <!-- TEXT WEIGHT -->\n    \n    <doc for=\"text.weight.thin\">\n        <summary>\n            Sets the font weight to \"thin\" (equivalent to CSS 100).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.extraLight\">\n        <summary>\n            Sets the font weight to \"extra light\" (equivalent to CSS 200).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.light\">\n        <summary>\n            Sets the font weight to \"light\" (equivalent to CSS 300).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.normal\">\n        <summary>\n            Sets the font weight to \"normal\" or \"regular (equivalent to CSS 400).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.medium\">\n        <summary>\n            Sets the font weight to \"medium\" (equivalent to CSS 500).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.semiBold\">\n        <summary>\n            Sets the font weight to \"semi bold\" (equivalent to CSS 600).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.bold\">\n        <summary>\n            Sets the font weight to \"bold\" (equivalent to CSS 700).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.extraBold\">\n        <summary>\n            Sets the font weight to \"extra bold\" (equivalent to CSS 800).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.black\">\n        <summary>\n            Sets the font weight to \"black\" (equivalent to CSS 900).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.extraBlack\">\n        <summary>\n            Sets the font weight to \"extra black\" (equivalent to CSS 1000).\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#font-weight\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.weight.remarks\">\n        <remarks>\n            <para>Determines the thickness of the text characters, ranging from light to bold, to create visual hierarchy or emphasis.</para>\n            \n            <para>\n                Not all fonts support every weight.\n                If the specified weight isn't available, the library selects the closest available option.\n            </para>\n        </remarks>\n    </doc>\n    \n    <!-- TEXT POSITION -->\n    \n    <doc for=\"text.position.normal\">\n        <summary>\n            Resets the text position and size to default, utilizing the full available line height.\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#subscript\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.position.subscript\">\n        <summary>\n            Sets the text style to subscript, making it smaller and positioning it below the baseline, e.g.: H₂0.\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#subscript\">Learn more</a>\n        </summary>\n    </doc>\n\n    <doc for=\"text.position.superscript\">\n        <summary>\n            Sets the text style to subscript, making it smaller and positioning it above the baseline, e.g.: y² + x² = 1.\n            <a href=\"https://www.questpdf.com/api-reference/text/text-style.html#superscript\">Learn more</a>\n        </summary>\n    </doc>\n    \n    <!-- TEXT DIRECTION -->\n\n    <doc for=\"text.direction.auto\">\n        <summary>\n            Resets the text direction, enabling content to follow the automatically detected direction.\n        </summary>\n    </doc>\n\n    <doc for=\"text.direction.ltr\">\n        <summary>\n            Enforces a left-to-right text direction.\n        </summary>\n    </doc>\n\n    <doc for=\"text.direction.rtl\">\n        <summary>\n            Enforces a right-to-left text direction.\n        </summary>\n    </doc>\n    \n    <!-- TEXT OTHERS -->\n    <doc for=\"text.style\">\n        <summary>\n            Sets a font style using the typography pattern.\n            <a href=\"https://www.questpdf.com/api-reference/text/basics.html#typography-pattern\">Learn more</a>\n        </summary>\n        \n        <remarks>\n            This API reduces the garbage collector pressure and offers the best performance.\n        </remarks>\n    </doc>\n    \n    <!-- PREVIEWER -->\n\n    <doc for=\"companion.support\">\n        <summary>\n            Connects to the QuestPDF Companion application to automatically preview the document being currently implemented after every code modification,\n            without the need to recompile the code or restart the application.\n            <a href=\"https://www.questpdf.com/document-companion.html\">Learn more</a>\n        </summary>\n        \n        <remarks>\n            For details on the hot-reload functionality, please refer to the documentation of your preferred IDE.\n        </remarks>\n        \n        <param name=\"port\">Specifies port for communication with the QuestPDF Previewer application. Default value is 12500.</param>\n    </doc>\n\n    <doc for=\"companion.notSupported\">\n        <summary>\n            The hot-reload feature and QuestPDF Companion integration are available only in the .NET 6 environment or later.\n            Please consider updating your project.\n            <a href=\"https://www.questpdf.com/companion/usage.html\">Installation and usage</a><br />\n            <a href=\"https://www.questpdf.com/companion/features.html\">Features overview</a>\n        </summary>\n        \n        <param name=\"port\">This parameter is ignored.</param>\n    </doc>\n    \n    <!-- COMPONENTS -->\n\n    <doc for=\"component\">\n        <summary>\n            Components serve as modular building blocks for abstracting document layouts. \n            They promote code reusability across multiple sections or types of documents. \n            Using a component, you can generate content based on its internal state.\n            <a href=\"https://www.questpdf.com/concepts/components.html\">Learn more</a>\n        </summary>\n        <example>\n            Consider the scenario of a company-wide page header. \n            Instead of replicating the same header design across various documents, a single component can be created and referenced wherever needed.\n        </example>\n    </doc>\n\n    <!-- DOCUMENT OPERATIONS -->\n\n    <doc for=\"documentOperation.pageSelector\">\n        <remarks>\n            <list type=\"table\">\n                <listheader>\n                    <term>Syntax</term>\n                    <description>Description</description>\n                </listheader>\n                <item>\n                    <term>1, 2, 3</term>\n                    <description>Plain numbers indicate pages numbered from the start</description>\n                </item>\n                <item>\n                    <term>r1, r2</term>\n                    <description>Numbers with 'r' prefix count from the end (r1 = last page)</description>\n                </item>\n                <item>\n                    <term>z</term>\n                    <description>Represents the last page (equivalent to r1)</description>\n                </item>\n                <item>\n                    <term>1-5</term>\n                    <description>Dash-separated ranges are inclusive</description>\n                </item>\n                <item>\n                    <term>5-1</term>\n                    <description>Reversed ranges list pages in descending order</description>\n                </item>\n                <item>\n                    <term>x1-3</term>\n                    <description>Excludes specified pages from previous range</description>\n                </item>\n                <item>\n                    <term>:odd</term>\n                    <description>Selects odd-positioned pages from the resulting page-set</description>\n                </item>\n                <item>\n                    <term>:even</term>\n                    <description>Selects even-positioned pages from the resulting page-set</description>\n                </item>\n            </list>\n        </remarks>\n        \n        <example>\n            <list type=\"table\">\n                <listheader>\n                    <term>Expression</term>\n                    <description>Result</description>\n                </listheader>\n                <item>\n                    <term>1,6,4</term>\n                    <description>pages 1, 6, and 4 in that order</description>\n                </item>\n                <item>\n                    <term>3-7</term>\n                    <description>pages 3 through 7 inclusive</description>\n                </item>\n                <item>\n                    <term>7-3</term>\n                    <description>pages 7, 6, 5, 4, and 3 in that order</description>\n                </item>\n                <item>\n                    <term>1-z</term>\n                    <description>all pages in order</description>\n                </item>\n                <item>\n                    <term>z-1</term>\n                    <description>all pages in reverse order</description>\n                </item>\n                <item>\n                    <term>r3-r1</term>\n                    <description>the last three pages of the document</description>\n                </item>\n                <item>\n                    <term>r1-r3</term>\n                    <description>the last three pages of the document in reverse order</description>\n                </item>\n                <item>\n                    <term>1-20:even</term>\n                    <description>even pages from 2 to 20</description>\n                </item>\n                <item>\n                    <term>5,7-9,12</term>\n                    <description>pages 5, 7, 8, 9, and 12</description>\n                </item>\n                <item>\n                    <term>5,7-9,12:odd</term>\n                    <description>pages 5, 8, and 12 (pages in odd positions from the original set of 5, 7, 8, 9, 12)</description>\n                </item>\n                <item>\n                    <term>5,7-9,12:even</term>\n                    <description>pages 7 and 9 (pages in even positions from the original set of 5, 7, 8, 9, 12)</description>\n                </item>\n                <item>\n                    <term>1-10,x3-4</term>\n                    <description>pages 1 through 10 except pages 3 and 4 (1, 2, and 5 through 10)</description>\n                </item>\n                <item>\n                    <term>4-10,x7-9,12-8,xr5</term>\n                    <description>In a 15-page file: pages 4, 5, 6, 10, 12, 10, 9, and 8 in that order (pages 4 through 10 except 7 through 9, followed by 12 through 8 descending, except 11 which is the fifth page from the end)</description>\n                </item>\n            </list>\n        </example>\n    </doc>\n    \n    <doc for=\"documentOperation.encryption.allow.annotation\">\n        <summary>\n            Specifies whether the user is permitted to add signatures and annotations to the document.\n        </summary>\n    </doc>\n\n    <doc for=\"documentOperation.encryption.allow.contentExtraction\">\n        <summary>\n            Specifies whether the user is allowed to copy text and graphics from the document.\n        </summary>\n    </doc>\n\n    <doc for=\"documentOperation.encryption.allow.modification\">\n        <summary>\n            Specifies whether the user is permitted to insert, rotate, or delete pages within the document.\n        </summary>\n    </doc>\n\n    <doc for=\"documentOperation.encryption.allow.printing\">\n        <summary>\n            Specifies whether the user can print the document.\n        </summary>\n    </doc>\n\n    <doc for=\"documentOperation.encryption.allow.assembly\">\n        <summary>\n            Specifies whether the user is permitted to insert, rotate, or delete pages within the document.\n        </summary>\n    </doc>\n\n    <doc for=\"documentOperation.encryption.allow.fillingForms\">\n        <summary>\n            Specifies whether the user is allowed to fill out existing form fields in the document.\n        </summary>\n    </doc>\n\n    <doc for=\"documentOperation.encryption.encryptMetadata\">\n        <summary>\n            Determines whether the document's metadata is included in encryption.\n        </summary>\n    </doc>\n</documentation>"
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/emsdk.txt",
    "content": "Copyright (c) 2018 Emscripten authors (see AUTHORS in Emscripten)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n----------------------------------------------------------------------------\n\nThis is the MIT/Expat Licence. For more information see:\n\n1. http://www.opensource.org/licenses/mit-license.php\n\n2. http://en.wikipedia.org/wiki/MIT_License"
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/expat.txt",
    "content": "Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper\nCopyright (c) 2001-2022 Expat maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/harfbuzz.txt",
    "content": "HarfBuzz is licensed under the so-called \"Old MIT\" license.  Details follow.\nFor parts of HarfBuzz that are licensed under different licenses see individual\nfiles names COPYING in subdirectories where applicable.\n\nCopyright © 2010-2022  Google, Inc.\nCopyright © 2015-2020  Ebrahim Byagowi\nCopyright © 2019,2020  Facebook, Inc.\nCopyright © 2012,2015  Mozilla Foundation\nCopyright © 2011  Codethink Limited\nCopyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)\nCopyright © 2009  Keith Stribley\nCopyright © 2011  Martin Hosken and SIL International\nCopyright © 2007  Chris Wilson\nCopyright © 2005,2006,2020,2021,2022,2023  Behdad Esfahbod\nCopyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023  Red Hat, Inc.\nCopyright © 1998-2005  David Turner and Werner Lemberg\nCopyright © 2016  Igalia S.L.\nCopyright © 2022  Matthias Clasen\nCopyright © 2018,2021  Khaled Hosny\nCopyright © 2018,2019,2020  Adobe, Inc\nCopyright © 2013-2015  Alexei Podtelezhnikov\n\nFor full copyright notices consult the individual files in the package.\n\n\nPermission is hereby granted, without written agreement and without\nlicense or royalty fees, to use, copy, modify, and distribute this\nsoftware and its documentation for any purpose, provided that the\nabove copyright notice and the following two paragraphs appear in\nall copies of this software.\n\nIN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR\nDIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\nARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN\nIF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGE.\n\nTHE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,\nBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS\nON AN \"AS IS\" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO\nPROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/libgrapheme.txt",
    "content": "ISC-License\n\nCopyright 2019-2025 Laslo Hunhold <dev@frign.de>\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE."
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/libjpeg-turbo.txt",
    "content": "libjpeg-turbo Licenses\n======================\n\nlibjpeg-turbo is covered by two compatible BSD-style open source licenses:\n\n- The IJG (Independent JPEG Group) License, which is listed in\n  [README.ijg](README.ijg)\n\n  This license applies to the libjpeg API library and associated programs,\n  including any code inherited from libjpeg and any modifications to that\n  code.  Note that the libjpeg-turbo SIMD source code bears the\n  [zlib License](https://opensource.org/licenses/Zlib), but in the context of\n  the overall libjpeg API library, the terms of the zlib License are subsumed\n  by the terms of the IJG License.\n\n- The Modified (3-clause) BSD License, which is listed below\n\n  This license applies to the TurboJPEG API library and associated programs, as\n  well as the build system.  Note that the TurboJPEG API library wraps the\n  libjpeg API library, so in the context of the overall TurboJPEG API library,\n  both the terms of the IJG License and the terms of the Modified (3-clause)\n  BSD License apply.\n  \n  \n\n\n--------------------------------------------------------------------------------\n\n\n\n\nlibjpeg-turbo note:  This file has been modified by The libjpeg-turbo Project\nto include only information relevant to libjpeg-turbo, to wordsmith certain\nsections, and to remove impolitic language that existed in the libjpeg v8\nREADME.  It is included only for reference.  Please see README.md for\ninformation specific to libjpeg-turbo.\n\n\nThe Independent JPEG Group's JPEG software\n==========================================\n\nThis distribution contains a release of the Independent JPEG Group's free JPEG\nsoftware.  You are welcome to redistribute this software and to use it for any\npurpose, subject to the conditions under LEGAL ISSUES, below.\n\nThis software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,\nBill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,\nJulian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,\nand other members of the Independent JPEG Group.\n\nIJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee\n(also known as JPEG, together with ITU-T SG16).\n\n\nDOCUMENTATION ROADMAP\n=====================\n\nThis file contains the following sections:\n\nOVERVIEW            General description of JPEG and the IJG software.\nLEGAL ISSUES        Copyright, lack of warranty, terms of distribution.\nREFERENCES          Where to learn more about JPEG.\nARCHIVE LOCATIONS   Where to find newer versions of this software.\nFILE FORMAT WARS    Software *not* to get.\nTO DO               Plans for future IJG releases.\n\nOther documentation files in the distribution are:\n\nUser documentation:\n  usage.txt         Usage instructions for cjpeg, djpeg, jpegtran,\n                    rdjpgcom, and wrjpgcom.\n  *.1               Unix-style man pages for programs (same info as usage.txt).\n  wizard.txt        Advanced usage instructions for JPEG wizards only.\n  change.log        Version-to-version change highlights.\nProgrammer and internal documentation:\n  libjpeg.txt       How to use the JPEG library in your own programs.\n  example.c         Sample code for calling the JPEG library.\n  structure.txt     Overview of the JPEG library's internal structure.\n  coderules.txt     Coding style rules --- please read if you contribute code.\n\nPlease read at least usage.txt.  Some information can also be found in the JPEG\nFAQ (Frequently Asked Questions) article.  See ARCHIVE LOCATIONS below to find\nout where to obtain the FAQ article.\n\nIf you want to understand how the JPEG code works, we suggest reading one or\nmore of the REFERENCES, then looking at the documentation files (in roughly\nthe order listed) before diving into the code.\n\n\nOVERVIEW\n========\n\nThis package contains C software to implement JPEG image encoding, decoding,\nand transcoding.  JPEG (pronounced \"jay-peg\") is a standardized compression\nmethod for full-color and grayscale images.  JPEG's strong suit is compressing\nphotographic images or other types of images that have smooth color and\nbrightness transitions between neighboring pixels.  Images with sharp lines or\nother abrupt features may not compress well with JPEG, and a higher JPEG\nquality may have to be used to avoid visible compression artifacts with such\nimages.\n\nJPEG is normally lossy, meaning that the output pixels are not necessarily\nidentical to the input pixels.  However, on photographic content and other\n\"smooth\" images, very good compression ratios can be obtained with no visible\ncompression artifacts, and extremely high compression ratios are possible if\nyou are willing to sacrifice image quality (by reducing the \"quality\" setting\nin the compressor.)\n\nThis software implements JPEG baseline, extended-sequential, progressive, and\nlossless compression processes.  Provision is made for supporting all variants\nof these processes, although some uncommon parameter settings aren't\nimplemented yet.  We have made no provision for supporting the hierarchical\nprocesses defined in the standard.\n\nWe provide a set of library routines for reading and writing JPEG image files,\nplus two sample applications \"cjpeg\" and \"djpeg\", which use the library to\nperform conversion between JPEG and some other popular image file formats.\nThe library is intended to be reused in other applications.\n\nIn order to support file conversion and viewing software, we have included\nconsiderable functionality beyond the bare JPEG coding/decoding capability;\nfor example, the color quantization modules are not strictly part of JPEG\ndecoding, but they are essential for output to colormapped file formats or\ncolormapped displays.  These extra functions can be compiled out of the\nlibrary if not required for a particular application.\n\nWe have also included \"jpegtran\", a utility for lossless transcoding between\ndifferent JPEG processes, and \"rdjpgcom\" and \"wrjpgcom\", two simple\napplications for inserting and extracting textual comments in JFIF files.\n\nThe emphasis in designing this software has been on achieving portability and\nflexibility, while also making it fast enough to be useful.  In particular,\nthe software is not intended to be read as a tutorial on JPEG.  (See the\nREFERENCES section for introductory material.)  Rather, it is intended to\nbe reliable, portable, industrial-strength code.  We do not claim to have\nachieved that goal in every aspect of the software, but we strive for it.\n\nWe welcome the use of this software as a component of commercial products.\nNo royalty is required, but we do ask for an acknowledgement in product\ndocumentation, as described under LEGAL ISSUES.\n\n\nLEGAL ISSUES\n============\n\nIn plain English:\n\n1. We don't promise that this software works.  (But if you find any bugs,\n   please let us know!)\n2. You can use this software for whatever you want.  You don't have to pay us.\n3. You may not pretend that you wrote this software.  If you use it in a\n   program, you must acknowledge somewhere in your documentation that\n   you've used the IJG code.\n\nIn legalese:\n\nThe authors make NO WARRANTY or representation, either express or implied,\nwith respect to this software, its quality, accuracy, merchantability, or\nfitness for a particular purpose.  This software is provided \"AS IS\", and you,\nits user, assume the entire risk as to its quality and accuracy.\n\nThis software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.\nAll Rights Reserved except as specified below.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsoftware (or portions thereof) for any purpose, without fee, subject to these\nconditions:\n(1) If any part of the source code for this software is distributed, then this\nREADME file must be included, with this copyright and no-warranty notice\nunaltered; and any additions, deletions, or changes to the original files\nmust be clearly indicated in accompanying documentation.\n(2) If only executable code is distributed, then the accompanying\ndocumentation must state that \"this software is based in part on the work of\nthe Independent JPEG Group\".\n(3) Permission for use of this software is granted only if the user accepts\nfull responsibility for any undesirable consequences; the authors accept\nNO LIABILITY for damages of any kind.\n\nThese conditions apply to any software derived from or based on the IJG code,\nnot just to the unmodified library.  If you use our work, you ought to\nacknowledge us.\n\nPermission is NOT granted for the use of any IJG author's name or company name\nin advertising or publicity relating to this software or products derived from\nit.  This software may be referred to only as \"the Independent JPEG Group's\nsoftware\".\n\nWe specifically permit and encourage the use of this software as the basis of\ncommercial products, provided that all warranty or liability claims are\nassumed by the product vendor.\n\n\nREFERENCES\n==========\n\nWe recommend reading one or more of these references before trying to\nunderstand the innards of the JPEG software.\n\nThe best short technical introduction to the JPEG compression algorithm is\n        Wallace, Gregory K.  \"The JPEG Still Picture Compression Standard\",\n        Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.\n(Adjacent articles in that issue discuss MPEG motion picture compression,\napplications of JPEG, and related topics.)  If you don't have the CACM issue\nhandy, a PDF file containing a revised version of Wallace's article is\navailable at http://www.ijg.org/files/Wallace.JPEG.pdf.  The file (actually\na preprint for an article that appeared in IEEE Trans. Consumer Electronics)\nomits the sample images that appeared in CACM, but it includes corrections\nand some added material.  Note: the Wallace article is copyright ACM and IEEE,\nand it may not be used for commercial purposes.\n\nA somewhat less technical, more leisurely introduction to JPEG can be found in\n\"The Data Compression Book\" by Mark Nelson and Jean-loup Gailly, published by\nM&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1.  This book provides\ngood explanations and example C code for a multitude of compression methods\nincluding JPEG.  It is an excellent source if you are comfortable reading C\ncode but don't know much about data compression in general.  The book's JPEG\nsample code is far from industrial-strength, but when you are ready to look\nat a full implementation, you've got one here...\n\nThe best currently available description of JPEG is the textbook \"JPEG Still\nImage Data Compression Standard\" by William B. Pennebaker and Joan L.\nMitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.\nPrice US$59.95, 638 pp.  The book includes the complete text of the ISO JPEG\nstandards (DIS 10918-1 and draft DIS 10918-2).\n\nThe original JPEG standard is divided into two parts, Part 1 being the actual\nspecification, while Part 2 covers compliance testing methods.  Part 1 is\ntitled \"Digital Compression and Coding of Continuous-tone Still Images,\nPart 1: Requirements and guidelines\" and has document numbers ISO/IEC IS\n10918-1, ITU-T T.81.  Part 2 is titled \"Digital Compression and Coding of\nContinuous-tone Still Images, Part 2: Compliance testing\" and has document\nnumbers ISO/IEC IS 10918-2, ITU-T T.83.\n\nThe JPEG standard does not specify all details of an interchangeable file\nformat.  For the omitted details, we follow the \"JFIF\" conventions, revision\n1.02.  JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and\nRecommendation ITU-T T.871 (05/2011): Information technology - Digital\ncompression and coding of continuous-tone still images: JPEG File Interchange\nFormat (JFIF).  It is available as a free download in PDF file format from\nhttps://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871.\nA PDF file of the older JFIF 1.02 specification is available at\nhttp://www.w3.org/Graphics/JPEG/jfif3.pdf.\n\nThe TIFF 6.0 file format specification can be obtained from\nhttp://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz.  The JPEG incorporation\nscheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious\nproblems.  IJG does not recommend use of the TIFF 6.0 design (TIFF Compression\ntag 6).  Instead, we recommend the JPEG design proposed by TIFF Technical Note\n#2 (Compression tag 7).  Copies of this Note can be obtained from\nhttp://www.ijg.org/files/.  It is expected that the next revision\nof the TIFF spec will replace the 6.0 JPEG design with the Note's design.\nAlthough IJG's own code does not support TIFF/JPEG, the free libtiff library\nuses our library to implement TIFF/JPEG per the Note.\n\n\nARCHIVE LOCATIONS\n=================\n\nThe \"official\" archive site for this software is www.ijg.org.\nThe most recent released version can always be found there in\ndirectory \"files\".\n\nThe JPEG FAQ (Frequently Asked Questions) article is a source of some\ngeneral information about JPEG.  It is available at\nhttp://www.faqs.org/faqs/jpeg-faq.\n\n\nFILE FORMAT COMPATIBILITY\n=========================\n\nThis software implements ITU T.81 | ISO/IEC 10918 with some extensions from\nITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES).\nInformally, the term \"JPEG image\" or \"JPEG file\" most often refers to JFIF or\na subset thereof, but there are other formats containing the name \"JPEG\" that\nare incompatible with the original JPEG standard or with JFIF (for instance,\nJPEG 2000 and JPEG XR).  This software therefore does not support these\nformats.  Indeed, one of the original reasons for developing this free software\nwas to help force convergence on a common, interoperable format standard for\nJPEG files.\n\nJFIF is a minimal or \"low end\" representation.  TIFF/JPEG (TIFF revision 6.0 as\nmodified by TIFF Technical Note #2) can be used for \"high end\" applications\nthat need to record a lot of additional data about an image.\n\n\nTO DO\n=====\n\nPlease send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.  \n  \n\n\n\n--------------------------------------------------------------------------------\n\n\n\n\nThe Modified (3-clause) BSD License\n===================================\n\nCopyright (C)2009-2023 D. R. Commander.  All Rights Reserved.<br>\nCopyright (C)2015 Viktor Szathmáry.  All Rights Reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n- Redistributions of source code must retain the above copyright notice,\n  this list of conditions and the following disclaimer.\n- Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n- Neither the name of the libjpeg-turbo Project nor the names of its\n  contributors may be used to endorse or promote products derived from this\n  software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\",\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  "
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/libpng.txt",
    "content": "COPYRIGHT NOTICE, DISCLAIMER, and LICENSE\n=========================================\n\nPNG Reference Library License version 2\n---------------------------------------\n\n * Copyright (c) 1995-2024 The PNG Reference Library Authors.\n * Copyright (c) 2018-2024 Cosmin Truta.\n * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.\n * Copyright (c) 1996-1997 Andreas Dilger.\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nThe software is supplied \"as is\", without warranty of any kind,\nexpress or implied, including, without limitation, the warranties\nof merchantability, fitness for a particular purpose, title, and\nnon-infringement.  In no event shall the Copyright owners, or\nanyone distributing the software, be liable for any damages or\nother liability, whether in contract, tort or otherwise, arising\nfrom, out of, or in connection with the software, or the use or\nother dealings in the software, even if advised of the possibility\nof such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute\nthis software, or portions hereof, for any purpose, without fee,\nsubject to the following restrictions:\n\n 1. The origin of this software must not be misrepresented; you\n    must not claim that you wrote the original software.  If you\n    use this software in a product, an acknowledgment in the product\n    documentation would be appreciated, but is not required.\n\n 2. Altered source versions must be plainly marked as such, and must\n    not be misrepresented as being the original software.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\n\nPNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)\n-----------------------------------------------------------------------\n\nlibpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are\nCopyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are\nderived from libpng-1.0.6, and are distributed according to the same\ndisclaimer and license as libpng-1.0.6 with the following individuals\nadded to the list of Contributing Authors:\n\n    Simon-Pierre Cadieux\n    Eric S. Raymond\n    Mans Rullgard\n    Cosmin Truta\n    Gilles Vollant\n    James Yu\n    Mandar Sahastrabuddhe\n    Google Inc.\n    Vadim Barkov\n\nand with the following additions to the disclaimer:\n\n    There is no warranty against interference with your enjoyment of\n    the library or against infringement.  There is no warranty that our\n    efforts or the library will fulfill any of your particular purposes\n    or needs.  This library is provided with all faults, and the entire\n    risk of satisfactory quality, performance, accuracy, and effort is\n    with the user.\n\nSome files in the \"contrib\" directory and some configure-generated\nfiles that are distributed with libpng have other copyright owners, and\nare released under other open source licenses.\n\nlibpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are\nCopyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from\nlibpng-0.96, and are distributed according to the same disclaimer and\nlicense as libpng-0.96, with the following individuals added to the\nlist of Contributing Authors:\n\n    Tom Lane\n    Glenn Randers-Pehrson\n    Willem van Schaik\n\nlibpng versions 0.89, June 1996, through 0.96, May 1997, are\nCopyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,\nand are distributed according to the same disclaimer and license as\nlibpng-0.88, with the following individuals added to the list of\nContributing Authors:\n\n    John Bowler\n    Kevin Bracey\n    Sam Bushell\n    Magnus Holmgren\n    Greg Roelofs\n    Tom Tanner\n\nSome files in the \"scripts\" directory have other copyright owners,\nbut are released under this license.\n\nlibpng versions 0.5, May 1995, through 0.88, January 1996, are\nCopyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n\nFor the purposes of this copyright and license, \"Contributing Authors\"\nis defined as the following set of individuals:\n\n    Andreas Dilger\n    Dave Martindale\n    Guy Eric Schalnat\n    Paul Schmidt\n    Tim Wegner\n\nThe PNG Reference Library is supplied \"AS IS\".  The Contributing\nAuthors and Group 42, Inc. disclaim all warranties, expressed or\nimplied, including, without limitation, the warranties of\nmerchantability and of fitness for any purpose.  The Contributing\nAuthors and Group 42, Inc. assume no liability for direct, indirect,\nincidental, special, exemplary, or consequential damages, which may\nresult from the use of the PNG Reference Library, even if advised of\nthe possibility of such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsource code, or portions hereof, for any purpose, without fee, subject\nto the following restrictions:\n\n 1. The origin of this source code must not be misrepresented.\n\n 2. Altered versions must be plainly marked as such and must not\n    be misrepresented as being the original source.\n\n 3. This Copyright notice may not be removed or altered from any\n    source or altered source distribution.\n\nThe Contributing Authors and Group 42, Inc. specifically permit,\nwithout fee, and encourage the use of this source code as a component\nto supporting the PNG file format in commercial products.  If you use\nthis source code in a product, acknowledgment is not required but would\nbe appreciated."
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/libwebp.txt",
    "content": "Copyright (c) 2010, Google Inc. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n  * Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n  * Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n  * Neither the name of Google nor the names of its contributors may\n    be used to endorse or promote products derived from this software\n    without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/ninja-build.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2010\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/qpdf.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/readme.txt",
    "content": "If you believe that this folder does not include all of QuestPDF's third-party dependencies, please reach out to us at contact@questpdf.com. We will update the list as quickly as possible. Thank you!\n"
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/skia.txt",
    "content": "Copyright (c) 2011 Google Inc. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n  * Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n  * Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n  * Neither the name of the copyright holder nor the names of its\n    contributors may be used to endorse or promote products derived\n    from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/wuffs.txt",
    "content": "This software is distributed under the terms of both the MIT license and the\nApache License (Version 2.0).\n\n\nMIT license\n\nCopyright 2023 The Wuffs Authors\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n\n\nApache 2 license\n\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS"
  },
  {
    "path": "Source/QuestPDF/Resources/ExternalDependencyLicenses/zlib.txt",
    "content": "Copyright notice:\n\n (C) 1995-2024 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu"
  },
  {
    "path": "Source/QuestPDF/Resources/LatinWords.txt",
    "content": "ut\nsum\neius\nquod\nipse\nfuit\nnam\nin\nsunt\ncum\nilli\nesse\nat\nunum\nhabent\nhoc\nde\nby\ncalidum\nverbo\nsed\nquod\naliqua\nest\nquod\nvos\nvel\nquod\nin\nde\nut\net\na\nin\nnos\npotest\nex\nalia\nerant\nquibus\nfacite\neorum\ntempore\nsi\nvoluntas\nquam\nDixitque\nan\nquisque\nindica\nquod\nset\ntribus\nvolo\naer\netiam\netiam\nfabula\nparva\nfinem\nposuit\ndomum\nlego\nmanibus\nportus\nmagna\neamque\naddunt\netiam\nterra\nhic\nnecesse\nmagnum\nprinceps\ntalis\nsequitur\nactum\nquid\nquaeris\nhomines\nmutatio\nabiit\nlucem\nquaedam\noff\nopus\ndomus\nipsum\ntentant\nnos\nrursus\npecus\npunctum\nmater\norbis\nprope\nædificabis\nipsum\nterra\npater\naliqua\nnovum\nopus\npars\naccipe\nadepto\npro eo\nfactum\nvivo\nubi\npostquam\nrursus\nparum\nnisi\nper\nhominis\nanno\nfactum\nostende\nomnis\nbonum\nme\ndabit\nnostrum\nsub\nnomen\nipsum\nper\niustus\nforma\nsententia\nmagna\nputo\ndicunt\nadiuva\nhumilis\nline\ndifferunt\nvicissim\ncausa\ntantum\nsignificant\nantequam\nmovemur\nius\npuer\nVetus\netiam\nidem\nquae\nomnes\nibi\ncum\nascendit\nusus\ntuus\nmodo\nde\nmultis\ntunc\neorum\nscribo\nutinam\nsicut\nita\nhaec\neius\nlongis\nfac\naliquid\nvideo\neo\nduobus\nhabet\nrespice\nmore\ndie\npotuit\nvade\nvenit\nFeceruntque\nnumerus\ntuba canerent\nnulla\nmaxime\npopulus\nmea\nsupra\nscitis\naquam\nquam\ncall\nprima\nqui\nut\ndescendit\nlatere\nfuit\nnunc\ninvenies\ncaput\nstant\nipse\npage\nut\npatriae\ninvenit\ndicendum\nscholae\ncrescat\nstudiorum\netiam\ndiscant\nherba\nCover\ncibum\nsolis\nquatuor\ninter\nstatus\ncustodi\noculus\nnumquam\nnovissime\ndimitte\ncogitavit\nurbem\nlignum\ntransire\nfundum\ndifficile\ninitium\nut\nfabula\nViderunt omnes\ntantum\nmare\nhauriret\nreliquit\nquondam\ncurrunt\nnon\ncum\nturba\nproxime\nnoctis\nipsum\nvita\npauci\naquilonem\nliber\nferte\ntulit\nscientia\nmanducare\nlocus\namicitia\ncoeperunt\nidea\npisces\nmontem\nsubsisto\nquondam\nbasi\naudite\nequo\nsectis\ncertus\nvigilate\ncolorem\nfaciem\nlignum\nmain\naperi\nvidetur\nsimul\npostero\nalbum\nfilii\nincipe\nobtinuit\nambulate\nexemplum\nrelevare\ncartam\ngroup\nsemper\nmusica\neorum\net\ncaracterem\nsaepe\nlitteris\nusque\nmille passuum\nfluvio\ncar\npedes\ncura\nsecundo\nsufficit\npatet\npuella\nmore\nadulescens\nparata\nsupra\nin perpetuum\nred\nalbum\ntametsi\nsentio\nDisputatio\navem\nmox\ncorpus\ncanem\nfamilia\ndirige\naut statum\nrelinquo\ncanticum\nmetiretur\nostium\nVestibulum\nnigrum\nbreves\nnumerales\nclass\nspiritus\nquaestio\nfieri\ncompletum\nnavem\narea\ndimidiam\npetræ\nut\nignis\naustri\nforsit\nfrustrum\nnuntiavit\ncognovit\nfactum\ncum\ntop\nomnis\nrex\nplatea\ninch\nmultiplicabo\naliquid\nscilicet\nmanete\nrotam\npleni\nvi\nhyacintho\nobiectum\ndecernere\nsuperficies\nabyssus\nlunam\ninsulam\npede\nratio\noccupatus\naliquam\ntestimonium\nnavicula\ncommune\naurum\npotest\nplanum\npro eo\nsiccum\nadmiramini\nrideat\nmilia\nago\ncucurrit\nreprehendo\nludum\nfigura\naequat\ncalidum\nrequisierit\nadduxerunt\ncalor\nnix\npiget\nadducet\netiam\ndistant\nimple\norientem\npingere\nlingua\nin\nunitas\npotestatem\nurbem\nPostremo\nquaedam\nfuge\nceciderit\nducit\nclamor\nobscuro\napparatus\nnote\nexspecta\nconsilium\nfigura\nstella\nbox\nnoun\nagro\nReliqua\nrecte\npotest\nlibra\nfactum\npulchritudo\ncoegi\nstetit\ncontinent\nante\ndocebit\nweek\nultima\ndeditque\nviridem\no\nacutus\nevolvere\noceanus\ncalidum\nabsque\nminute\nconfortare\npeculiarem\nanimus\nretro\npatet\ncaudae\nproducere\neo\nlocus\naudivit\noptimum\nhora\nmelius\nverum\nper\ncentum\nquinque\nmemores\nstep\nmane\ntenent\noccasu\nterra\ninterest\nattingere\nieiunium\nverbo\ncantabo\naudite\nsex\nmensamque\nperegrinationes\nminor\nmane\ndecem\nsimplex\nplures\nvocali\nin\nbellum\ndormivitque\ncontra\nexemplar\ntardus\ncentrum\namant\naliquis\npecuniam\nserviant\nappareant\nvia\ntabula\npluviae\nimperium\nregunt\nattrahendam\nfrigus\nObservate\nvox\nnavitas\nhunt\nprobabile\ncubili\nfrater\novum\nride\ncell\nCredere\nforsan\ncolligunt\nrepentino\nNumerabitis\nquadratum\nideo\nlongitudinis\nrepraesentant\nart\nsubiectum\nregionem\namplitudo\nvariant\nhabita\ndicere\npondus\ngeneralis\nglaciem\nmateria\ncirculus\npar\ncomprehendo\ndivide\nsyllabae\nsensi\nmagnificum\npila\nsed\nunda\nconcrescunt\ncor\nsum\npraesens\nmagna\nchorea\nengine\nlocus\nbrachium\nwide\nvela\nmaterial\nfractionem\nsaltus\nsedebitis\ngeneris\nfenestram\nstore\naestas\nerant\nsomnum\nprobant\nagitur\nleg\nexercitium\nmurum\ncaptiones\nmontem\nvolunt\ncaelum\ntabulam\ngaudium\nwinter\nsat\nscriptum\nfera\ninstrumentum\ncustodivit\nvitro\nfœnum\nvitulus\nofficium\nore\nsignum\nvisit\npast\nmolli\nfun\nsplendidum\nVestibulum\ntempestas\nmense\nmillion\nferre\nperoratum\nbeati\nspero\nflos\ninduere\nmirum\nabiit\ncommercia\nmelodiam\ntrinus\nofficium\naccipiet\nrow\nos\nexactam\nsignum\nmortuus\nminimus\nangustia\njubila\nnisi\nscripsit\nsemen\ntone\niungere\nsuadeant\nmundi\naspiret\ndominae\nnavale\nsurgere\nmalum\nictus\nolei\nsanguis\ntangerent\ncrevit\ncent\nmiscere\nbigas\nwire\ncost\nperierat\nbrunneis\ninduere\nhortum\naequales\nmisit\nelige\ncecidit\napta\ninfluunt\npulchrae\nripam\ncolligunt\nsalvum\nimperium\ndecimales\naurem\naliud\nprorsus\nfregit\nita\nmediam\noccides\nfilius\nstagnum\nmomento\nstatera\nmagna\nver\nobserva\npuer\nrectas\nconsonans\ngentem\ndictionary\nlac\nceleritate\nmethodo\norgano\nredde\nsaeculi\nsection\nhabitus\nnubes\nmirantique\nquietum\nlapis\nvegrandis\nascenditur\nfrigus\nconsilium\npauper\nmultum\nexperimento\nimo\nkey\nferrum\nuna\nlignum\nflat\nviginti\npelle\nrisu\nrimula\nviolet\nsalire\nPraesent\nocto\nvilla\nconcurrunt\nradix\nemptum\nresuscitabo\nsolve\nferrum\nsive\ndis\nseptem\nparagraph\ntertia\nnumquid\nPosside\ncapillum\ndescribere\ncocus\npavimentum\naut\nex\ncomburet\ntumulus\nsalvum\ncat\ncentury\nconsiderate\ntype\nlegem\naliquam\nlitore\nrescriptum\nphrase\nsilentium\ntall\narenam\nsolum\nvolumen\ntemperatus\ndigitus\nindustria\nvalue\npugna\nmendacium\npercute\nexcitant\nnaturalis\nvisum\nsensum\ncapitale\nnolo\ncathedra\npericulum\nfructus\ndives\ndensa\nmiles\naliquid\noperantur\npraxi\nseparatum\ndifficile\nmedicus\nobsecro\nprotegat\nmeridies\nseges\nmodern\naliquid\nictus\ndiscipulo\nanguli\npars\ncopia\ncuius\nlocant\norbis\ncharacter\ninsect\ncaptus\ntempus\nindica\nradio\nLocutusque\natom\nhominis\nrerum\neffectus\nelectrica\nsperare\nosse\ncogitis\nimaginari\npraestare\nconveniunt\nita\nmitis\nmulier\ndux\nSuspicor\nnecesse\nacutum\nalae\npartum\nproximus\nlava\nBiblia\npotius\nturba\nfrumentum\ncompare\npoem\nnervo\ntintinnabulum\nex\ncibum\nfricabis\ntube\ncelebre\npupa\nfluvius\ntimore\nvisum\ntenuis\ntriangulo\nplaneta\nfestinate\nprinceps\ncoloniam\nhorologium\nmea\ntatem\nintrant\nmajor\nrecentes\nquaerere\nmitto\nflavis\ngun\nsino\nprint\nmortuus\nlocum\ndeserto\nsectam\ncurrent\nvitae\nsurrexit\nperveniunt\nmagister\nsemita\nparente\nlitore\ndivisione\nlinteum\nsubstantia\ngratiam\nPertinent\npost\nexpendas\nchorda\nadipem\ngavisus\noriginal\nshare\nstatio\nPater\npanem\nTestificor\nproprium\nbar\noffer\nsegmentum\nservus\nanas\ninstant\nipsum\ngradum\nfrequentare\npullus\ncarissimi\nhostem\nrespondeo\npotum\nincididunt\nauxilium\noratio\nnatura\nrange\nvapor\nmotus\nsemita\nliquidum\nstipes\nintelligantur\nquotus\ndentium\ntesta\ncervicibus\ndolor\nsugar\nmortem\nbellum\nperitia\nmulieres\ntempore\nsolutio\nmagnes\nargentum\ngratias\nramum\npar\netiamne\nmaxime\nfig\ntimere\ningenti\nsoror\nferrum\ndisputant\net deinceps\nsimile\ndirige\nexperientiam\nOctoginta\npupillam\nemptum\nductus\npicem\ntunica\nmissa\npecto\ncohors\nfune\nlabente\nvincere\nsomniatis\nad vesperum\ncondicionis\npascuntur\nferramentum\ntotalis\nprima\nolfactus\nvallis\nneque\nduplex\ncathedra\nperseverant\nclausus\ncursus\nhat\nvende\nsuccessu\ncomitatu\nAuferatur\neventus\nparticularis\nmultum\nnatant\nterm\noppositi\nuxorem\ncalceum\numero\nexpandit\ndisponere\ncastra\nconfingunt\nbombicis\nnatus\nstatuere\nquart\nnovem\ndolor\nsonus\nplana\nforte\ncongregate\ntaberna\ntractum\nmittite\nluceat\nproprietate\ncolumn\nmoleculo\neligere\niniuriam\ngray\niterum\nrequirunt\nlata\npraeparabit\nsal\nnasum\nplural\niratus\nclamium\ncontinentem"
  },
  {
    "path": "Source/QuestPDF/Resources/MimeTypes.csv",
    "content": "323,text/h323\n3g2,video/3gpp2\n3gp2,video/3gpp2\n3gp,video/3gpp\n3gpp,video/3gpp\naac,audio/aac\naaf,application/octet-stream\naca,application/octet-stream\naccdb,application/msaccess\naccde,application/msaccess\naccdt,application/msaccess\nacx,application/internet-property-stream\nadt,audio/vnd.dlna.adts\nadts,audio/vnd.dlna.adts\nafm,application/octet-stream\nai,application/postscript\naif,audio/x-aiff\naifc,audio/aiff\naiff,audio/aiff\nappcache,text/cache-manifest\napplication,application/x-ms-application\nart,image/x-jg\nasd,application/octet-stream\nasf,video/x-ms-asf\nasi,application/octet-stream\nasm,text/plain\nasr,video/x-ms-asf\nasx,video/x-ms-asf\natom,application/atom+xml\nau,audio/basic\navi,video/x-msvideo\navif,image/avif\naxs,application/olescript\nbas,text/plain\nbcpio,application/x-bcpio\nbin,application/octet-stream\nbmp,image/bmp\nc,text/plain\ncab,application/vnd.ms-cab-compressed\ncalx,application/vnd.ms-office.calx\ncat,application/vnd.ms-pki.seccat\ncdf,application/x-cdf\nchm,application/octet-stream\nclass,application/x-java-applet\nclp,application/x-msclip\ncmx,image/x-cmx\ncnf,text/plain\ncod,image/cis-cod\ncpio,application/x-cpio\ncpp,text/plain\ncrd,application/x-mscardfile\ncrl,application/pkix-crl\ncrt,application/x-x509-ca-cert\ncsh,application/x-csh\ncss,text/css\ncsv,text/csv\ncur,application/octet-stream\ndcr,application/x-director\ndeploy,application/octet-stream\nder,application/x-x509-ca-cert\ndib,image/bmp\ndir,application/x-director\ndisco,text/xml\ndlm,text/dlm\ndoc,application/msword\ndocm,application/vnd.ms-word.document.macroEnabled.12\ndocx,application/vnd.openxmlformats-officedocument.wordprocessingml.document\ndot,application/msword\ndotm,application/vnd.ms-word.template.macroEnabled.12\ndotx,application/vnd.openxmlformats-officedocument.wordprocessingml.template\ndsp,application/octet-stream\ndtd,text/xml\ndvi,application/x-dvi\ndvr-ms,video/x-ms-dvr\ndwf,drawing/x-dwf\ndwp,application/octet-stream\ndxr,application/x-director\neml,message/rfc822\nemz,application/octet-stream\neot,application/vnd.ms-fontobject\neps,application/postscript\netx,text/x-setext\nevy,application/envoy\nexe,application/vnd.microsoft.portable-executable\nfdf,application/vnd.fdf\nfif,application/fractals\nfla,application/octet-stream\nflr,x-world/x-vrml\nflv,video/x-flv\ngif,image/gif\ngtar,application/x-gtar\ngz,application/x-gzip\nh,text/plain\nhdf,application/x-hdf\nhdml,text/x-hdml\nhhc,application/x-oleobject\nhhk,application/octet-stream\nhhp,application/octet-stream\nhlp,application/winhlp\nhqx,application/mac-binhex40\nhta,application/hta\nhtc,text/x-component\nhtm,text/html\nhtml,text/html\nhtt,text/webviewhtml\nhxt,text/html\nical,text/calendar\nicalendar,text/calendar\nico,image/x-icon\nics,text/calendar\nief,image/ief\nifb,text/calendar\niii,application/x-iphone\ninf,application/octet-stream\nins,application/x-internet-signup\nisp,application/x-internet-signup\nIVF,video/x-ivf\njar,application/java-archive\njava,application/octet-stream\njck,application/liquidmotion\njcz,application/liquidmotion\njfif,image/pjpeg\njpb,application/octet-stream\njpe,image/jpeg\njpeg,image/jpeg\njpg,image/jpeg\njs,text/javascript\njson,application/json\njsx,text/jscript\nlatex,application/x-latex\nlit,application/x-ms-reader\nlpk,application/octet-stream\nlsf,video/x-la-asf\nlsx,video/x-la-asf\nlzh,application/octet-stream\nm13,application/x-msmediaview\nm14,application/x-msmediaview\nm1v,video/mpeg\nm2ts,video/vnd.dlna.mpeg-tts\nm3u,audio/x-mpegurl\nm4a,audio/mp4\nm4v,video/mp4\nman,application/x-troff-man\nmanifest,application/x-ms-manifest\nmap,text/plain\nmarkdown,text/markdown\nmd,text/markdown\nmdb,application/x-msaccess\nmdp,application/octet-stream\nme,application/x-troff-me\nmht,message/rfc822\nmhtml,message/rfc822\nmid,audio/mid\nmidi,audio/mid\nmix,application/octet-stream\nmjs,text/javascript\nmmf,application/x-smaf\nmno,text/xml\nmny,application/x-msmoney\nmov,video/quicktime\nmovie,video/x-sgi-movie\nmp2,video/mpeg\nmp3,audio/mpeg\nmp4,video/mp4\nmp4v,video/mp4\nmpa,video/mpeg\nmpe,video/mpeg\nmpeg,video/mpeg\nmpg,video/mpeg\nmpp,application/vnd.ms-project\nmpv2,video/mpeg\nms,application/x-troff-ms\nmsi,application/octet-stream\nmso,application/octet-stream\nmvb,application/x-msmediaview\nmvc,application/x-miva-compiled\nnc,application/x-netcdf\nnsc,video/x-ms-asf\nnws,message/rfc822\nocx,application/octet-stream\noda,application/oda\nodc,text/x-ms-odc\nods,application/oleobject\noga,audio/ogg\nogg,video/ogg\nogv,video/ogg\nogx,application/ogg\none,application/onenote\nonea,application/onenote\nonetoc,application/onenote\nonetoc2,application/onenote\nonetmp,application/onenote\nonepkg,application/onenote\nosdx,application/opensearchdescription+xml\notf,font/otf\np10,application/pkcs10\np12,application/x-pkcs12\np7b,application/x-pkcs7-certificates\np7c,application/pkcs7-mime\np7m,application/pkcs7-mime\np7r,application/x-pkcs7-certreqresp\np7s,application/pkcs7-signature\npbm,image/x-portable-bitmap\npcx,application/octet-stream\npcz,application/octet-stream\npdf,application/pdf\npfb,application/octet-stream\npfm,application/octet-stream\npfx,application/x-pkcs12\npgm,image/x-portable-graymap\npko,application/vnd.ms-pki.pko\npma,application/x-perfmon\npmc,application/x-perfmon\npml,application/x-perfmon\npmr,application/x-perfmon\npmw,application/x-perfmon\npng,image/png\npnm,image/x-portable-anymap\npnz,image/png\npot,application/vnd.ms-powerpoint\npotm,application/vnd.ms-powerpoint.template.macroEnabled.12\npotx,application/vnd.openxmlformats-officedocument.presentationml.template\nppam,application/vnd.ms-powerpoint.addin.macroEnabled.12\nppm,image/x-portable-pixmap\npps,application/vnd.ms-powerpoint\nppsm,application/vnd.ms-powerpoint.slideshow.macroEnabled.12\nppsx,application/vnd.openxmlformats-officedocument.presentationml.slideshow\nppt,application/vnd.ms-powerpoint\npptm,application/vnd.ms-powerpoint.presentation.macroEnabled.12\npptx,application/vnd.openxmlformats-officedocument.presentationml.presentation\nprf,application/pics-rules\nprm,application/octet-stream\nprx,application/octet-stream\nps,application/postscript\npsd,application/octet-stream\npsm,application/octet-stream\npsp,application/octet-stream\npub,application/x-mspublisher\nqt,video/quicktime\nqtl,application/x-quicktimeplayer\nqxd,application/octet-stream\nra,audio/x-pn-realaudio\nram,audio/x-pn-realaudio\nrar,application/octet-stream\nras,image/x-cmu-raster\nrf,image/vnd.rn-realflash\nrgb,image/x-rgb\nrm,application/vnd.rn-realmedia\nrmi,audio/mid\nroff,application/x-troff\nrpm,audio/x-pn-realaudio-plugin\nrtf,application/rtf\nrtx,text/richtext\nscd,application/x-msschedule\nsct,text/scriptlet\nsea,application/octet-stream\nsetpay,application/set-payment-initiation\nsetreg,application/set-registration-initiation\nsgml,text/sgml\nsh,application/x-sh\nshar,application/x-shar\nsit,application/x-stuffit\nsldm,application/vnd.ms-powerpoint.slide.macroEnabled.12\nsldx,application/vnd.openxmlformats-officedocument.presentationml.slide\nsmd,audio/x-smd\nsmi,application/octet-stream\nsmx,audio/x-smd\nsmz,audio/x-smd\nsnd,audio/basic\nsnp,application/octet-stream\nspc,application/x-pkcs7-certificates\nspl,application/futuresplash\nspx,audio/ogg\nsrc,application/x-wais-source\nssm,application/streamingmedia\nsst,application/vnd.ms-pki.certstore\nstl,application/vnd.ms-pki.stl\nsv4cpio,application/x-sv4cpio\nsv4crc,application/x-sv4crc\nsvg,image/svg+xml\nsvgz,image/svg+xml\nswf,application/x-shockwave-flash\nt,application/x-troff\ntar,application/x-tar\ntcl,application/x-tcl\ntex,application/x-tex\ntexi,application/x-texinfo\ntexinfo,application/x-texinfo\ntgz,application/x-compressed\nthmx,application/vnd.ms-officetheme\nthn,application/octet-stream\ntif,image/tiff\ntiff,image/tiff\ntoc,application/octet-stream\ntr,application/x-troff\ntrm,application/x-msterminal\nts,video/vnd.dlna.mpeg-tts\ntsv,text/tab-separated-values\nttc,application/x-font-ttf\nttf,application/x-font-ttf\ntts,video/vnd.dlna.mpeg-tts\ntxt,text/plain\nu32,application/octet-stream\nuls,text/iuls\nustar,application/x-ustar\nvbs,text/vbscript\nvcf,text/x-vcard\nvcs,text/plain\nvdx,application/vnd.ms-visio.viewer\nvml,text/xml\nvsd,application/vnd.visio\nvss,application/vnd.visio\nvst,application/vnd.visio\nvsto,application/x-ms-vsto\nvsw,application/vnd.visio\nvsx,application/vnd.visio\nvtx,application/vnd.visio\nwasm,application/wasm\nwav,audio/wav\nwax,audio/x-ms-wax\nwbmp,image/vnd.wap.wbmp\nwcm,application/vnd.ms-works\nwdb,application/vnd.ms-works\nwebm,video/webm\nwebmanifest,application/manifest+json\nwebp,image/webp\nwks,application/vnd.ms-works\nwm,video/x-ms-wm\nwma,audio/x-ms-wma\nwmd,application/x-ms-wmd\nwmf,application/x-msmetafile\nwml,text/vnd.wap.wml\nwmlc,application/vnd.wap.wmlc\nwmls,text/vnd.wap.wmlscript\nwmlsc,application/vnd.wap.wmlscriptc\nwmp,video/x-ms-wmp\nwmv,video/x-ms-wmv\nwmx,video/x-ms-wmx\nwmz,application/x-ms-wmz\nwoff,application/font-woff\nwoff2,font/woff2\nwps,application/vnd.ms-works\nwri,application/x-mswrite\nwrl,x-world/x-vrml\nwrz,x-world/x-vrml\nwsdl,text/xml\nwtv,video/x-ms-wtv\nwvx,video/x-ms-wvx\nx,application/directx\nxaf,x-world/x-vrml\nxaml,application/xaml+xml\nxap,application/x-silverlight-app\nxbap,application/x-ms-xbap\nxbm,image/x-xbitmap\nxdr,text/plain\nxht,application/xhtml+xml\nxhtml,application/xhtml+xml\nxla,application/vnd.ms-excel\nxlam,application/vnd.ms-excel.addin.macroEnabled.12\nxlc,application/vnd.ms-excel\nxlm,application/vnd.ms-excel\nxls,application/vnd.ms-excel\nxlsb,application/vnd.ms-excel.sheet.binary.macroEnabled.12\nxlsm,application/vnd.ms-excel.sheet.macroEnabled.12\nxlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\nxlt,application/vnd.ms-excel\nxltm,application/vnd.ms-excel.template.macroEnabled.12\nxltx,application/vnd.openxmlformats-officedocument.spreadsheetml.template\nxlw,application/vnd.ms-excel\nxml,text/xml\nxof,x-world/x-vrml\nxpm,image/x-xpixmap\nxps,application/vnd.ms-xpsdocument\nxsd,text/xml\nxsf,text/xml\nxsl,text/xml\nxslt,text/xml\nxsn,application/octet-stream\nxtp,application/octet-stream\nxwd,image/x-xwindowdump\nz,application/x-compress\nzip,application/x-zip-compressed"
  },
  {
    "path": "Source/QuestPDF/Resources/PackageLicense.md",
    "content": "﻿# QuestPDF License\n\n## License Selection Guide\n\nWelcome to QuestPDF! This guide will help you understand how to select the appropriate license for our library, based on your usage context.\n\nThe licensing options for QuestPDF include the MIT license (which is free), and two tiers of paid licenses: the Professional License and the Enterprise License.\n\n### License Equality\n\nWe believe in offering the full power of QuestPDF to all our users, regardless of the license they choose. Whether you're operating under our Community MIT, Professional, or Enterprise licenses, you can enjoy the same comprehensive range of features:\n\n- Full access to all QuestPDF features.\n- Support for commercial usage.\n- Freedom to create and deploy unlimited closed-source projects, applications, and APIs.\n- Royalty-free redistribution of the compiled library with your applications.\n  \n### Transitive Dependency Usage\n\nIf you're using QuestPDF as a transitive dependency, you're free to use it under the MIT license without any cost. However, you're welcomed and encouraged to support the project by purchasing a paid license if you find the library valuable.\n\n### Non-profit Usage\n\nIf you represent an open-source project, a charitable organization, or are using QuestPDF for evaluation, learning or training purposes, you can also use QuestPDF for free under the MIT license.\n\n### Small Businesses\n\nFor companies generating less than $1M USD in annual gross revenue, you can use QuestPDF under the MIT license for free.\n\n### Larger Businesses\n\nCompanies with an annual gross revenue exceeding $1M USD are required to purchase a paid license. The type of license you need depends on the number of developers working on projects that use QuestPDF:\n\n- Professional License - If there are up to 10 developers in your company who are using QuestPDF, you need to purchase the Professional License.\n\n- Enterprise License - If your company has more than 10 developers using QuestPDF, the Enterprise License is the right choice.\n\n### Beyond Compliance\n\nRemember, purchasing a license isn't just about adhering to our guidelines, but also supporting the development of QuestPDF. Your contribution helps us to improve the library and offer top-notch support to all users.\n\n\n\n## QuestPDF Community MIT License\n\n### License Permissions\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n### Copyright\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n### Limitation Of Liability\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n## QuestPDF Professional and Enterprise Use License\n\n### Do No Harm\n\nBy downloading or using the Software, the Licensee agrees not to utilize the software in a manner which is disparaging to QuestPDF, and not to rent, lease or otherwise transfer rights to the Software.\n\n### License Permissions\n\nGrants the use of the Software by a specified number of developers to create and deploy closed-source software for unlimited end user organizations (\"The Organization\") in multiple locations. This license covers unlimited applications or projects. The Software may be deployed upon any number of machines for the end-use of The Organization. This license also intrinsically covers for development, staging and production servers for each project.\n\nGrants the right to distribute the Software (without royalty) as part of packaged commercial products.\n\n### License Fees\n\nA. If you wish to use the Software in a production environment, the purchase of a license is required. This license is perpetual, granting you continued use of the Software in accordance with the terms and conditions of this Agreement. The cost of the license is as indicated on the pricing page.\n\nB. Upon purchasing a license, you are also enrolled in a yearly, recurring subscription for software updates. This subscription is valid for a period of one year from the date of purchase, and it will automatically renew each year unless cancelled. We recommend maintaining your subscription as long as you are performing active software development to ensure you have access to the latest updates and improvements to the Software.\n\nC. However, it should be noted that the perpetual license allows use of only the latest library revision available at the time of or within the active subscription period, in accordance with the terms and conditions of this Agreement.\n\nD. If you wish to use the Software in a non-production environment, such as for testing and evaluation purposes, you may download and access the source and/or binaries at no charge. This access is subject to all license limitations and restrictions set forth in this Agreement.\n\n### Ownership\n\nQuestPDF shall at all times retain ownership of the QuestPDF Software library and all subsequent copies.\n\n### Copyright\n\nTitle, ownership rights, and intellectual property rights in and to the Software shall remain with QuestPDF. The Software is protected by the international copyright laws. Title, ownership rights, and intellectual property rights in and to the content accessed through the Software is the property of the applicable content owner and may be protected by applicable copyright or other law. This License gives you no rights to such content.\n\n### Limitation Of Liability\n\nTHIS SOFTWARE IS PROVIDED \"AS IS,\" WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. QUESTPDF AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL QUESTPDF OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF QUESTPDF HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES."
  },
  {
    "path": "Source/QuestPDF/Resources/ReleaseNotes.txt",
    "content": "- Fixed a bug where using Page.MinSize() or Page.MaxSize() could produce unexpected results\n- Added more helpful validation messages for minimum and maximum size constraints in the Constrained element\n- Improved the welcome message with a clearer explanation of the library license"
  },
  {
    "path": "Source/QuestPDF/Settings.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF\n{\n    public static class Settings\n    {\n        /// <summary>\n        /// <para>Please kindly select license type that applies to your usage of the QuestPDF library.</para>\n        /// <para>For more details, please check the <a href=\"https://www.questpdf.com/license\">QuestPDF License and Pricing webpage</a></para>\n        /// </summary>\n        public static LicenseType? License { get; set; }\n        \n        [Obsolete(\"This setting is ignored since the 2023.10 version. The new infinite layout detection algorithm works automatically. You can safely remove this setting from your codebase.\")]\n        public static int DocumentLayoutExceptionThreshold { get; set; } = 250;\n        \n        /// <summary>\n        /// This flag generates additional document elements to cache layout calculation results.\n        /// In the vast majority of cases, this significantly improves performance, while slightly increasing memory consumption.\n        /// </summary>\n        /// <remarks>Enabled by default.</remarks>\n        public static bool EnableCaching { get; set; } = true;\n        \n        /// <summary>\n        /// This flag generates additional document elements to improve layout debugging experience.\n        /// When the provided content contains size constraints impossible to meet, the library generates an enhanced exception message with additional location and layout measurement details.\n        /// </summary>\n        /// <remarks>By default, this flag is enabled only when the debugger IS attached.</remarks>  \n        public static bool EnableDebugging { get; set; } = System.Diagnostics.Debugger.IsAttached;\n        \n        /// <summary>\n        /// This flag enables checking the font glyph availability.\n        /// If your text contains glyphs that are not present in the specified font,\n        /// 1) when this flag is enabled: the DocumentDrawingException is thrown. OR \n        /// 2) when this flag is disabled: placeholder characters are visible in the produced PDF file. \n        /// Enabling this flag may slightly decrease document generation performance.\n        /// However, it provides hints that used fonts are not sufficient to produce correct results.\n        /// </summary>\n        /// <remarks>By default, this flag is enabled only when the debugger IS attached.</remarks>\n        public static bool CheckIfAllTextGlyphsAreAvailable { get; set; } = System.Diagnostics.Debugger.IsAttached;\n\n        /// <summary>\n        /// Decides whether the application should use the fonts available in the environment.\n        /// </summary>\n        /// <remarks>\n        /// <para>When set to <c>true</c>, the application will use the fonts installed on the system where it is running. This is the default behavior.</para>\n        /// <para>When set to <c>false</c>, the application will only use the fonts that have been registered using the <c>FontManager</c> class in the QuestPDF library.</para>\n        /// <para>This property is useful when you want to control the fonts used by your application, especially in cases where the environment might not have the necessary fonts installed.</para>\n        /// </remarks>\n        public static bool UseEnvironmentFonts { get; set; } = true;\n        \n        /// <summary>\n        /// Specifies the collection of paths where the library will automatically search for font files to register.\n        /// </summary>\n        /// <remarks>\n        /// <para>By default, this collection contains the application files path.</para>\n        /// <para>You can add additional paths to this collection to include more directories for automatic font registration.</para>\n        /// </remarks>\n        public static ICollection<string> FontDiscoveryPaths { get; } = new List<string>()\n        {\n            Helpers.Helpers.ApplicationFilesPath\n        };\n\n        /// <summary>\n        /// Gets or sets the file path used for temporary storage during the document generation process.\n        /// This path is used by various operations that require temporary files.\n        /// </summary>\n        public static string? TemporaryStoragePath { get; set; }\n        \n        static Settings()\n        {\n            SkNativeDependencyCompatibilityChecker.Test();\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkBitmap.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkBitmap : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n\n    public SkBitmap(int width, int height)\n    {\n        Instance = API.bitmap_create(width, height);\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    public SkData EncodeAsJpeg(int quality)\n    {\n        var dataInstance = API.bitmap_encode_as_jpg(Instance, quality);\n        return new SkData(dataInstance);\n    }\n    \n    public SkData EncodeAsPng()\n    {\n        var dataInstance = API.bitmap_encode_as_png(Instance);\n        return new SkData(dataInstance);\n    }\n    \n    public SkData EncodeAsWebp(int quality)\n    {\n        var dataInstance = API.bitmap_encode_as_webp(Instance, quality);\n        return new SkData(dataInstance);\n    }\n    \n    ~SkBitmap()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.bitmap_delete(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr bitmap_create(int width, int height);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void bitmap_delete(IntPtr image);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr bitmap_encode_as_jpg(IntPtr image, int quality);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr bitmap_encode_as_png(IntPtr image);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr bitmap_encode_as_webp(IntPtr image, int quality);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkBoxShadow.cs",
    "content": "using System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct SkBoxShadow\n{\n    public float OffsetX;\n    public float OffsetY;\n    public float Blur;\n    public uint Color;\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkCanvas.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkCanvas : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    private bool DisposeNativeObject { get; }\n\n    public SkCanvas(IntPtr instance, bool disposeNativeObject = true)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n        \n        DisposeNativeObject = disposeNativeObject;\n    }\n    \n    public static SkCanvas CreateFromBitmap(SkBitmap bitmap)\n    {\n        var instance = API.canvas_create_from_bitmap(bitmap.Instance);\n        return new SkCanvas(instance);\n    }\n    \n    public void Save()\n    {\n        API.canvas_save(Instance);\n    }\n    \n    public void Restore()\n    {\n        API.canvas_restore(Instance);\n    }\n    \n    public void Translate(float x, float y)\n    {\n        API.canvas_translate(Instance, x, y);\n    }\n    \n    public void Scale(float factorX, float factorY)\n    {\n        API.canvas_scale(Instance, factorX, factorY);\n    }\n    \n    public void Rotate(float degrees)\n    {\n        API.canvas_rotate(Instance, degrees);\n    }\n    \n    public void DrawLine(SkPoint start, SkPoint end, SkPaint paint)\n    {\n        API.canvas_draw_line(Instance, start, end, paint.Instance);\n    }\n\n    public void DrawRectangle(SkRect position, SkPaint paint)\n    {\n        API.canvas_draw_rectangle(Instance, position, paint.Instance);\n    }\n    \n    public void DrawComplexBorder(SkRoundedRect innerRect, SkRoundedRect outerRect, SkPaint paint)\n    {\n        API.canvas_draw_complex_border(Instance, innerRect, outerRect, paint.Instance);\n    }\n    \n    public void DrawShadow(SkRoundedRect shadowRect, SkBoxShadow shadow)\n    {\n        API.canvas_draw_shadow(Instance, shadowRect, shadow);\n    }\n    \n    public void DrawImage(SkImage image, float width, float height)\n    {\n        API.canvas_draw_image(Instance, image.Instance, width, height);\n    }\n    \n    public void DrawPicture(SkPicture picture)\n    {\n        API.canvas_draw_picture(Instance, picture.Instance);\n    }\n    \n    public void DrawParagraph(SkParagraph paragraph, int? lineFrom = null, int? lineTo = null)\n    {\n        API.canvas_draw_paragraph(Instance, paragraph.Instance, lineFrom ?? 0, lineTo ?? int.MaxValue);\n    }\n    \n    public void DrawSvgPath(string svg, uint color)\n    {\n        API.canvas_draw_svg_path(Instance, svg, color);\n    }\n    \n    public void DrawSvg(SkSvgImage svgImage, float width, float height)\n    {\n        API.canvas_draw_svg(Instance, svgImage.Instance, width, height);\n    }\n    \n    /// <summary>\n    /// draws stripe pattern (red lines at 45 deegree angle)\n    /// </summary>\n    public void DrawOverflowArea(SkRect position)\n    {\n        API.canvas_draw_overflow_area(Instance, position);\n    }\n    \n    public void ClipOverflowArea(SkRect availableSpace, SkRect requiredSpace)\n    {\n        API.canvas_clip_overflow_area(Instance, availableSpace, requiredSpace);\n    }\n    \n    public void ClipRectangle(SkRect clipArea)\n    {\n        API.canvas_clip_rectangle(Instance, clipArea);\n    }\n    \n    public void ClipRoundedRectangle(SkRoundedRect rect)\n    {\n        API.canvas_clip_rounded_rectangle(Instance, rect);\n    }\n    \n    public void AnnotateUrl(float width, float height, string url, string? description)\n    {\n        API.canvas_annotate_url(Instance, width, height, url, description);\n    }\n    \n    public void AnnotateDestination(string destinationName)\n    {\n        API.canvas_annotate_destination(Instance, destinationName);\n    }\n    \n    public void AnnotateDestinationLink(float width, float height, string destinationName, string? description)\n    {\n        API.canvas_annotate_destination_link(Instance, width, height, destinationName, description);\n    }\n    \n    public SkCanvasMatrix GetCurrentMatrix()\n    { \n        return API.canvas_get_matrix9(Instance);\n    }\n    \n    public void SetCurrentMatrix(SkCanvasMatrix matrix)\n    {\n        API.canvas_set_matrix9(Instance, matrix);\n    }\n    \n    public void SetSemanticNodeId(int nodeId)\n    {\n        API.canvas_set_semantic_node_id(Instance, nodeId);\n    }\n    \n    ~SkCanvas()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        if (DisposeNativeObject)\n            API.canvas_delete(Instance);\n        \n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr canvas_create_from_bitmap(IntPtr bitmap);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_delete(IntPtr canvas);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_save(IntPtr canvas);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_restore(IntPtr canvas);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_translate(IntPtr canvas, float x, float y);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_rotate(IntPtr canvas, float angle);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_scale(IntPtr canvas, float factorX, float factorY);\n\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_image(IntPtr canvas, IntPtr image, float width, float height);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_picture(IntPtr canvas, IntPtr picture);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_line(IntPtr canvas, SkPoint start, SkPoint end, IntPtr paint);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_rectangle(IntPtr canvas, SkRect position, IntPtr paint);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_complex_border(IntPtr canvas, SkRoundedRect innerRect, SkRoundedRect outerRect, IntPtr paint);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_shadow(IntPtr canvas, SkRoundedRect shadowRect, SkBoxShadow shadow);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_paragraph(IntPtr canvas, IntPtr paragraph, int lineFrom, int lineTo);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_svg_path(IntPtr canvas, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string svg, uint color);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_svg(IntPtr canvas, IntPtr svg, float width, float height);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_draw_overflow_area(IntPtr canvas, SkRect position);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_clip_overflow_area(IntPtr canvas, SkRect availableSpace, SkRect requiredSpace);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_clip_rectangle(IntPtr canvas, SkRect clipArea);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_clip_rounded_rectangle(IntPtr canvas, SkRoundedRect rect);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_annotate_url(\n            IntPtr canvas, \n            float width, \n            float height, \n            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string url,\n            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string? description);\n\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_annotate_destination(IntPtr canvas, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string destinationName);\n\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_annotate_destination_link(\n            IntPtr canvas, \n            float width,\n            float height, \n            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string destinationName,\n            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string? description);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern SkCanvasMatrix canvas_get_matrix9(IntPtr canvas);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_set_matrix9(IntPtr canvas, SkCanvasMatrix matrix);\n\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void canvas_set_semantic_node_id(IntPtr canvas, int nodeId);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkCanvasMatrix.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct SkCanvasMatrix\n{\n    public float ScaleX;\n    public float SkewX;\n    public float TranslateX;\n    \n    public float SkewY;\n    public float ScaleY;\n    public float TranslateY;\n\n    public float Perspective1;\n    public float Perspective2;\n    public float Perspective3;\n\n    public static readonly SkCanvasMatrix Identity = FromMatrix4x4(Matrix4x4.Identity);\n\n    public Matrix4x4 ToMatrix4x4()\n    {\n        return new Matrix4x4(\n            ScaleX, SkewY, 0, 0,\n            SkewX, ScaleY, 0, 0,\n            0, 0, Perspective3, 0,\n            TranslateX, TranslateY, 0, 1);\n    }\n    \n    public static SkCanvasMatrix FromMatrix4x4(Matrix4x4 matrix)\n    {\n        return new SkCanvasMatrix\n        {\n            ScaleX = matrix.M11,\n            SkewX = matrix.M21,\n            TranslateX = matrix.M41,\n            \n            SkewY = matrix.M12,\n            ScaleY = matrix.M22,\n            TranslateY = matrix.M42,\n            \n            Perspective1 = 0,\n            Perspective2 = 0,\n            Perspective3 = 1\n        };\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkData.cs",
    "content": "using System;\nusing System.IO;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkData : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n\n    public SkData(IntPtr instance)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    public static SkData FromFile(string filePath)\n    {\n        var instance = API.data_create_from_file(filePath);\n        \n        if (instance == IntPtr.Zero)\n            throw new Exception($\"Cannot load a file under the provided path: {filePath}.\");\n        \n        return new SkData(instance);\n    }\n    \n    public static SkData FromStream(Stream stream)\n    {\n        using var memoryStream = new MemoryStream();\n        stream.CopyTo(memoryStream);\n        \n        var binaryData = memoryStream.ToArray();\n        return SkData.FromBinary(binaryData);\n    }\n    \n    public static unsafe SkData FromBinary(byte[] data)\n    {\n        fixed (byte* dataPtr = data)\n        {\n            var instance = API.data_create_from_binary(dataPtr, data.Length);\n            GC.KeepAlive(data);\n            return new SkData(instance);\n        }\n    }\n    \n    public byte[] ToBytes()\n    {\n        var content = API.data_get_bytes(Instance);\n        \n        var result = new byte[content.length];\n        Marshal.Copy(content.bytes, result, 0, content.length);\n        \n        // do not Marshal.FreeHGlobal(content.bytes)\n        // this array is managed by SkData\n        \n        return result;\n    }\n    \n    ~SkData()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.data_unref(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr data_create_from_file([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string path);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern unsafe IntPtr data_create_from_binary(byte* arrayPointer, int arrayLength);\n    \n        [StructLayout(LayoutKind.Sequential)]\n        public struct GetBytesFromDataResult\n        {\n            public int length;\n            public IntPtr bytes;\n        }\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern GetBytesFromDataResult data_get_bytes(IntPtr data);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void data_unref(IntPtr data);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkDateTime.cs",
    "content": "namespace QuestPDF.Skia;\n\ninternal struct SkDateTime\n{\n    public short TimeZoneMinutes;\n    public ushort Year;\n    public byte Month;\n    public byte DayOfWeek;\n    public byte Day;\n    public byte Hour;\n    public byte Minute;\n    public byte Second;\n        \n    public SkDateTime(System.DateTimeOffset dateTime)\n    {\n        TimeZoneMinutes = (short)(dateTime.Offset.TotalMinutes);\n        Year = (ushort)dateTime.Year;\n        Month = (byte)dateTime.Month;\n        DayOfWeek = (byte)dateTime.DayOfWeek;\n        Day = (byte)dateTime.Day;\n        Hour = (byte)dateTime.Hour;\n        Minute = (byte)dateTime.Minute;\n        Second = (byte)dateTime.Second;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkDocument.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkDocument : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n\n    internal SkDocument(IntPtr instance)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n\n    public SkCanvas BeginPage(float width, float height)\n    {\n        var instance = API.document_begin_page(Instance, width, height);\n        return new SkCanvas(instance, disposeNativeObject: false);\n    }\n    \n    public void EndPage()\n    {\n        API.document_end_page(Instance);\n    }\n\n    public void Close()\n    {\n        API.document_close(Instance);\n    }\n    \n    ~SkDocument()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.document_unref(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr document_begin_page(IntPtr document, float width, float height);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void document_end_page(IntPtr document);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void document_close(IntPtr document);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void document_unref(IntPtr document);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkImage.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkImage : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n\n    public readonly int Width;\n    public readonly int Height;\n    public readonly int EncodedDataSize;\n    \n    public SkImage(IntPtr instance)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n        \n        // load image details\n        var details = API.image_get_details(Instance);\n        \n        Width = details.Width;\n        Height = details.Height;\n        EncodedDataSize = details.EncodedDataSize;\n        \n        GC.AddMemoryPressure(EncodedDataSize);\n    }\n\n    public static SkImage FromData(SkData data)\n    {\n        var instance = API.image_create_from_data(data.Instance);\n        \n        if (instance == IntPtr.Zero)\n            throw new Exception(\"Cannot decode the provided image.\");\n        \n        return new SkImage(instance);\n    }\n    \n    /// <summary>\n    /// Scales image only when target size is smaller than original image size.\n    /// When image is opaque, uses the JPEG compression algorithm, otherwise uses the PNG algorithm.\n    /// Only the JPEG compression algorithm uses the compressionQuality parameter.\n    /// </summary>\n    public SkImage ResizeAndCompress(int targetWidth, int targetHeight, int compressionQuality, bool downsample)\n    {\n        var instance = API.image_resize_and_compress(Instance, targetWidth, targetHeight, compressionQuality, downsample);\n        return new SkImage(instance);\n    }\n    \n    public static SkImage GeneratePlaceholder(int targetWidth, int targetHeight, uint firstColor, uint secondColor)\n    {\n        var instance = API.image_generate_placeholder(targetWidth, targetHeight, firstColor, secondColor);\n        return new SkImage(instance);\n    }\n    \n    public SkData GetEncodedData()\n    {\n        var dataInstance = API.image_get_encoded_data(Instance);\n        return new SkData(dataInstance);\n    }\n    \n    ~SkImage()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.image_unref(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n        GC.RemoveMemoryPressure(EncodedDataSize);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr image_create_from_data(IntPtr data);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void image_unref(IntPtr image);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr image_resize_and_compress(IntPtr image, int targetImageWidth, int targetImageHeight, int compressionQuality, bool downsample);\n\n        [StructLayout(LayoutKind.Sequential)]\n        public struct SkImageDetails\n        {\n            public int Width;\n            public int Height;\n            public int EncodedDataSize;\n        }\n\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern SkImageDetails image_get_details(IntPtr image);\n\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr image_get_encoded_data(IntPtr image);\n \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr image_generate_placeholder(int imageWidth, int imageHeight, UInt32 firstColor, UInt32 secondColor);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkNativeDependencyCompatibilityChecker.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.Skia;\n\ninternal static class SkNativeDependencyCompatibilityChecker\n{\n    private const int ExpectedNativeLibraryVersion = 13;\n    \n    private static NativeDependencyCompatibilityChecker Instance { get; } = new()\n    {\n        ExecuteNativeCode = ExecuteNativeCode,\n        CheckNativeLibraryVersion = CheckNativeLibraryVersion\n    };\n    \n    public static void Test()\n    {\n        Instance.Test();\n    }\n\n    private static bool CheckNativeLibraryVersion()\n    {\n        try\n        {\n            return API.get_questpdf_version() == ExpectedNativeLibraryVersion;\n        }\n        catch\n        {\n            return false;\n        }\n    }\n    \n    private static void ExecuteNativeCode()\n    {\n        var random = new Random();\n            \n        var a = random.Next();\n        var b = random.Next();\n        \n        var expected = a + b;\n        var returned = API.check_compatibility_by_calculating_sum(a, b);\n        \n        if (expected != returned)\n            throw new Exception();\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern int get_questpdf_version();\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern int check_compatibility_by_calculating_sum(int a, int b);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkPaint.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkPaint : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    \n    public SkPaint()\n    {\n        Instance = API.paint_create();\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    public void SetSolidColor(uint color)\n    {\n        API.paint_set_solid_color(Instance, color);\n    }\n    \n    public void SetLinearGradient(Position start, Position end, Color[] colors)\n    {\n        if (colors.Length == 0)\n            throw new ArgumentException(\"At least one color must be provided to create a gradient.\", nameof(colors));\n        \n        var startPoint = new SkPoint(start.X, start.Y);\n        var endPoint = new SkPoint(end.X, end.Y);\n        \n        var colorArray = colors.Select(c => c.Hex).ToArray();\n        \n        API.paint_set_linear_gradient(Instance, startPoint, endPoint, colorArray.Length, colorArray);\n    }\n    \n    public void SetStroke(float thickness)\n    {\n        API.paint_set_stroke(Instance, thickness);\n    }\n    \n    public void SetDashedPathEffect(float[] intervals)\n    {\n        if (intervals.Length == 0)\n            throw new ArgumentException(\"At least one interval must be provided to create a dashed path effect.\", nameof(intervals));\n        \n        if (intervals.Length % 2 != 0)\n            throw new ArgumentException(\"The intervals array must contain an even number of elements.\", nameof(intervals));\n        \n        API.paint_set_dashed_path_effect(Instance, intervals.Length, intervals);\n    }\n    \n    ~SkPaint()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.paint_delete(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr paint_create();\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paint_delete(IntPtr paint);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paint_set_solid_color(IntPtr paint, uint color);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paint_set_linear_gradient(IntPtr paint, SkPoint start, SkPoint end,  int colorsLength, uint[] colors);    \n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paint_set_stroke(IntPtr paint, float thickness);    \n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paint_set_dashed_path_effect(IntPtr paint, int arrayLength, float[] intervals); \n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkPdfDocument.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\nusing System.Xml;\n\nnamespace QuestPDF.Skia;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct SkPdfDocumentMetadata\n{\n    public IntPtr Title; // string\n    public IntPtr Author; // string\n    public IntPtr Subject; // string\n    public IntPtr Keywords; // string\n    public IntPtr Creator; // string\n    public IntPtr Producer; // string\n    public IntPtr Language; // string\n\n    public SkDateTime CreationDate;\n    public SkDateTime ModificationDate;\n\n    public PDFA_Conformance PDFA_Conformance;\n    public PDFUA_Conformance PDFUA_Conformance;\n    \n    [MarshalAs(UnmanagedType.I1)] public bool CompressDocument;\n    public float RasterDPI;\n\n    public IntPtr SemanticNodeRoot;\n}\n\ninternal enum PDFA_Conformance\n{\n    None = 0,\n    PDFA_1A = 1,\n    PDFA_1B = 2,\n    PDFA_2A = 3,\n    PDFA_2B = 4,\n    PDFA_2U = 5,\n    PDFA_3A = 6,\n    PDFA_3B = 7,\n    PDFA_3U = 8\n}\n\ninternal enum PDFUA_Conformance\n{\n    None = 0,\n    PDFUA_1 = 1\n}\n\ninternal static class SkPdfDocument\n{\n    public static SkDocument Create(SkWriteStream stream, SkPdfDocumentMetadata metadata)\n    {\n        var instance = API.pdf_document_create(stream.Instance, metadata);\n        return new SkDocument(instance);\n    }\n\n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr pdf_document_create(IntPtr stream, SkPdfDocumentMetadata metadata);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkPdfTag.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkPdfTag : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    public int NodeId { get; set; }\n    public string Type { get; set; } = \"\";\n    public string? Alt { get; set; }\n    public string? Lang { get; set; }\n    private ICollection<SkPdfTag>? Children { get; set; }\n    \n    private SkPdfTag(IntPtr instance)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    public static SkPdfTag Create(int nodeId, string? type, string? alt, string? lang)\n    {\n        var instance = API.pdf_structure_element_create(nodeId, type, alt, lang);\n        return new SkPdfTag(instance) { NodeId = nodeId, Type = type ?? \"\", Alt = alt, Lang = lang };\n    }\n    \n    public void SetChildren(ICollection<SkPdfTag> children)\n    {\n        Children = children;\n        \n        var childrenArray = children.ToArray();\n        var childrenPointers = childrenArray.Select(c => c.Instance).ToArray();\n        var unmanagedArray = Marshal.AllocHGlobal(IntPtr.Size * childrenPointers.Length);\n        Marshal.Copy(childrenPointers, 0, unmanagedArray, childrenPointers.Length);\n        \n        API.pdf_structure_element_set_children(Instance, unmanagedArray, childrenPointers.Length);\n        Marshal.FreeHGlobal(unmanagedArray);\n    }\n\n    public void AddAttribute(string owner, string name, object value)\n    {\n        // for some reason, other marshaling approaches do not work \n        var ownerBytes = Encoding.ASCII.GetBytes(owner + \"\\0\");\n        var nameBytes = Encoding.ASCII.GetBytes(name + \"\\0\");\n        \n        if (value is string textValue)\n        {\n            var valueBytes = Encoding.ASCII.GetBytes(textValue + \"\\0\");\n            API.pdf_structure_element_add_attribute_text(Instance, ownerBytes, nameBytes, valueBytes);\n        }\n        else if (value is int intValue)\n        {\n            API.pdf_structure_element_add_attribute_integer(Instance, ownerBytes, nameBytes, intValue);\n        }\n        else if (value is float floatValue)\n        {\n            API.pdf_structure_element_add_attribute_float(Instance, ownerBytes, nameBytes, floatValue);\n        }\n        else if (value is float[] floatArray)\n        {\n            API.pdf_structure_element_add_attribute_float_array(Instance, ownerBytes, nameBytes, floatArray, floatArray.Length);\n        }\n        else if (value is int[] nodeIds)\n        {\n            API.pdf_structure_element_add_attribute_node_ids(Instance, ownerBytes, nameBytes, nodeIds, nodeIds.Length);\n        }\n        else\n        {\n            throw new ArgumentException($\"Unsupported attribute value type: {value.GetType()}\");\n        }\n    }\n\n    ~SkPdfTag()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n\n        // to dispose the entire tree, it is enough to invoke the pdf_structure_element_delete method on the root element\n        // root's children should be only marked as disposed\n        DisposeChildren(this);\n        \n        API.pdf_structure_element_delete(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n        \n        static void DisposeChildren(SkPdfTag parent)\n        {\n            if (parent.Children == null)\n                return;\n\n            foreach (var child in parent.Children)\n            {\n                child.Instance = IntPtr.Zero;\n                GC.SuppressFinalize(child);\n                DisposeChildren(child);\n            }\n        }\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr pdf_structure_element_create(\n            int nodeId,\n            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string type,\n            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string alt,\n            [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string lang);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void pdf_structure_element_set_children(IntPtr element, IntPtr children, int count);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void pdf_structure_element_add_attribute_text(IntPtr element, byte[] owner, byte[] name, byte[] value);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void pdf_structure_element_add_attribute_integer(IntPtr element, byte[] owner, byte[] name, int value);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void pdf_structure_element_add_attribute_float(IntPtr element, byte[] owner, byte[] name, float value);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void pdf_structure_element_add_attribute_float_array(IntPtr element, byte[] owner, byte[] name, float[] array, int arrayLength);\n\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void pdf_structure_element_add_attribute_node_ids(IntPtr element, byte[] owner, byte[] name, int[] array, int arrayLength);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void pdf_structure_element_delete(IntPtr element);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkPicture.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkPicture : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    \n    public SkPicture(IntPtr instance)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    public static SkPicture Deserialize(SkData data)\n    {\n        var instance = API.picture_deserialize(data.Instance);\n        return new SkPicture(instance);\n    }\n    \n    public SkData Serialize()\n    {\n        var dataInstance = API.picture_serialize(Instance);\n        return new SkData(dataInstance);\n    }\n    \n    ~SkPicture()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.picture_unref(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void picture_unref(IntPtr picture);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr picture_serialize(IntPtr picture);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr picture_deserialize(IntPtr data);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkPictureRecorder.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkPictureRecorder : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    private bool IsRecording { get; set; }\n    \n    public SkPictureRecorder()\n    {\n        Instance = API.picture_recorder_create();\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n\n    public SkCanvas BeginRecording(float width, float height)\n    {\n        var canvasInstance = API.picture_recorder_begin_recording(Instance, width, height);\n        IsRecording = true;\n        return new SkCanvas(canvasInstance, disposeNativeObject: false);\n    }\n    \n    public SkPicture EndRecording()\n    {\n        var pictureInstance = API.picture_recorder_end_recording(Instance);\n        IsRecording = false;\n        return new SkPicture(pictureInstance);\n    }\n    \n    ~SkPictureRecorder()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n\n        if (IsRecording)\n        {\n            try\n            {\n                var picture = EndRecording();\n                picture.Dispose();\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n        \n        API.picture_recorder_delete(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr picture_recorder_create();\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr picture_recorder_begin_recording(IntPtr pictureRecorder, float width, float height);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr picture_recorder_end_recording(IntPtr pictureRecorder);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void picture_recorder_delete(IntPtr pictureRecorder);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkPoint.cs",
    "content": "using System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct SkPoint(float x, float y)\n{\n    public float X = x;\n    public float Y = y;\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkRect.cs",
    "content": "using System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct SkRect\n{\n    public float Left;\n    public float Top;\n    public float Right;\n    public float Bottom;\n    \n    public SkRect(float left, float top, float right, float bottom)\n    {\n        Left = left;\n        Top = top;\n        Right = right;\n        Bottom = bottom;\n    }\n    \n    public float Width => Right - Left;\n    public float Height => Bottom - Top;\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkResourceProvider.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkResourceProvider\n{\n    public IntPtr Instance { get; private set; }\n    \n    public static SkResourceProvider Local { get; } = new(SkFontManager.Local);\n    public static SkResourceProvider Global { get; } = new(SkFontManager.Global);\n    \n    internal static SkResourceProvider CurrentResourceProvider => Settings.UseEnvironmentFonts ? Global : Local;\n\n    private SkResourceProvider(SkFontManager fontManager)\n    {\n        Instance = API.resource_provider_create(Helpers.Helpers.ApplicationFilesPath, fontManager.Instance);\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr resource_provider_create(string resourcesPath, IntPtr fontManager);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkRoundedRect.cs",
    "content": "using System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct SkRoundedRect\n{\n    public SkRect Rect;\n    public SkPoint TopLeftRadius;\n    public SkPoint TopRightRadius;\n    public SkPoint BottomRightRadius;\n    public SkPoint BottomLeftRadius;\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkSemanticNodeSpecialId.cs",
    "content": "namespace QuestPDF.Skia;\n\ninternal class SkSemanticNodeSpecialId\n{\n    public const int Nothing = 0;\n    public const int OtherArtifact = -1;\n    public const int PaginationArtifact = -2;\n    public const int PaginationHeaderArtifact = -3;\n    public const int PaginationFooterArtifact = -4;\n    public const int PaginationWatermarkArtifact = -5;\n    public const int LayoutArtifact = -6;\n    public const int PageArtifact = -7;\n    public const int BackgroundArtifact = -8;\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkSize.cs",
    "content": "using System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct SkSize\n{\n    public float Width;\n    public float Height;\n    \n    public SkSize(float width, float height)\n    {\n        Width = width;\n        Height = height;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkSvgCanvas.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkSvgCanvas\n{\n    public static SkCanvas CreateSvg(float width, float height, SkWriteStream writeStream)\n    {\n        var bounds = new SkRect(0, 0, width, height);\n        var instance = API.svg_create_canvas(bounds, writeStream.Instance);\n        return new SkCanvas(instance);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr svg_create_canvas(SkRect bounds, IntPtr writeStream);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkSvgImage.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.Skia;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct SkSvgImageSize\n{\n    public float Width;\n    public float Height;\n    \n    public Unit WidthUnit;\n    public Unit HeightUnit;\n    \n    public enum Unit\n    {\n        Unknown,\n        Number,\n        Percentage,\n        Pixels,\n        Centimeters,\n        Millimeters,\n        Inches,\n        Points,\n        Picas, // 1 Pica = 12 points\n    }\n}\n\ninternal sealed class SkSvgImage : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    public SkSvgImageSize Size;\n    public SkRect ViewBox;\n    \n    public SkSvgImage(string svgString, SkResourceProvider resourceProvider, SkFontManager fontManager)\n    {\n        using var data = SkData.FromBinary(System.Text.Encoding.UTF8.GetBytes(svgString));\n\n        Instance = API.svg_create(data.Instance, resourceProvider.Instance, fontManager.Instance);\n        \n        if (Instance == IntPtr.Zero)\n            throw new Exception(\"Cannot decode the provided SVG image.\");\n        \n        API.svg_get_size(Instance, out Size, out ViewBox);\n    }\n\n    internal float AspectRatio\n    {\n        get\n        {\n            if (Size.WidthUnit is SkSvgImageSize.Unit.Percentage || Size.HeightUnit is SkSvgImageSize.Unit.Percentage)\n                return ViewBox.Width / ViewBox.Height;\n        \n            return Size.Width / Size.Height;\n        }\n    }\n    \n    ~SkSvgImage()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.svg_unref(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr svg_create(IntPtr data, IntPtr resourceProvider, IntPtr fontManager);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void svg_unref(IntPtr svg);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void svg_get_size(IntPtr svg, out SkSvgImageSize size, out SkRect viewBox);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkText.cs",
    "content": "using System;\nusing System.Text;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkText : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n\n    public SkText(string? text)\n    {\n        Instance = MarshalFromManagedToNative(text);\n    }\n\n    ~SkText()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public static unsafe IntPtr MarshalFromManagedToNative(string? text)\n    {\n        if (text == null) \n            return IntPtr.Zero;\n\n        var length = Encoding.UTF8.GetByteCount(text);\n        var nativeArray = Marshal.AllocHGlobal(length + 1);\n        \n        fixed (char* pText = text)\n        {\n            var ptr = (byte*)nativeArray;\n            Encoding.UTF8.GetBytes(pText, text.Length, ptr, length);\n        }\n        \n        Marshal.WriteByte(nativeArray, length, 0); // null termination\n        \n        return nativeArray;\n    } \n    \n    public static implicit operator IntPtr(SkText text) => text.Instance;\n    \n    public void Dispose()\n    {\n        if (Instance != IntPtr.Zero)\n        {\n            Marshal.FreeHGlobal(Instance);\n            Instance = IntPtr.Zero;\n        }\n        \n        GC.SuppressFinalize(this);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkWriteStream.cs",
    "content": "using System;\nusing System.IO;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class SkWriteStream : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    private GCHandle CallbackHandle { get; }\n\n    public SkWriteStream(Stream stream)\n    {\n        var nativeCallback = new API.ByteArrayCallback((data, size) =>\n        {\n#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER\n            unsafe\n            {\n                var span = new ReadOnlySpan<byte>((void*)data, size);\n                stream.Write(span);\n            }\n#else\n            var managedArray = new byte[size];\n            Marshal.Copy(data, managedArray, 0, size);\n            stream?.Write(managedArray, 0, managedArray.Length);\n#endif\n        });\n\n        CallbackHandle = GCHandle.Alloc(nativeCallback);\n        \n        Instance = API.write_stream_create(nativeCallback);\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    public void Flush()\n    {\n        API.write_stream_flush(Instance);\n    }\n    \n    ~SkWriteStream()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n     \n        CallbackHandle.Free();\n        API.write_stream_delete(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n        public delegate void ByteArrayCallback(IntPtr data, int size);\n\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr write_stream_create(ByteArrayCallback callback);\n    \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void write_stream_flush(IntPtr stream);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void write_stream_delete(IntPtr stream);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkXpsDocument.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal static class SkXpsDocument\n{\n    public static SkDocument Create(SkWriteStream stream, float dpi)\n    {\n        var instance = API.xps_document_create(stream.Instance, dpi);\n        return new SkDocument(instance);\n    }\n\n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr xps_document_create(IntPtr stream, float dpi);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/SkiaAPI.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing QuestPDF.Drawing.Exceptions;\n\nnamespace QuestPDF.Skia;\n\ninternal static class SkiaAPI\n{\n    public const string LibraryName = \"QuestPdfSkia\";\n    \n    public static void EnsureNotNull(IntPtr instance)\n    {\n        if (instance == IntPtr.Zero)\n            throw new InitializationException($\"QuestPDF cannot instantiate native object.\");\n    }\n    \n    public static void WarnThatFinalizerIsReached<T>(this T disposableObject) where T : IDisposable\n    {\n        Debug.Fail($\"An object of type '{typeof(T).Name}' was not disposed explicitly, and was finalized instead.\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/Text/SkFontCollection.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia.Text;\n\ninternal sealed class SkFontCollection : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    \n    public SkFontCollection(IntPtr instance)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n\n    public static SkFontCollection Create(SkTypefaceProvider typefaceProvider, SkFontManager fontManager)\n    {\n        var instance = API.font_collection_create(fontManager.Instance, typefaceProvider.Instance);\n        return new SkFontCollection(instance);\n    }\n    \n    ~SkFontCollection()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.font_collection_unref(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr font_collection_create(IntPtr fontManager, IntPtr typefaceProvider);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void font_collection_unref(IntPtr fontCollection);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/Text/SkFontManager.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia.Text;\n\ninternal sealed class SkFontManager\n{\n    public IntPtr Instance { get; }\n    \n    public static SkFontManager Local { get; } = new(API.font_manager_create_local(Settings.FontDiscoveryPaths.FirstOrDefault() ?? Helpers.Helpers.ApplicationFilesPath));\n    public static SkFontManager Global { get; } = new(API.font_manager_create_global());\n\n    private SkFontManager(IntPtr instance)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    public SkTypeface CreateTypeface(SkData data)\n    {\n        var instance = API.font_manager_create_typeface(Instance, data.Instance);\n        \n        if (instance == IntPtr.Zero)\n            throw new Exception(\"Cannot decode the provided font file.\");\n        \n        return new SkTypeface(instance);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr font_manager_create_local(string path);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr font_manager_create_global();\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr font_manager_create_typeface(IntPtr fontManager, IntPtr fontData);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/Text/SkParagraph.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia.Text;\n\ninternal sealed class SkParagraph : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    \n    public SkParagraph(IntPtr instance)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n\n    public void PlanLayout(float availableWidth)\n    {\n        API.paragraph_plan_layout(Instance, availableWidth);\n    }\n    \n    public SkSize[] GetLineMetrics()\n    {\n        API.paragraph_get_line_metrics(Instance, out var array, out var arrayLength);\n        \n        var managedArray = new SkSize[arrayLength];\n        \n        var size = Marshal.SizeOf<SkSize>();\n        \n        for (var i = 0; i < arrayLength; i++)\n        {\n            var ptr = IntPtr.Add(array, i * size);\n            managedArray[i] = Marshal.PtrToStructure<SkSize>(ptr);\n        }\n\n        API.paragraph_delete_line_metrics(array);\n        return managedArray;\n    }\n    \n    public int[] GetUnresolvedCodepoints()\n    {\n        API.paragraph_get_unresolved_codepoints(Instance, out var array, out var arrayLength);\n        \n        var managedArray = new int[arrayLength];\n        Marshal.Copy(array, managedArray,  0, arrayLength);\n        API.paragraph_delete_unresolved_codepoints(array);\n\n        return managedArray;\n    }\n    \n    public SkRect[] GetPlaceholderPositions()\n    {\n        API.paragraph_get_placeholder_positions(Instance, out var array, out var arrayLength);\n        \n        var managedArray = new SkRect[arrayLength];\n        \n        var size = Marshal.SizeOf<SkRect>();\n        \n        for (var i = 0; i < arrayLength; i++)\n        {\n            var ptr = IntPtr.Add(array, i * size);\n            managedArray[i] = Marshal.PtrToStructure<SkRect>(ptr);\n        }\n\n        API.paragraph_delete_positions(array);\n        return managedArray;\n    }\n    \n    public SkRect[] GetTextRangePositions(int rangeStart, int rangeEnd)\n    {\n        API.paragraph_get_text_range_positions(Instance, rangeStart, rangeEnd, out var array, out var arrayLength);\n        \n        var managedArray = new SkRect[arrayLength];\n        \n        var size = Marshal.SizeOf<SkRect>();\n        \n        for (var i = 0; i < arrayLength; i++)\n        {\n            var ptr = IntPtr.Add(array, i * size);\n            managedArray[i] = Marshal.PtrToStructure<SkRect>(ptr);\n        }\n\n        API.paragraph_delete_positions(array);\n        return managedArray;\n    }\n    \n    ~SkParagraph()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.paragraph_delete(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_plan_layout(IntPtr paragraph, float availableWidth);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_get_line_metrics(IntPtr paragraph, out IntPtr array, out int arrayLength);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_delete_line_metrics(IntPtr array);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_get_unresolved_codepoints(IntPtr paragraph, out IntPtr array, out int arrayLength);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_delete_unresolved_codepoints(IntPtr array);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_get_placeholder_positions(IntPtr paragraph, out IntPtr array, out int arrayLength);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_get_text_range_positions(IntPtr paragraph, int rangeStart, int rangeEnd, out IntPtr array, out int arrayLength);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_delete_positions(IntPtr array);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_delete(IntPtr paragraph);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/Text/SkParagraphBuilder.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia.Text;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal record struct ParagraphStyleConfiguration\n{\n    public TextAlign Alignment;\n    public TextDirection Direction;\n    public int MaxLinesVisible;\n    public IntPtr LineClampEllipsis; // SKText\n\n    internal enum TextAlign\n    {\n        Left,\n        Right,\n        Center,\n        Justify,\n        Start,\n        End\n    }\n    \n    internal enum TextDirection\n    {\n        Rtl,\n        Ltr\n    }\n}\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct SkPlaceholderStyle\n{\n    public float Width;\n    public float Height;\n    public PlaceholderAlignment Alignment;\n    public PlaceholderBaseline Baseline;\n    public float BaselineOffset;\n\n    public SkPlaceholderStyle()\n    {\n        Width = 0;\n        Height = 0;\n        Alignment = PlaceholderAlignment.AboveBaseline;\n        Baseline = PlaceholderBaseline.Alphabetic;\n        BaselineOffset = 0;\n    }\n    \n    internal enum PlaceholderAlignment\n    {\n        /// Match the baseline of the placeholder with the baseline.\n        Baseline,\n\n        /// Align the bottom edge of the placeholder with the baseline such that the\n        /// placeholder sits on top of the baseline.\n        AboveBaseline,\n\n        /// Align the top edge of the placeholder with the baseline specified in\n        /// such that the placeholder hangs below the baseline.\n        BelowBaseline,\n\n        /// Align the top edge of the placeholder with the top edge of the font.\n        /// When the placeholder is very tall, the extra space will hang from\n        /// the top and extend through the bottom of the line.\n        Top,\n\n        /// Align the bottom edge of the placeholder with the top edge of the font.\n        /// When the placeholder is very tall, the extra space will rise from\n        /// the bottom and extend through the top of the line.\n        Bottom,\n\n        /// Align the middle of the placeholder with the middle of the text. When the\n        /// placeholder is very tall, the extra space will grow equally from\n        /// the top and bottom of the line.\n        Middle,\n    }\n    \n    internal enum PlaceholderBaseline\n    {\n        Alphabetic,\n        Ideographic\n    }\n}\n\nrecord ParagraphStyle\n{\n    public ParagraphStyleConfiguration.TextAlign Alignment { get; init; }\n    public ParagraphStyleConfiguration.TextDirection Direction { get; init; }\n    public int MaxLinesVisible { get; init; }\n    public string LineClampEllipsis { get; init; }\n}\n\ninternal sealed class SkParagraphBuilder : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    \n    public ParagraphStyle Style { get; private set; }\n    private SkFontCollection FontCollection { get; set; }\n\n    public static SkParagraphBuilder Create(ParagraphStyle style, SkFontCollection fontCollection)\n    {\n        using var clampLinesEllipsis = new SkText(style.LineClampEllipsis);\n\n        var paragraphStyleConfiguration = new ParagraphStyleConfiguration\n        {\n            Alignment = style.Alignment,\n            Direction = style.Direction,\n            MaxLinesVisible = style.MaxLinesVisible,\n            LineClampEllipsis = clampLinesEllipsis.Instance\n        };\n        \n        var instance = API.paragraph_builder_create(paragraphStyleConfiguration, SkUnicode.Global.Instance, fontCollection.Instance);\n        SkiaAPI.EnsureNotNull(instance);\n        \n        return new SkParagraphBuilder\n        {\n            Instance = instance,\n            Style = style,\n            FontCollection = fontCollection\n        };\n    }\n    \n    public void AddText(string text, SkTextStyle textStyle)\n    {\n        API.paragraph_builder_add_text(Instance, text, textStyle.Instance);\n    }\n    \n    public void AddPlaceholder(SkPlaceholderStyle placeholderStyle)\n    {\n        API.paragraph_builder_add_placeholder(Instance, placeholderStyle);\n    }\n    \n    public SkParagraph CreateParagraph()\n    {\n        var instance = API.paragraph_builder_create_paragraph(Instance);\n        return new SkParagraph(instance);\n    }\n    \n    public void Reset()\n    {\n        API.paragraph_builder_reset(Instance);\n    }\n    \n    ~SkParagraphBuilder()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        FontCollection?.Dispose();\n        \n        API.paragraph_builder_delete(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr paragraph_builder_create(ParagraphStyleConfiguration paragraphStyleConfiguration, IntPtr unicode, IntPtr fontCollection);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_builder_add_text(IntPtr paragraphBuilder, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string text, IntPtr textStyle);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_builder_add_placeholder(IntPtr paragraphBuilder, SkPlaceholderStyle placeholderStyle);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr paragraph_builder_create_paragraph(IntPtr paragraphBuilder);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_builder_reset(IntPtr paragraphBuilder);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void paragraph_builder_delete(IntPtr paragraphBuilder);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/Text/SkTextStyle.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia.Text;\n\n[StructLayout(LayoutKind.Sequential)]\ninternal struct TextStyleConfiguration\n{\n    public float FontSize;\n    public FontWeights FontWeight;\n    public bool IsItalic;\n\n    public const int FONT_FAMILIES_LENGTH = 16;\n    [MarshalAs(UnmanagedType.ByValArray, SizeConst = FONT_FAMILIES_LENGTH)] public IntPtr[] FontFamilies;\n    \n    public const int FONT_FEATURES_LENGTH = 16;\n    [MarshalAs(UnmanagedType.ByValArray, SizeConst = FONT_FEATURES_LENGTH)] public FontFeature[] FontFeatures;\n    \n    public uint ForegroundColor;\n    public uint BackgroundColor;\n    \n    public uint DecorationColor;\n    public float DecorationThickness;\n    public TextDecoration DecorationType;\n    public TextDecorationMode DecorationMode;\n    public TextDecorationStyle DecorationStyle;\n    \n    public float LineHeight; // when 0, the default font metrics are used \n    public float LetterSpacing;\n    public float WordSpacing;\n    public float BaselineOffset;\n    \n    [StructLayout(LayoutKind.Sequential)]\n    public struct FontFeature\n    {\n        [MarshalAs(UnmanagedType.LPStr)] public string Name;\n        public int Value;\n    }\n    \n    public enum FontWeights\n    {\n        Invisible = 0,\n        Thin = 100,\n        ExtraLight = 200,\n        Light = 300,\n        Normal = 400,\n        Medium = 500,\n        SemiBold = 600,\n        Bold = 700,\n        ExtraBold = 800,\n        Black = 900,\n        ExtraBlack = 1000,\n    }\n    \n    [Flags]\n    public enum TextDecoration\n    {\n        NoDecoration = 0x0,\n        Underline = 0x1,\n        Overline = 0x2,\n        LineThrough = 0x4\n    }\n    \n    public enum TextDecorationMode\n    {\n        Gaps, \n        Through\n    }\n    \n    public enum TextDecorationStyle\n    {\n        Solid, \n        Double, \n        Dotted, \n        Dashed, \n        Wavy\n    }\n}\n\ninternal sealed class SkTextStyle : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    \n    public SkTextStyle(TextStyleConfiguration textStyleConfiguration)\n    {\n        Instance = API.text_style_create(textStyleConfiguration);\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    ~SkTextStyle()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.text_style_delete(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr text_style_create(TextStyleConfiguration textStyleConfiguration);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void text_style_delete(IntPtr textStyle);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/Text/SkTypeface.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia.Text;\n\ninternal sealed class SkTypeface : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n\n    public SkTypeface(IntPtr instance)\n    {\n        Instance = instance;\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    ~SkTypeface()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        API.typeface_unref(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void typeface_unref(IntPtr typeface);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/Text/SkTypefaceProvider.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia.Text;\n\ninternal sealed class SkTypefaceProvider : IDisposable\n{\n    public IntPtr Instance { get; private set; }\n    private List<SkTypeface> Typefaces { get; } = new();\n    \n    public SkTypefaceProvider()\n    {\n        Instance = API.typeface_font_provider_create();\n        SkiaAPI.EnsureNotNull(Instance);\n    }\n    \n    public void AddTypefaceFromData(SkData data, string? alias = null)\n    {\n        var typeface = SkFontManager.Global.CreateTypeface(data);\n        Typefaces.Add(typeface);\n        \n        if (alias == null)\n            API.typeface_font_provider_add_typeface(Instance, typeface.Instance);\n        else\n            API.typeface_font_provider_add_typeface_with_custom_alias(Instance, typeface.Instance, alias);\n    }\n    \n    ~SkTypefaceProvider()\n    {\n        this.WarnThatFinalizerIsReached();\n        Dispose();\n    }\n    \n    public void Dispose()\n    {\n        if (Instance == IntPtr.Zero)\n            return;\n        \n        foreach (var typeface in Typefaces)\n            typeface.Dispose();\n        \n        API.typeface_font_provider_unref(Instance);\n        Instance = IntPtr.Zero;\n        GC.SuppressFinalize(this);\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr typeface_font_provider_create();\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void typeface_font_provider_add_typeface(IntPtr typefaceProvider, IntPtr typeface);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void typeface_font_provider_add_typeface_with_custom_alias(IntPtr typefaceProvider, IntPtr typeface, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8StringMarshaller))] string alias);\n        \n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern void typeface_font_provider_unref(IntPtr typefaceProvider);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/Text/SkUnicode.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia.Text;\n\ninternal sealed class SkUnicode\n{\n    public IntPtr Instance { get; private set; }\n    public static SkUnicode Global { get; } = new();\n\n    private SkUnicode()\n    {\n        Instance = API.unicode_create();\n    }\n    \n    private static class API\n    {\n        [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]\n        public static extern IntPtr unicode_create();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF/Skia/Utf8StringMarshaller.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace QuestPDF.Skia;\n\ninternal sealed class Utf8StringMarshaller : ICustomMarshaler\n{\n    private static readonly Utf8StringMarshaller Instance = new();\n\n    public static ICustomMarshaler GetInstance(string? cookie) => Instance;\n    \n    public void CleanUpManagedData(object managedObj)\n    {\n        \n    }\n\n    public void CleanUpNativeData(IntPtr pNativeData)\n    {\n        Marshal.FreeHGlobal(pNativeData);\n    }\n\n    public int GetNativeDataSize()\n    {\n        return -1;\n    }\n\n    public IntPtr MarshalManagedToNative(object managedObject)\n    {\n        return SkText.MarshalFromManagedToNative(managedObject as string);\n    }\n\n    public object MarshalNativeToManaged(IntPtr pNativeData)\n    {\n        throw new NotImplementedException();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.Companion.TestRunner/Program.cs",
    "content": "﻿using QuestPDF;\nusing QuestPDF.Companion;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.ReportSample;\nusing QuestPDF.ReportSample.Layouts;\n\nSettings.License = LicenseType.Professional;\n\n//await RunGenericException();\n//await RunLayoutError();\nawait RunSimpleDocument();\n//await RunReportDocument();\n//await RunDocumentWithMultiplePages();\n\nTask RunGenericException()\n{\n    return Document\n        .Create(container =>\n        {\n            container.Page(page =>\n            {\n                page.Content()\n                    .PaddingVertical(1, Unit.Centimetre)\n                    .Column(x =>\n                    {\n                        x.Spacing(20);\n\n                        x.Item().Text(Placeholders.LoremIpsum());\n                        x.Item().Hyperlink(\"questpdf.com\").Image(Placeholders.Image(300, 200));\n\n                        throw new Exception(\"New exception\");\n                    });\n            });\n        })\n        .ShowInCompanionAsync();\n}\n\nTask RunLayoutError()\n{\n    return Document\n        .Create(container =>\n        {\n            container.Page(page =>\n            {\n                page.Size(PageSizes.A4);\n                page.Margin(2, Unit.Centimetre);\n                page.PageColor(Colors.White);\n                page.DefaultTextStyle(x => x.FontSize(20));\n\n                page.Content()\n                    .PaddingVertical(1, Unit.Centimetre)\n                    .Column(x =>\n                    {\n                        x.Spacing(20);\n                    \n                        x.Item().Text(Placeholders.LoremIpsum());\n                    \n                        foreach (var i in Enumerable.Range(0, 15))\n                        {\n                            x.Item().Background(Colors.Grey.Lighten3).MaxWidth(200).Container().Width(100 + i * 10).Height(50).Text($\"Item {i}\");\n                        }\n                    });\n            });\n        })\n        .ShowInCompanionAsync();\n}\n\nTask RunSimpleDocument()\n{\n    return Document\n        .Create(container =>\n        {\n            container.Page(page =>\n            {\n                page.Size(PageSizes.A4);\n                page.Margin(2, Unit.Centimetre);\n                page.PageColor(Colors.White);\n                page.DefaultTextStyle(x => x.FontSize(20));\n        \n                page.Header()\n                    .Text(\"Hello PDF!\")\n                    .SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);\n        \n                page.Content()\n                    .PaddingVertical(1, Unit.Centimetre)\n                    .Column(x =>\n                    {\n                        x.Spacing(20);\n                \n                        x.Item().Text(Placeholders.LoremIpsum());\n                        x.Item().Hyperlink(\"questpdf.com\").Image(Placeholders.Image(200, 100));\n                    });\n        \n                page.Footer()\n                    .AlignCenter()\n                    .Text(x =>\n                    {\n                        x.Span(\"Page \");\n                        x.CurrentPageNumber();\n                    });\n            });\n        })\n        .ShowInCompanionAsync();\n}\n\nTask RunReportDocument()\n{\n    ImagePlaceholder.Solid = true;\n    \n    var model = DataSource.GetReport();\n    var report = new StandardReport(model);\n    return report.ShowInCompanionAsync();\n}\n\nTask RunDocumentWithMultiplePages()\n{\n    return Document\n        .Create(document =>\n        {\n            foreach (var i in Enumerable.Range(10, 10))\n            {\n                document.Page(page =>\n                {\n                    page.Size(new PageSize(i * 20, i * 30));\n                    page.Margin(20);\n                    page.Content().Background(Placeholders.BackgroundColor());\n                });\n            }\n        })\n        .ShowInCompanionAsync();\n}\n\nTask RunMergedDocument()\n{\n    var document1 = Document\n        .Create(container =>\n        {\n            container.Page(page =>\n            {\n                page.Content()\n                    .Text(\"Page 1!\")\n                    .SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);\n            });\n        });\n    var document2 = Document\n        .Create(container =>\n        {\n            container.Page(page =>\n            {\n                page.Content()\n                    .Text(\"Page 2!\")\n                    .SemiBold().FontSize(36).FontColor(Colors.Blue.Medium);\n            });\n        });\n\n    var mergedDocument = Document.Merge(document1, document2);\n\n    return mergedDocument.ShowInCompanionAsync();\n}\n"
  },
  {
    "path": "Source/QuestPDF.Companion.TestRunner/QuestPDF.Companion.TestRunner.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <OutputType>Exe</OutputType>\n        <TargetFramework>net10.0</TargetFramework>\n        <ImplicitUsings>enable</ImplicitUsings>\n        <Nullable>enable</Nullable>\n        <SatelliteResourceLanguages>en</SatelliteResourceLanguages>\n    </PropertyGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\QuestPDF.ReportSample\\QuestPDF.ReportSample.csproj\" />\n      <ProjectReference Include=\"..\\QuestPDF\\QuestPDF.csproj\" />\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/DecorationTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class DecorationTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        QuestPDF.Settings.EnableDebugging = true;\n        \n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(600, 975);\n                    page.Margin(50);\n\n                    page.Content()\n                        .Decoration(decoration =>\n                        {\n                            decoration.Before()\n                                .Column(column =>\n                                {\n                                    column.Item()\n                                        .ShowOnce()\n                                        .Height(50)\n                                        .Width(200)\n                                        .SemanticImage(\"First page: decoration before\")\n                                        .Image(Placeholders.Image);\n                                    \n                                    column.Item()\n                                        .SkipOnce()\n                                        .Text(\"Second page: decoration before\");\n                                });\n                            \n                            decoration\n                                .Content()\n                                .PaddingVertical(25)\n                                .Column(column =>\n                                {\n                                    column.Spacing(25);\n                                    \n                                    foreach (var i in Enumerable.Range(1, 15))\n                                    {\n                                        column.Item()\n                                            .Width(200)\n                                            .Height(50)\n                                            .Background(Colors.Grey.Lighten3)\n                                            .AlignCenter()\n                                            .AlignMiddle()\n                                            .Text($\"Item {i}\");\n                                    }\n                                });\n                            \n                            decoration.After()\n                                .Column(column =>\n                                {\n                                    column.Item()\n                                        .ShowOnce()\n                                        .Height(50)\n                                        .Width(200)\n                                        .SemanticImage(\"First page: decoration after\")\n                                        .Image(Placeholders.Image);\n                                    \n                                    column.Item()\n                                        .SkipOnce()\n                                        .Text(\"Second page: decoration after\");\n                                });\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"Figure\", figure => figure.Alt(\"First page: decoration before\"));\n                \n            foreach (var i in Enumerable.Range(1, 10))\n                root.Child(\"P\");\n                \n            root.Child(\"Figure\", figure => figure.Alt(\"First page: decoration after\"));\n            \n            foreach (var i in Enumerable.Range(1, 5))\n                root.Child(\"P\");\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/DynamicTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class DynamicTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        var imageData = File.ReadAllBytes(\"Resources/photo.jpeg\");\n        \n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .PaddingVertical(30)\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n\n                            column.Item().SemanticHeader1().Text(\"Conformance Test: Lazy\");\n                            \n                            column.Item().SemanticHeader2().Text(\"Before lazy\");\n\n                            foreach (var i in Enumerable.Range(0, 10))\n                                column.Item().Dynamic(new DynamicComponent(i));\n                            \n                            column.Item().SemanticHeader2().Text(\"After lazy\");\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Lazy\"));\n            root.Child(\"H2\", h2 => h2.Alt(\"Before lazy\"));\n\n            foreach (var i in Enumerable.Range(0, 10))\n            {\n                root.Child(\"Art\", art =>\n                {\n                    art.Child(\"H3\", h3 => h3.Alt($\"Article {i}\"));\n         \n                    foreach (var j in Enumerable.Range(0, 10))\n                    {\n                        art.Child(\"P\");\n                    }\n                });\n            }\n\n            root.Child(\"H2\", h2 => h2.Alt(\"After lazy\"));\n        });\n    }\n\n    internal class DynamicComponent(int index) : IDynamicComponent\n    {\n        public DynamicComponentComposeResult Compose(DynamicContext context)\n        {\n            var result = context.CreateElement(container =>\n            {\n                container.SemanticArticle().Column(column =>\n                {\n                    column.Item().SemanticHeader3().Text($\"Article {index}\").Bold();\n\n                    foreach (var j in Enumerable.Range(0, 10))\n                    {\n                        column.Item().Text($\"{index} - {j}\");\n                    }\n                });\n            });\n\n            if (result.Size.Height > context.AvailableSize.Height)\n            {\n                return new DynamicComponentComposeResult\n                {\n                    Content = context.CreateElement(container => { }),\n                    HasMoreContent = true\n                };\n            }\n            \n            return new DynamicComponentComposeResult\n            {\n                Content = result,\n                HasMoreContent = false\n            };\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/FooterTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class FooterTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .PaddingBottom(25)\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n\n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test: Footer\")\n                                .FontSize(24)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n\n                            column.Item()\n                                .Text(\"Footer content should not be present in the semantic tree.\");\n\n                            column.Item()\n                                .SemanticDivision()\n                                .Column(column =>\n                                {\n                                    foreach (var i in Enumerable.Range(1, 12))\n                                    {\n                                        column.Item()\n                                            .Width(200)\n                                            .Height(100)\n                                            .Background(Colors.Grey.Lighten2)\n                                            .AlignCenter()\n                                            .AlignMiddle()\n                                            .Text($\"Item {i}\");\n                                    }\n                                });\n                        });\n\n                    page.Footer()\n                        .AlignCenter()\n                        .Text(text =>\n                        {\n                            text.CurrentPageNumber();\n                            text.Span(\" / \");\n                            text.TotalPages();\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Footer\"));\n            \n            root.Child(\"P\");\n\n            root.Child(\"Div\", div =>\n            {\n                foreach (var i in Enumerable.Range(1, 12))\n                    div.Child(\"P\");\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/HeaderTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class HeaderTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Header()\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n                            \n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test: Header\")\n                                .FontSize(24)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n\n                            column.Item()\n                                .ShowOnce()\n                                .Text(\"Only the first page of the Header should be present in the semantic tree.\");\n                            \n                            column.Item()\n                                .SkipOnce()\n                                .Text(\"This item should NOT be present in the semantic tree.\");\n                        });\n                    \n                    page.Content()\n                        .PaddingTop(25)\n                        .SemanticDivision()\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n                            \n                            foreach (var i in Enumerable.Range(1, 12))\n                            {\n                                column.Item()\n                                    .Width(200)\n                                    .Height(100)\n                                    .Background(Colors.Grey.Lighten2)\n                                    .AlignCenter()\n                                    .AlignMiddle()\n                                    .Text($\"Item {i}\");\n                            }\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Header\"));\n            \n            root.Child(\"P\");\n\n            root.Child(\"Div\", div =>\n            {\n                foreach (var i in Enumerable.Range(1, 12))\n                    div.Child(\"P\");\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/HyperlinkInFooterTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class HyperlinkInFooterTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .PaddingVertical(25)\n                        .Column(column =>\n                        {\n                            column.Spacing(15);\n\n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test: Hyperlink in Footer\")\n                                .FontSize(24)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n                            \n                            column.Item().Text(\"Please find the link in the footer.\");\n                            \n                            foreach (var i in Enumerable.Range(1, 25))\n                                column.Item().Width(100).Height(50).Background(Colors.Grey.Lighten3);\n                        });\n                    \n                    page.Footer()\n                        .SemanticLink(\"Link to the QuestPDF website\")\n                        .Hyperlink(\"https://www.questpdf.com\")\n                        .Text(\"https://www.questpdf.com\")\n                        .Underline()\n                        .FontColor(Colors.Blue.Darken2);\n                });\n            });\n    }\n    \n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Hyperlink in Footer\"));\n            \n            root.Child(\"P\");\n            \n            // the first occurrence of footer content should be treated as content,\n            // all subsequent occurrences should be marked as artifacts.\n            root.Child(\"Link\", link =>\n            {\n                link.Alt(\"Link to the QuestPDF website\");\n                link.Child(\"P\");\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/HyperlinkTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class HyperlinkTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(15);\n\n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test: Hyperlinks\")\n                                .FontSize(24)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n                            \n                            column.Item().Text(\"Please find the link below:\");\n                            \n                            column.Item()\n                                .SemanticLink(\"Link to the QuestPDF website\")\n                                .Hyperlink(\"https://www.questpdf.com\")\n                                .Text(\"QuestPDF website\")\n                                .Underline()\n                                .FontColor(Colors.Blue.Darken2);\n                        });\n                });\n            });\n    }\n    \n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Hyperlinks\"));\n            \n            root.Child(\"P\");\n            \n            root.Child(\"Link\", link =>\n            {\n                link.Alt(\"Link to the QuestPDF website\");\n                link.Child(\"P\");\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/IgnoreTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class IgnoreTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        var photo = File.ReadAllBytes(\"Resources/photo.jpeg\");\n        \n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .PaddingVertical(30)\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n\n                            column.Item().Text(\"This photo has semantic meaning:\");\n                            \n                            column.Item()\n                                .SemanticImage(\"A beautiful landscape\")\n                                .Image(photo);\n                            \n                            column.Item().Text(\"While this one doesn't:\");\n                            \n                            column.Item()\n                                .SemanticIgnore()\n                                .Image(photo);\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"P\");\n            root.Child(\"Figure\", figure => figure.Alt(\"A beautiful landscape\"));\n            root.Child(\"P\");\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/ImageTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class ImageTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        var imageData = File.ReadAllBytes(\"Resources/photo.jpeg\");\n        \n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .PaddingVertical(30)\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n\n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test: Images\")\n                                .FontSize(24)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n                            \n                            column.Item()\n                                .Width(300)\n                                .SemanticImage(\"Sample image description\")\n                                .Column(column =>\n                                {\n                                    column.Item().Image(imageData);\n                                    column.Item().PaddingTop(5).AlignCenter().SemanticCaption().Text(\"Sample image caption\");\n                                });\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Images\"));\n\n            root.Child(\"Figure\", figure =>\n            {\n                figure.Alt(\"Sample image description\");\n                figure.Child(\"Caption\", caption => caption.Child(\"P\"));\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/LazyTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class LazyTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        var imageData = File.ReadAllBytes(\"Resources/photo.jpeg\");\n        \n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .PaddingVertical(30)\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n\n                            column.Item().SemanticHeader1().Text(\"Conformance Test: Lazy\");\n                            \n                            column.Item().SemanticHeader2().Text(\"Before lazy\");\n\n                            foreach (var i in Enumerable.Range(0, 10))\n                            {\n                                column.Item()\n                                    .Lazy(lazy =>\n                                    {\n                                        lazy.SemanticArticle().Column(innerColumn =>\n                                        {\n                                            innerColumn.Item().SemanticHeader3().Text($\"Article {i}\").Bold();\n                                            \n                                            foreach (var j in Enumerable.Range(0, 10))\n                                            {\n                                                innerColumn.Item().Text($\"{i} - {j}\");\n                                            }\n                                        });\n                                    });\n                            }\n                            \n                            column.Item().SemanticHeader2().Text(\"After lazy\");\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Lazy\"));\n            root.Child(\"H2\", h2 => h2.Alt(\"Before lazy\"));\n\n            foreach (var i in Enumerable.Range(0, 10))\n            {\n                root.Child(\"Art\", art =>\n                {\n                    art.Child(\"H3\", h3 => h3.Alt($\"Article {i}\"));\n         \n                    foreach (var j in Enumerable.Range(0, 10))\n                    {\n                        art.Child(\"P\");\n                    }\n                });\n            }\n\n            root.Child(\"H2\", h2 => h2.Alt(\"After lazy\"));\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/LineTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class LineTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n\n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test: Line Elements\")\n                                .FontSize(24)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n\n                            column.Item()\n                                .Text(\"Line elements should be rendered but semantically treated as artifacts.\");\n\n                            column.Item()\n                                .LineHorizontal(2)\n                                .LineColor(Colors.Red.Medium);\n\n                            column.Item()\n                                .Text(Placeholders.LoremIpsum());\n\n                            column.Item()\n                                .LineHorizontal(4)\n                                .LineColor(Colors.Green.Medium)\n                                .LineDashPattern([6, 6, 12, 6]);\n    \n                            column.Item()\n                                .SemanticDivision()\n                                .Background(Colors.Grey.Lighten3).Row(row =>\n                                {\n                                    row.RelativeItem()\n                                        .PaddingVertical(25)\n                                        .AlignRight()\n                                        .Text(\"Text on the left side\");\n                                    \n                                    row.AutoItem()\n                                        .PaddingHorizontal(25)\n                                        .LineVertical(4)\n                                        .LineGradient([ Colors.Blue.Lighten2, Colors.Blue.Darken2 ]);\n                                    \n                                    row.RelativeItem()\n                                        .PaddingVertical(25)\n                                        .Text(\"Text on the right side\");\n                                });\n                        });\n                });\n            });\n    }\n    \n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Line Elements\"));\n            \n            root.Child(\"P\");\n            root.Child(\"P\");\n            root.Child(\"Div\", div =>\n            {\n                div.Child(\"P\");\n                div.Child(\"P\");\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/ListTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class ListTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .PaddingVertical(30)\n                        .SemanticSection()\n                        .Column(column =>\n                        {\n                            column.Spacing(15);\n\n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test: Lists\")\n                                .FontSize(36)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n\n                            column.Item()\n                                .SemanticList()\n                                .Column(listColumn =>\n                                {\n                                    listColumn.Spacing(10);\n\n                                    listColumn.Item()\n                                        .SemanticListItem()\n                                        .Row(row =>\n                                        {\n                                            row.ConstantItem(20).SemanticListLabel().Text(\"1.\");\n\n                                            row.RelativeItem()\n                                                .SemanticListItemBody()\n                                                .Column(bodyColumn =>\n                                                {\n                                                    bodyColumn.Spacing(8);\n\n                                                    bodyColumn.Item().Text(Placeholders.Sentence());\n\n                                                    bodyColumn.Item()\n                                                        .SemanticList()\n                                                        .Column(nestedColumn =>\n                                                        {\n                                                            nestedColumn.Spacing(10);\n\n                                                            foreach (var i in Enumerable.Range(1, 4))\n                                                            {\n                                                                nestedColumn.Item()\n                                                                    .SemanticListItem()\n                                                                    .Row(nestedRow =>\n                                                                    {\n                                                                        nestedRow.ConstantItem(10)\n                                                                            .SemanticListLabel()\n                                                                            .Text(\"-\");\n\n                                                                        nestedRow.RelativeItem()\n                                                                            .SemanticListItemBody()\n                                                                            .Text(Placeholders.Sentence());\n                                                                    });\n                                                            }\n                                                        });\n                                                });\n                                        });\n\n                                    foreach (var i in Enumerable.Range(2, 5))\n                                    {\n                                        listColumn.Item()\n                                            .SemanticListItem()\n                                            .Row(row =>\n                                            {\n                                                row.ConstantItem(20)\n                                                    .SemanticListLabel()\n                                                    .Text($\"{i}.\");\n\n                                                row.RelativeItem()\n                                                    .SemanticListItemBody()\n                                                    .Text(Placeholders.Sentence());\n                                            });\n                                    }\n                                });\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"Sect\", sect =>\n            {\n                sect.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Lists\"));\n\n                sect.Child(\"L\", list =>\n                {\n                    list.Child(\"LI\", listItem =>\n                    {\n                        listItem.Child(\"Lbl\");\n                        listItem.Child(\"LBody\", lBody =>\n                        {\n                            lBody.Child(\"P\");\n\n                            lBody.Child(\"L\", nestedList =>\n                            {\n                                foreach (var i in Enumerable.Range(1, 4))\n                                {\n                                    nestedList.Child(\"LI\", nestedItem =>\n                                    {\n                                        nestedItem.Child(\"Lbl\");\n                                        nestedItem.Child(\"LBody\", listBody => listBody.Child(\"P\"));\n                                    });\n                                }\n                            });\n                        });\n                    });\n\n                    foreach (var i in Enumerable.Range(2, 5))\n                    {\n                        list.Child(\"LI\", listItem =>\n                        {\n                            listItem.Child(\"Lbl\");\n                            listItem.Child(\"LBody\", listBody => listBody.Child(\"P\"));\n                        });\n                    }\n                });\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/MultiColumnTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class MultiColumnTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .MultiColumn(multiColumn =>\n                        {\n                            multiColumn.Spacing(75);\n                            \n                            multiColumn\n                                .Spacer()\n                                .PaddingHorizontal(25)\n                                .Background(Colors.Blue.Lighten4)\n                                .RotateLeft()\n                                .AlignMiddle()\n                                .AlignCenter()\n                                .Text(\"This text should not be a part of the semantic tree\")\n                                .FontColor(Colors.Blue.Darken4)\n                                .Bold();\n                                \n                            multiColumn\n                                .Content()\n                                .Column(column =>\n                                {\n                                    column.Spacing(25);\n                                    \n                                    foreach (var i in Enumerable.Range(1, 25))\n                                    {\n                                        column.Item()\n                                            .AlignCenter()\n                                            .Background(Colors.Grey.Lighten3)\n                                            .Padding(10)\n                                            .Text(text =>\n                                            {\n                                                text.Span($\"Chapter {i}: \").Bold();\n                                                text.Span(Placeholders.LoremIpsum());\n                                            });\n                                    }\n                                });\n                        });\n                });\n            });\n    }\n    \n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            foreach (var i in Enumerable.Range(1, 25))\n                root.Child(\"P\");\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/OrderOfSemanticItemsTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class OrderOfSemanticItemsTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        // this test checks if SemanticTag registers semantic content only in actual Skia drawing canvas\n        \n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"1 - H1\");\n                            \n                            column.Item()\n                                .SemanticHeader2()\n                                .Text(\"2 - H2\");\n                            \n                            column.Item()\n                                .SemanticHeader2()\n                                .Text(\"3 - H2\");\n                            \n                            column.Item().MultiColumn(multiColumn =>\n                            {\n                                multiColumn.Spacing(75);\n                            \n                                multiColumn.Content().Column(column =>\n                                {\n                                    column.Item()\n                                        .SemanticHeader2()\n                                        .Text(\"4 - H2\");\n                                    \n                                    column.Item()\n                                        .SemanticHeader3()\n                                        .Text(\"5 - H3\");\n                                    \n                                    column.Item()\n                                        .SemanticHeader3()\n                                        .Text(\"6 - H3\");\n                                });\n                            });\n                        });\n                });\n            });\n    }\n    \n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"1 - H1\"));\n            \n            root.Child(\"H2\", h2 => h2.Alt(\"2 - H2\"));\n            root.Child(\"H2\", h2 => h2.Alt(\"3 - H2\"));\n            \n            root.Child(\"H2\", h2 => h2.Alt(\"4 - H2\"));\n            root.Child(\"H3\", h3 => h3.Alt(\"5 - H3\"));\n            root.Child(\"H3\", h3 => h3.Alt(\"6 - H3\"));\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/QuestPDF.ConformanceTests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <ImplicitUsings>enable</ImplicitUsings>\n        <Nullable>enable</Nullable>\n        <SatelliteResourceLanguages>en</SatelliteResourceLanguages>\n        <IsPackable>false</IsPackable>\n        <IsTestProject>true</IsTestProject>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.13.0\" />\n        <PackageReference Include=\"NUnit\" Version=\"4.4.0\" />\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"4.11.2\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"6.1.0\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <Using Include=\"NUnit.Framework\"/>\n    </ItemGroup>\n\n    <ItemGroup>\n        <ProjectReference Include=\"..\\QuestPDF\\QuestPDF.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <None Include=\"Resources\\**\\*.*\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n        </None>\n    </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/Resources/zugferd-factur-x.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<rsm:CrossIndustryInvoice xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">\n    <rsm:ExchangedDocumentContext>\n        <ram:GuidelineSpecifiedDocumentContextParameter>\n            <ram:ID>urn:cen.eu:en16931:2017</ram:ID>\n        </ram:GuidelineSpecifiedDocumentContextParameter>\n    </rsm:ExchangedDocumentContext>\n    <rsm:ExchangedDocument>\n        <ram:ID>RE-20201121/508</ram:ID>\n        <ram:TypeCode>380</ram:TypeCode>\n        <ram:IssueDateTime>\n            <udt:DateTimeString format=\"102\">20201121</udt:DateTimeString>\n        </ram:IssueDateTime>\n    </rsm:ExchangedDocument>\n    <rsm:SupplyChainTradeTransaction>\n        <ram:IncludedSupplyChainTradeLineItem>\n            <ram:AssociatedDocumentLineDocument>\n                <ram:LineID>1</ram:LineID>\n            </ram:AssociatedDocumentLineDocument>\n            <ram:SpecifiedTradeProduct>\n                <ram:Name>Design (hours)</ram:Name>\n                <ram:Description>Of a sample invoice</ram:Description>\n            </ram:SpecifiedTradeProduct>\n            <ram:SpecifiedLineTradeAgreement>\n                <ram:GrossPriceProductTradePrice>\n                    <ram:ChargeAmount>160.0000</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"HUR\">1.0000</ram:BasisQuantity>\n                </ram:GrossPriceProductTradePrice>\n                <ram:NetPriceProductTradePrice>\n                    <ram:ChargeAmount>160.0000</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"HUR\">1.0000</ram:BasisQuantity>\n                </ram:NetPriceProductTradePrice>\n            </ram:SpecifiedLineTradeAgreement>\n            <ram:SpecifiedLineTradeDelivery>\n                <ram:BilledQuantity unitCode=\"HUR\">1.0000</ram:BilledQuantity>\n            </ram:SpecifiedLineTradeDelivery>\n            <ram:SpecifiedLineTradeSettlement>\n                <ram:ApplicableTradeTax>\n                    <ram:TypeCode>VAT</ram:TypeCode>\n                    <ram:CategoryCode>S</ram:CategoryCode>\n                    <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>\n                </ram:ApplicableTradeTax>\n                <ram:SpecifiedTradeSettlementLineMonetarySummation>\n                    <ram:LineTotalAmount>160.00</ram:LineTotalAmount>\n                </ram:SpecifiedTradeSettlementLineMonetarySummation>\n            </ram:SpecifiedLineTradeSettlement>\n        </ram:IncludedSupplyChainTradeLineItem>\n        <ram:IncludedSupplyChainTradeLineItem>\n            <ram:AssociatedDocumentLineDocument>\n                <ram:LineID>2</ram:LineID>\n            </ram:AssociatedDocumentLineDocument>\n            <ram:SpecifiedTradeProduct>\n                <ram:Name>Ballons</ram:Name>\n                <ram:Description>various colors, ~2000ml</ram:Description>\n            </ram:SpecifiedTradeProduct>\n            <ram:SpecifiedLineTradeAgreement>\n                <ram:GrossPriceProductTradePrice>\n                    <ram:ChargeAmount>0.7900</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"H87\">1.0000</ram:BasisQuantity>\n                </ram:GrossPriceProductTradePrice>\n                <ram:NetPriceProductTradePrice>\n                    <ram:ChargeAmount>0.7900</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"H87\">1.0000</ram:BasisQuantity>\n                </ram:NetPriceProductTradePrice>\n            </ram:SpecifiedLineTradeAgreement>\n            <ram:SpecifiedLineTradeDelivery>\n                <ram:BilledQuantity unitCode=\"H87\">400.0000</ram:BilledQuantity>\n            </ram:SpecifiedLineTradeDelivery>\n            <ram:SpecifiedLineTradeSettlement>\n                <ram:ApplicableTradeTax>\n                    <ram:TypeCode>VAT</ram:TypeCode>\n                    <ram:CategoryCode>S</ram:CategoryCode>\n                    <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>\n                </ram:ApplicableTradeTax>\n                <ram:SpecifiedTradeSettlementLineMonetarySummation>\n                    <ram:LineTotalAmount>316.00</ram:LineTotalAmount>\n                </ram:SpecifiedTradeSettlementLineMonetarySummation>\n            </ram:SpecifiedLineTradeSettlement>\n        </ram:IncludedSupplyChainTradeLineItem>\n        <ram:IncludedSupplyChainTradeLineItem>\n            <ram:AssociatedDocumentLineDocument>\n                <ram:LineID>3</ram:LineID>\n            </ram:AssociatedDocumentLineDocument>\n            <ram:SpecifiedTradeProduct>\n                <ram:Name>Hot air „heiße Luft“ (litres)</ram:Name>\n                <ram:Description/>\n            </ram:SpecifiedTradeProduct>\n            <ram:SpecifiedLineTradeAgreement>\n                <ram:GrossPriceProductTradePrice>\n                    <ram:ChargeAmount>0.0250</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"LTR\">1.0000</ram:BasisQuantity>\n                </ram:GrossPriceProductTradePrice>\n                <ram:NetPriceProductTradePrice>\n                    <ram:ChargeAmount>0.0250</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"LTR\">1.0000</ram:BasisQuantity>\n                </ram:NetPriceProductTradePrice>\n            </ram:SpecifiedLineTradeAgreement>\n            <ram:SpecifiedLineTradeDelivery>\n                <ram:BilledQuantity unitCode=\"LTR\">800.0000</ram:BilledQuantity>\n            </ram:SpecifiedLineTradeDelivery>\n            <ram:SpecifiedLineTradeSettlement>\n                <ram:ApplicableTradeTax>\n                    <ram:TypeCode>VAT</ram:TypeCode>\n                    <ram:CategoryCode>S</ram:CategoryCode>\n                    <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>\n                </ram:ApplicableTradeTax>\n                <ram:SpecifiedTradeSettlementLineMonetarySummation>\n                    <ram:LineTotalAmount>20.00</ram:LineTotalAmount>\n                </ram:SpecifiedTradeSettlementLineMonetarySummation>\n            </ram:SpecifiedLineTradeSettlement>\n        </ram:IncludedSupplyChainTradeLineItem>\n        <ram:ApplicableHeaderTradeAgreement>\n            <ram:BuyerReference>AB321</ram:BuyerReference>\n            <ram:SellerTradeParty>\n                <ram:Name>Bei Spiel GmbH</ram:Name>\n                <ram:PostalTradeAddress>\n                    <ram:PostcodeCode>12345</ram:PostcodeCode>\n                    <ram:LineOne>Ecke 12</ram:LineOne>\n                    <ram:CityName>Stadthausen</ram:CityName>\n                    <ram:CountryID>DE</ram:CountryID>\n                </ram:PostalTradeAddress>\n                <ram:SpecifiedTaxRegistration>\n                    <ram:ID schemeID=\"VA\">DE136695976</ram:ID>\n                </ram:SpecifiedTaxRegistration>\n            </ram:SellerTradeParty>\n            <ram:BuyerTradeParty>\n                <ram:ID>2</ram:ID>\n                <ram:Name>Theodor Est</ram:Name>\n                <ram:PostalTradeAddress>\n                    <ram:PostcodeCode>88802</ram:PostcodeCode>\n                    <ram:LineOne>Bahnstr. 42</ram:LineOne>\n                    <ram:CityName>Spielkreis</ram:CityName>\n                    <ram:CountryID>DE</ram:CountryID>\n                </ram:PostalTradeAddress>\n            </ram:BuyerTradeParty>\n        </ram:ApplicableHeaderTradeAgreement>\n        <ram:ApplicableHeaderTradeDelivery>\n            <ram:ActualDeliverySupplyChainEvent>\n                <ram:OccurrenceDateTime>\n                    <udt:DateTimeString format=\"102\">20201110</udt:DateTimeString>\n                </ram:OccurrenceDateTime>\n            </ram:ActualDeliverySupplyChainEvent>\n        </ram:ApplicableHeaderTradeDelivery>\n        <ram:ApplicableHeaderTradeSettlement>\n            <ram:PaymentReference>RE-20201121/508</ram:PaymentReference>\n            <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>\n            <ram:SpecifiedTradeSettlementPaymentMeans>\n                <ram:TypeCode>42</ram:TypeCode>\n                <ram:Information>Bank transfer</ram:Information>\n                <ram:PayeePartyCreditorFinancialAccount>\n                    <ram:IBANID>DE88200800000970375700</ram:IBANID>\n                    <ram:AccountName>Max Mustermann</ram:AccountName>\n                </ram:PayeePartyCreditorFinancialAccount>\n                <ram:PayeeSpecifiedCreditorFinancialInstitution>\n                    <ram:BICID>COBADEFFXXX</ram:BICID>\n                </ram:PayeeSpecifiedCreditorFinancialInstitution>\n            </ram:SpecifiedTradeSettlementPaymentMeans>\n            <ram:ApplicableTradeTax>\n                <ram:CalculatedAmount>11.20</ram:CalculatedAmount>\n                <ram:TypeCode>VAT</ram:TypeCode>\n                <ram:BasisAmount>160.00</ram:BasisAmount>\n                <ram:CategoryCode>S</ram:CategoryCode>\n                <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>\n            </ram:ApplicableTradeTax>\n            <ram:ApplicableTradeTax>\n                <ram:CalculatedAmount>63.84</ram:CalculatedAmount>\n                <ram:TypeCode>VAT</ram:TypeCode>\n                <ram:BasisAmount>336.00</ram:BasisAmount>\n                <ram:CategoryCode>S</ram:CategoryCode>\n                <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>\n            </ram:ApplicableTradeTax>\n            <ram:SpecifiedTradePaymentTerms>\n                <ram:Description>Zahlbar ohne Abzug bis 12.12.2020</ram:Description>\n                <ram:DueDateDateTime>\n                    <udt:DateTimeString format=\"102\">20201212</udt:DateTimeString>\n                </ram:DueDateDateTime>\n            </ram:SpecifiedTradePaymentTerms>\n            <ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n                <ram:LineTotalAmount>496.00</ram:LineTotalAmount>\n                <ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>\n                <ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>\n                <ram:TaxBasisTotalAmount>496.00</ram:TaxBasisTotalAmount>\n                <ram:TaxTotalAmount currencyID=\"EUR\">75.04</ram:TaxTotalAmount>\n                <ram:GrandTotalAmount>571.04</ram:GrandTotalAmount>\n                <ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>\n                <ram:DuePayableAmount>571.04</ram:DuePayableAmount>\n            </ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n        </ram:ApplicableHeaderTradeSettlement>\n    </rsm:SupplyChainTradeTransaction>\n</rsm:CrossIndustryInvoice>\n"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/Resources/zugferd-xmp-metadata.xml",
    "content": "<rdf:Description xmlns:fx=\"urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#\" rdf:about=\"\">\n    <fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>\n    <fx:DocumentType>INVOICE</fx:DocumentType>\n    <fx:DocumentFileName>factur-x.xml</fx:DocumentFileName>\n    <fx:Version>1.0</fx:Version>\n</rdf:Description>\n<rdf:Description xmlns:pdfaExtension=\"http://www.aiim.org/pdfa/ns/extension/\"\n                 xmlns:pdfaProperty=\"http://www.aiim.org/pdfa/ns/property#\"\n                 xmlns:pdfaSchema=\"http://www.aiim.org/pdfa/ns/schema#\"\n                 rdf:about=\"\">\n<pdfaExtension:schemas>\n    <rdf:Bag>\n        <rdf:li rdf:parseType=\"Resource\">\n            <pdfaSchema:schema>ZUGFeRD PDFA Extension Schema</pdfaSchema:schema>\n            <pdfaSchema:namespaceURI>urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#</pdfaSchema:namespaceURI>\n            <pdfaSchema:prefix>fx</pdfaSchema:prefix>\n            <pdfaSchema:property>\n                <rdf:Seq>\n                    <rdf:li rdf:parseType=\"Resource\">\n                        <pdfaProperty:name>DocumentFileName</pdfaProperty:name>\n                        <pdfaProperty:valueType>Text</pdfaProperty:valueType>\n                        <pdfaProperty:category>external</pdfaProperty:category>\n                        <pdfaProperty:description>name of the embedded XML invoice file</pdfaProperty:description>\n                    </rdf:li>\n                    <rdf:li rdf:parseType=\"Resource\">\n                        <pdfaProperty:name>DocumentType</pdfaProperty:name>\n                        <pdfaProperty:valueType>Text</pdfaProperty:valueType>\n                        <pdfaProperty:category>external</pdfaProperty:category>\n                        <pdfaProperty:description>INVOICE</pdfaProperty:description>\n                    </rdf:li>\n                    <rdf:li rdf:parseType=\"Resource\">\n                        <pdfaProperty:name>Version</pdfaProperty:name>\n                        <pdfaProperty:valueType>Text</pdfaProperty:valueType>\n                        <pdfaProperty:category>external</pdfaProperty:category>\n                        <pdfaProperty:description>The actual version of the ZUGFeRD XML schema</pdfaProperty:description>\n                    </rdf:li>\n                    <rdf:li rdf:parseType=\"Resource\">\n                        <pdfaProperty:name>ConformanceLevel</pdfaProperty:name>\n                        <pdfaProperty:valueType>Text</pdfaProperty:valueType>\n                        <pdfaProperty:category>external</pdfaProperty:category>\n                        <pdfaProperty:description>The selected ZUGFeRD profile completeness</pdfaProperty:description>\n                    </rdf:li>\n                </rdf:Seq>\n            </pdfaSchema:property>\n        </rdf:li>\n    </rdf:Bag>\n</pdfaExtension:schemas>\n</rdf:Description>"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/StyledBoxTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class StyledBoxTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .PaddingVertical(30)\n                        .SemanticSection()\n                        .Column(column =>\n                        {\n                            column.Spacing(30);\n\n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test: Styled Boxes\")\n                                .FontSize(36)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n\n                            column.Item()\n                                .Background(Colors.Blue.Lighten4)\n                                .Padding(20)\n                                .Text(\"Background only\")\n                                .FontSize(16);\n\n                            column.Item()\n                                .Border(2, Colors.Blue.Darken2)\n                                .Padding(20)\n                                .Text(\"Border only\")\n                                .FontSize(16);\n\n                            column.Item()\n                                .Background(Colors.White)\n                                .Shadow(new BoxShadowStyle\n                                {\n                                    OffsetX = 5,\n                                    OffsetY = 5,\n                                    Blur = 10,\n                                    Spread = 5,\n                                    Color = Colors.Grey.Medium\n                                })\n                                .Padding(20)\n                                .Text(\"Simple shadow\")\n                                .FontSize(16);\n\n                            column.Item()\n                                .Border(1, Colors.Purple.Lighten4)\n                                .Background(Colors.Purple.Lighten5)\n                                .CornerRadius(15)\n                                .Padding(20)\n                                .Text(\"Rounded corners\")\n                                .FontSize(16);\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"Sect\", sect =>\n            {\n                sect.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: Styled Boxes\"));\n\n                foreach (var i in Enumerable.Range(1, 4))\n                    sect.Child(\"P\");\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/SvgTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class SvgTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n\n                            column.Item()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test: SVG\")\n                                .FontSize(24)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n\n                            column.Item()\n                                .Text(\"SVG content should be rendered correctly and possible to be annotated as semantic image. Image taken from: undraw.co\");\n\n                            column.Item()\n                                .SemanticImage(\"Sample SVG image description\")\n                                .Svg(\"Resources/image.svg\");\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test: SVG\"));\n            root.Child(\"P\");\n            root.Child(\"Figure\", figure => figure.Alt(\"Sample SVG image description\"));\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/Table/TableWithFooterTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.Table;\n\ninternal class TableWithFooterTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Shrink()\n                        .Border(1)\n                        .BorderColor(Colors.Grey.Darken1)\n                        .SemanticTable()\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                            });\n\n                            foreach (var i in Enumerable.Range(1, 30))\n                            {\n                                table.Cell().Element(CellStyle).Text($\"{i}/1\");\n                                table.Cell().Element(CellStyle).Text($\"{i}/2\");\n                                table.Cell().Element(CellStyle).Text($\"{i}/3\");\n                            }\n                            \n                            table.Footer(footer =>\n                            {\n                                footer.Cell().Element(FooterCellStyle).Text(\"F11\");\n                                footer.Cell().Element(FooterCellStyle).Text(\"F12\");\n                                footer.Cell().Element(FooterCellStyle).Text(\"F13\");\n                                \n                                footer.Cell().Element(FooterCellStyle).Text(\"F21\");\n                                footer.Cell().Element(FooterCellStyle).Text(\"F22\");\n                                footer.Cell().Element(FooterCellStyle).Text(\"F23\");\n                            });\n                            \n                            IContainer CellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Padding(8);\n                            \n                            IContainer FooterCellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Background(Colors.Grey.Lighten3)\n                                    .Padding(8);\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"Table\", table =>\n            {\n                table.Child(\"TBody\", tbody =>\n                {\n                    foreach (var i in Enumerable.Range(1, 30))\n                    {\n                        tbody.Child(\"TR\", row =>\n                        {\n                            row.Child(\"TD\", td => td.Child(\"P\"));\n                            row.Child(\"TD\", td => td.Child(\"P\"));\n                            row.Child(\"TD\", td => td.Child(\"P\"));\n                        });\n                    }\n                });\n                \n                table.Child(\"TFoot\", tfoot =>\n                {\n                    tfoot.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n                        \n                    tfoot.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n                });\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/Table/TableWithHeaderCellsSpanningMultipleColumnsTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.Table;\n\ninternal class TableWithHeaderCellsSpanningMultipleColumnsTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Shrink()\n                        .Border(1)\n                        .BorderColor(Colors.Grey.Darken1)\n                        .SemanticTable()\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                            });\n                            \n                            table.Header(header =>\n                            {\n                                header.Cell().RowSpan(2).Element(HeaderCellStyle).Text(\"Paper Type\");\n                                header.Cell().ColumnSpan(2).Element(HeaderCellStyle).Text(\"Width\");\n                                header.Cell().ColumnSpan(2).Element(HeaderCellStyle).Text(\"Height\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Inches\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Points\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Inches\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Points\");\n                            });\n\n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"A3\");\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                                \n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"A4\");\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            \n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"A5\");\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Decimal());\n                            \n                            IContainer HeaderCellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Background(Colors.Grey.Lighten3)\n                                    .Padding(8)\n                                    .AlignMiddle()\n                                    .DefaultTextStyle(x => x.Bold());\n\n                            IContainer CellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Padding(8);\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"Table\", table =>\n            {\n                table.Child(\"THead\", thead =>\n                {\n                    thead.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(5)\n                            .Attribute(\"Table\", \"RowSpan\", 2)\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TH\", th => th\n                            .Id(6)\n                            .Attribute(\"Table\", \"ColSpan\", 2)\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TH\", th => th\n                            .Id(7)\n                            .Attribute(\"Table\", \"ColSpan\", 2)\n                            .Child(\"P\"));\n                    });\n                    \n                    thead.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(9)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TH\", th => th\n                            .Id(10)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TH\", th => th\n                            .Id(11)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TH\", th => th\n                            .Id(12)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7 })\n                            .Child(\"P\"));\n                    });\n                });\n\n                table.Child(\"TBody\", tbody =>\n                {\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(22)\n                            .Attribute(\"Table\", \"Headers\", new[] { 5 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", th => th\n                            .Id(23)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 9, 22 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(24)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 10, 22 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(25)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 11, 22 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(26)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 12, 22 })\n                            .Child(\"P\"));\n                    });\n                    \n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(28)\n                            .Attribute(\"Table\", \"Headers\", new[] { 5 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", th => th\n                            .Id(29)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 9, 28 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(30)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 10, 28 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(31)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 11, 28 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(32)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 12, 28 })\n                            .Child(\"P\"));\n                    });\n                    \n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(34)\n                            .Attribute(\"Table\", \"Headers\", new[] { 5 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", th => th\n                            .Id(35)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 9, 34 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(36)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 10, 34 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(37)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 11, 34 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(38)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 12, 34 })\n                            .Child(\"P\"));\n                    });\n                });\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/Table/TableWithHeaderCellsSpanningMultipleRowsTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.Table;\n\ninternal class TableWithHeaderCellsSpanningMultipleRowsTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Shrink()\n                        .Border(1)\n                        .BorderColor(Colors.Grey.Darken1)\n                        .SemanticTable()\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                            });\n                            \n                            table.Header(header =>\n                            {\n                                header.Cell().Element(HeaderCellStyle).Text(\"Year\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Quarter\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Outcome\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Income\");\n                            });\n\n                            table.Cell().RowSpan(4).AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"2024\");\n                                \n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Q1\");\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                                \n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Q2\");\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                                \n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Q3\");\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                                \n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Q4\");\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n\n                            table.Cell().RowSpan(2).AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"2025\");\n\n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Q1\");\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                                \n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Q2\");\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                            table.Cell().Element(CellStyle).Text(Placeholders.Price());\n                            \n                            IContainer HeaderCellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Background(Colors.Grey.Lighten3)\n                                    .Padding(8)\n                                    .AlignMiddle()\n                                    .DefaultTextStyle(x => x.Bold());\n\n                            IContainer CellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Padding(8);\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"Table\", table =>\n            {\n                table.Child(\"THead\", thead =>\n                {\n                    thead.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th.Id(5).Child(\"P\"));\n                        row.Child(\"TH\", th => th.Id(6).Child(\"P\"));\n                        row.Child(\"TH\", th => th.Id(7).Child(\"P\"));\n                        row.Child(\"TH\", th => th.Id(8).Child(\"P\"));\n                    });\n                });\n                \n                table.Child(\"TBody\", tbody =>\n                {\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(15)\n                            .Attribute(\"Table\", \"RowSpan\", 4)\n                            .Attribute(\"Table\", \"Headers\", new[] { 5 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TH\", th => th\n                            .Id(16)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 15 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(17)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 15, 16 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(18)\n                            .Attribute(\"Table\", \"Headers\", new[] { 8, 15, 16 })\n                            .Child(\"P\"));\n                    });\n                    \n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(20)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 15 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(21)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 15, 20 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(22)\n                            .Attribute(\"Table\", \"Headers\", new[] { 8, 15, 20 })\n                            .Child(\"P\"));\n                    });\n                    \n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(24)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 15 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(25)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 15, 24 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(26)\n                            .Attribute(\"Table\", \"Headers\", new[] { 8, 15, 24 })\n                            .Child(\"P\"));\n                    });\n                    \n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(28)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 15 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(29)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 15, 28 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(30)\n                            .Attribute(\"Table\", \"Headers\", new[] { 8, 15, 28 })\n                            .Child(\"P\"));\n                    });\n\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(32)\n                            .Attribute(\"Table\", \"RowSpan\", 2)\n                            .Attribute(\"Table\", \"Headers\", new[] { 5 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TH\", th => th\n                            .Id(33)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 32 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(34)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 32, 33 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(35)\n                            .Attribute(\"Table\", \"Headers\", new[] { 8, 32, 33 })\n                            .Child(\"P\"));\n                    });\n                    \n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th\n                            .Id(37)\n                            .Attribute(\"Table\", \"Headers\", new[] { 6, 32 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(38)\n                            .Attribute(\"Table\", \"Headers\", new[] { 7, 32, 37 })\n                            .Child(\"P\"));\n                        \n                        row.Child(\"TD\", td => td\n                            .Id(39)\n                            .Attribute(\"Table\", \"Headers\", new[] { 8, 32, 37 })\n                            .Child(\"P\"));\n                    });\n                });\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/Table/TableWithHorizontalHeadersTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.Table;\n\ninternal class TableWithHorizontalHeadersTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Shrink()\n                        .Border(1)\n                        .BorderColor(Colors.Grey.Darken1)\n                        .SemanticTable()                        \n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                            });\n\n                            // Row 1: Name\n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Name\");\n                            table.Cell().Element(CellStyle).Text(\"John Smith\");\n                            table.Cell().Element(CellStyle).Text(\"Jane Doe\");\n\n                            // Row 2: Position\n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Position\");\n                            table.Cell().Element(CellStyle).Text(\"Senior Developer\");\n                            table.Cell().Element(CellStyle).Text(\"UX Designer\");\n\n                            // Row 3: Department\n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Department\");\n                            table.Cell().Element(CellStyle).Text(\"Engineering\");\n                            table.Cell().Element(CellStyle).Text(\"Design\");\n\n                            // Row 4: Experience\n                            table.Cell().AsSemanticHorizontalHeader().Element(HeaderCellStyle).Text(\"Experience\");\n                            table.Cell().Element(CellStyle).Text(\"5 years\");\n                            table.Cell().Element(CellStyle).Text(\"3 years\");\n\n                            IContainer HeaderCellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Background(Colors.Grey.Lighten3)\n                                    .Padding(8)\n                                    .AlignMiddle()\n                                    .DefaultTextStyle(x => x.Bold());\n\n                            IContainer CellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Padding(8);\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"Table\", table =>\n            {\n                table.Child(\"TBody\", tbody =>\n                {\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th.Attribute(\"Table\", \"Scope\", \"Row\").Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th.Attribute(\"Table\", \"Scope\", \"Row\").Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th.Attribute(\"Table\", \"Scope\", \"Row\").Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th.Attribute(\"Table\", \"Scope\", \"Row\").Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n                });\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/Table/TableWithVerticalHeadersTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.Table;\n\ninternal class TableWithVerticalHeadersTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    { \n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Shrink()\n                        .Border(1)\n                        .BorderColor(Colors.Grey.Darken1)\n                        .SemanticTable()\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                            });\n                            \n                            table.Header(header =>\n                            {\n                                header.Cell().Element(HeaderCellStyle).Text(\"Name\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Position\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Department\");\n                                header.Cell().Element(HeaderCellStyle).Text(\"Experience\");\n                            });\n\n                            // Row 1:\n                            table.Cell().Element(CellStyle).Text(\"John Smith\");\n                            table.Cell().Element(CellStyle).Text(\"Senior Developer\");\n                            table.Cell().Element(CellStyle).Text(\"Engineering\");\n                            table.Cell().Element(CellStyle).Text(\"5 years\");\n                            \n                            // Row 2:\n                            table.Cell().Element(CellStyle).Text(\"Jane Doe\");\n                            table.Cell().Element(CellStyle).Text(\"UX Designer\");\n                            table.Cell().Element(CellStyle).Text(\"Design\");\n                            table.Cell().Element(CellStyle).Text(\"3 years\");\n                            IContainer HeaderCellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Background(Colors.Grey.Lighten3)\n                                    .Padding(8)\n                                    .AlignMiddle()\n                                    .DefaultTextStyle(x => x.Bold());\n\n                            IContainer CellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Padding(8);\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"Table\", table =>\n            {\n                table.Child(\"THead\", thead =>\n                {\n                    thead.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TH\", th => th.Attribute(\"Table\", \"Scope\", \"Column\").Child(\"P\"));\n                        row.Child(\"TH\", th => th.Attribute(\"Table\", \"Scope\", \"Column\").Child(\"P\"));\n                        row.Child(\"TH\", th => th.Attribute(\"Table\", \"Scope\", \"Column\").Child(\"P\"));\n                        row.Child(\"TH\", th => th.Attribute(\"Table\", \"Scope\", \"Column\").Child(\"P\"));\n                    });\n                });\n                \n                table.Child(\"TBody\", tbody =>\n                {\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n                });\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/Table/TableWithoutHeadersTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.Table;\n\ninternal class TableWithoutHeadersTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Border(1)\n                        .BorderColor(Colors.Grey.Darken1)\n                        .SemanticTable()\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                                columns.RelativeColumn();\n                            });\n\n                            // Row 1\n                            table.Cell().Element(CellStyle).Text(\"11\");\n                            table.Cell().Element(CellStyle).Text(\"12\");\n                            table.Cell().Element(CellStyle).Text(\"13\");\n\n                            // Row 2\n                            table.Cell().Element(CellStyle).Text(\"21\");\n                            table.Cell().Element(CellStyle).Text(\"22\");\n                            table.Cell().Element(CellStyle).Text(\"23\");\n\n                            // Row 3\n                            table.Cell().Element(CellStyle).Text(\"31\");\n                            table.Cell().Element(CellStyle).Text(\"32\");\n                            table.Cell().Element(CellStyle).Text(\"33\");\n\n                            // Row 4\n                            table.Cell().Element(CellStyle).Text(\"41\");\n                            table.Cell().Element(CellStyle).Text(\"42\");\n                            table.Cell().Element(CellStyle).Text(\"43\");\n                            \n                            IContainer CellStyle(IContainer container) =>\n                                container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten2)\n                                    .Padding(8);\n                        });\n                });\n            });\n    }\n\n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"Table\", table =>\n            {\n                table.Child(\"TBody\", tbody =>\n                {\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TD\", th => th.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TD\", th => th.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TD\", th => th.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n\n                    tbody.Child(\"TR\", row =>\n                    {\n                        row.Child(\"TD\", th => th.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                        row.Child(\"TD\", td => td.Child(\"P\"));\n                    });\n                });\n            });\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/TableOfContentsTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class TableOfContentsTests : ConformanceTestBase\n{\n    protected override Document GetDocumentUnderTest()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .PaddingVertical(30)\n                        .Column(column =>\n                        {\n                            column.Item()\n                                .ExtendVertical()\n                                .AlignMiddle()\n                                .SemanticHeader1()\n                                .Text(\"Conformance Test:\\nTable of Contents\")\n                                .FontSize(36)\n                                .Bold()\n                                .FontColor(Colors.Blue.Darken2);\n\n                            column.Item().PageBreak();\n\n                            column.Item().Element(GenerateTableOfContentsSection);\n\n                            column.Item().PageBreak();\n\n                            column.Item().Element(GeneratePlaceholderContentSection);\n                        });\n                });\n            });\n        \n        static void GenerateTableOfContentsSection(IContainer container)\n        {\n            container\n                .SemanticSection()\n                .Column(column =>\n                {\n                    column.Spacing(15);\n                    \n                    column\n                        .Item()\n                        .Text(\"Table of Contents\")\n                        .Bold()\n                        .FontSize(20)\n                        .FontColor(Colors.Blue.Medium);\n                    \n                    column.Item()\n                        .SemanticTableOfContents()\n                        .Column(column =>\n                        {\n                            column.Spacing(5);\n                            \n                            foreach (var i in Enumerable.Range(1, 10))\n                            {\n                                column.Item()\n                                    .SemanticTableOfContentsItem()\n                                    .SemanticLink($\"Link to section {i}\")\n                                    .SectionLink($\"section-{i}\")\n                                    .Row(row =>\n                                    {\n                                        row.ConstantItem(25).Text($\"{i}.\");\n                                        row.AutoItem().Text(Placeholders.Label());\n                                        row.RelativeItem().PaddingHorizontal(2).TranslateY(11).LineHorizontal(1).LineDashPattern([1, 3]);\n                                        row.AutoItem().Text(text => text.BeginPageNumberOfSection($\"section-{i}\"));\n                                    });\n                            }\n                        });\n                });\n        }\n        \n        static void GeneratePlaceholderContentSection(IContainer container)\n        {\n            container\n                .Column(column =>\n                {\n                    foreach (var i in Enumerable.Range(1, 10))\n                    {\n                        column.Item()\n                            .SemanticSection()\n                            .Section($\"section-{i}\")\n                            .Column(column =>\n                            {\n                                column.Spacing(15);\n                                \n                                column.Item()\n                                    .SemanticHeader2()\n                                    .Text($\"Section {i}\")\n                                    .Bold()\n                                    .FontSize(20)\n                                    .FontColor(Colors.Blue.Medium);\n                                \n                                column.Item().Text(Placeholders.Paragraph());\n                                \n                                foreach (var j in Enumerable.Range(1, i))\n                                {\n                                    column.Item()\n                                        .SemanticIgnore()\n                                        .Width(200)\n                                        .Height(150)\n                                        .CornerRadius(10)\n                                        .Background(Placeholders.BackgroundColor());\n                                }\n                            });\n                        \n                        if (i < 10)\n                            column.Item().PageBreak();\n                    }\n                });\n        }\n    }\n    \n    protected override SemanticTreeNode? GetExpectedSemanticTree()\n    {\n        return ExpectedSemanticTree.DocumentRoot(root =>\n        {\n            root.Child(\"H1\", h1 => h1.Alt(\"Conformance Test:\\nTable of Contents\"));\n\n            // Table of Contents Section\n            root.Child(\"Sect\", sect =>\n            {\n                sect.Child(\"P\");\n\n                sect.Child(\"TOC\", toc =>\n                {\n                    foreach (var i in Enumerable.Range(1, 10))\n                    {\n                        toc.Child(\"TOCI\", toci =>\n                        {\n                            toci.Child(\"Link\", link =>\n                            {\n                                link.Alt($\"Link to section {i}\");\n                                link.Child(\"P\"); // Number\n                                link.Child(\"P\"); // Label\n                                link.Child(\"P\"); // Page number\n                            });\n                        });\n                    }\n                });\n            });\n\n            // Content Sections\n            foreach (var i in Enumerable.Range(1, 10))\n            {\n                root.Child(\"Sect\", sect =>\n                {\n                    sect.Child(\"H2\", h2 => h2.Alt($\"Section {i}\"));\n                    sect.Child(\"P\");\n                });\n            }\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/TestEngine/ConformanceTestBase.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.TestEngine;\n\n[TestFixture]\n[Parallelizable(ParallelScope.All)]\ninternal abstract class ConformanceTestBase\n{\n    public static readonly IEnumerable<PDFA_Conformance> PDFA_ConformanceLevels = Enum.GetValues<PDFA_Conformance>().Skip(1);\n    public static readonly IEnumerable<PDFUA_Conformance> PDFUA_ConformanceLevels = Enum.GetValues<PDFUA_Conformance>().Skip(1);\n    \n    [Test]\n    [Explicit(\"Manual debugging only (override to enable)\")]\n    public void GenerateAndShow()\n    {\n        GetDocumentUnderTest()\n            .WithMetadata(GetMetadata())\n            .WithSettings(new DocumentSettings\n            {\n                PDFA_Conformance = PDFA_Conformance.PDFA_3A,\n                PDFUA_Conformance = PDFUA_Conformance.PDFUA_1\n            })\n            .GeneratePdfAndShow();\n    }\n    \n    [Test, TestCaseSource(nameof(PDFA_ConformanceLevels))]\n    public void Test_PDFA(PDFA_Conformance conformance)\n    {\n        GetDocumentUnderTest()\n            .WithMetadata(GetMetadata())\n            .WithSettings(new DocumentSettings\n            {\n                PDFA_Conformance = conformance\n            })\n            .TestConformanceWithVeraPdf();\n    }\n    \n    [Test, TestCaseSource(nameof(PDFUA_ConformanceLevels))]\n    public void Test_PDFUA(PDFUA_Conformance conformance)\n    {\n        GetDocumentUnderTest()\n            .WithMetadata(GetMetadata())\n            .WithSettings(new DocumentSettings\n            {\n                PDFUA_Conformance = conformance\n            })\n            .TestConformanceWithVeraPdf();\n    }\n    \n    [Test]\n    public void TestSemanticMeaning()\n    {\n        var expectedSemanticTree = GetExpectedSemanticTree();\n            \n        GetDocumentUnderTest()\n            .WithSettings(new DocumentSettings\n            {\n                PDFUA_Conformance = PDFUA_Conformance.PDFUA_1\n            })\n            .TestSemanticTree(expectedSemanticTree);\n    }\n\n    private DocumentMetadata GetMetadata()\n    {\n        return new DocumentMetadata\n        {\n            Language = \"en-US\",\n            Title = \"Conformance Test\",\n            Subject = this.GetType().Name.Replace(\"Tests\", string.Empty).PrettifyName()\n        };\n    }\n\n    protected abstract Document GetDocumentUnderTest();\n    \n    protected abstract SemanticTreeNode? GetExpectedSemanticTree();\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/TestEngine/MustangConformanceTestRunner.cs",
    "content": "using System.Diagnostics;\nusing System.Text;\nusing System.Xml.Linq;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.TestEngine;\n\npublic static class MustangConformanceTestRunner\n{\n    public class ValidationResult\n    {\n        public bool IsDocumentValid => !FailedRules.Any();\n        public ICollection<string> FailedRules { get; set; } = [];\n        \n        public string GetErrorMessage()\n        {\n            var errorMessage = new StringBuilder();\n\n            foreach (var failedRule in FailedRules)\n            {\n                errorMessage.AppendLine($\"🟥\\tError\");\n                errorMessage.AppendLine($\"\\t{failedRule}\");\n                errorMessage.AppendLine();\n            }\n\n            return errorMessage.ToString();\n        }\n    }\n\n    public static void TestConformance(string filePath)\n    {\n        var result = RunMustang(filePath);\n\n        if (!result.IsDocumentValid)\n        {\n            Console.WriteLine(result.GetErrorMessage());\n            Assert.Fail();\n        }\n    }\n\n    private static ValidationResult RunMustang(string pdfFilePath)\n    {\n        if (!File.Exists(pdfFilePath))\n            throw new FileNotFoundException($\"PDF file not found: {pdfFilePath}\");\n\n        var mustangExecutablePath = Environment.GetEnvironmentVariable(\"MUSTANG_EXECUTABLE_PATH\");\n        \n        if (string.IsNullOrEmpty(mustangExecutablePath))\n            throw new Exception(\"The location path of the Mustang executable is not set. Set the MUSTANG_EXECUTABLE_PATH environment variable to the path of the Mustang executable.\");\n        \n        var arguments = $\"-jar {mustangExecutablePath} --action validate --source {pdfFilePath}\";\n\n        var process = new Process\n        {\n            StartInfo = new ProcessStartInfo\n            {\n                FileName = \"java\",\n                Arguments = arguments,\n                RedirectStandardOutput = true,\n                RedirectStandardError = true,\n                UseShellExecute = false,\n                CreateNoWindow = true\n            }\n        };\n\n        process.Start();\n        var output = process.StandardOutput.ReadToEnd();\n        process.WaitForExit();\n\n        return new ValidationResult()\n        {\n            FailedRules = XDocument\n                .Parse(output)\n                .Descendants(\"error\")\n                .Select(x => x.Value)\n                .ToList()\n        };\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/TestEngine/SemanticAwareDrawingCanvas.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.ConformanceTests.TestEngine;\n\ninternal class SemanticAwareDocumentCanvas : IDocumentCanvas\n{\n    internal SemanticTreeNode? SemanticTree { get; private set; }\n    private SemanticAwareDrawingCanvas DrawingCanvas { get; } = new();\n    \n    public void SetSemanticTree(SemanticTreeNode? semanticTree)\n    {\n        SemanticTree = semanticTree;\n    }\n\n    public void BeginDocument()\n    {\n        \n    }\n\n    public void EndDocument()\n    {\n        \n    }\n\n    public void BeginPage(Size size)\n    {\n        \n    }\n\n    public void EndPage()\n    {\n        \n    }\n\n    public IDrawingCanvas GetDrawingCanvas()\n    {\n        return DrawingCanvas;\n    }\n}\n\ninternal class SemanticAwareDrawingCanvas : IDrawingCanvas\n{\n    private int CurrentSemanticNodeId { get; set; }\n    \n    public DocumentPageSnapshot GetSnapshot()\n    {\n        return new DocumentPageSnapshot();\n    }\n\n    public void DrawSnapshot(DocumentPageSnapshot snapshot)\n    {\n        \n    }\n\n    public void Save()\n    {\n        \n    }\n\n    public void Restore()\n    {\n        \n    }\n\n    public void SetZIndex(int index)\n    {\n        \n    }\n\n    public int GetZIndex()\n    {\n        return 0;\n    }\n\n    public SkCanvasMatrix GetCurrentMatrix()\n    {\n        return SkCanvasMatrix.Identity;\n    }\n\n    public void SetMatrix(SkCanvasMatrix matrix)\n    {\n        \n    }\n\n    public void Translate(Position vector)\n    {\n        \n    }\n\n    public void Scale(float scaleX, float scaleY)\n    {\n        \n    }\n\n    public void Rotate(float angle)\n    {\n        \n    }\n\n    public void DrawLine(Position start, Position end, SkPaint paint)\n    {\n        if (CurrentSemanticNodeId != SkSemanticNodeSpecialId.LayoutArtifact)\n            Assert.Fail(\"Detected a line drawing operation outside of layout artifact\");\n    }\n\n    public void DrawRectangle(Position vector, Size size, SkPaint paint)\n    {\n        if (CurrentSemanticNodeId is not (SkSemanticNodeSpecialId.BackgroundArtifact or SkSemanticNodeSpecialId.LayoutArtifact))\n            Assert.Fail(\"Detected a rectangle drawing operation outside of layout artifact\");\n    }\n\n    public void DrawComplexBorder(SkRoundedRect innerRect, SkRoundedRect outerRect, SkPaint paint)\n    {\n        if (CurrentSemanticNodeId != SkSemanticNodeSpecialId.LayoutArtifact)\n            Assert.Fail(\"Detected a complex-border drawing operation outside of layout artifact\");\n    }\n\n    public void DrawShadow(SkRoundedRect shadowRect, SkBoxShadow shadow)\n    {\n        if (CurrentSemanticNodeId != SkSemanticNodeSpecialId.BackgroundArtifact)\n            Assert.Fail(\"Detected a shadow drawing operation outside of background artifact\");\n    }\n\n    public void DrawParagraph(SkParagraph paragraph, int lineFrom, int lineTo)\n    {\n        \n    }\n\n    public void DrawImage(SkImage image, Size size)\n    {\n        \n    }\n\n    public void DrawPicture(SkPicture picture)\n    {\n        \n    }\n\n    public void DrawSvgPath(string path, Color color)\n    {\n        \n    }\n\n    public void DrawSvg(SkSvgImage svgImage, Size size)\n    {\n        \n    }\n\n    public void DrawOverflowArea(SkRect area)\n    {\n        \n    }\n\n    public void ClipOverflowArea(SkRect availableSpace, SkRect requiredSpace)\n    {\n        \n    }\n\n    public void ClipRectangle(SkRect clipArea)\n    {\n        \n    }\n\n    public void ClipRoundedRectangle(SkRoundedRect clipArea)\n    {\n        \n    }\n\n    public void DrawHyperlink(Size size, string url, string? description)\n    {\n        \n    }\n\n    public void DrawSectionLink(Size size, string sectionName, string? description)\n    {\n        \n    }\n\n    public void DrawSection(string sectionName)\n    {\n        \n    }\n    \n    public int GetSemanticNodeId()\n    {\n        return CurrentSemanticNodeId;\n    }\n\n    public void SetSemanticNodeId(int nodeId)\n    {\n        CurrentSemanticNodeId = nodeId;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/TestEngine/SemanticTreeTestRunner.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.TestEngine;\n\ninternal static class SemanticTreeTestRunner\n{\n    public static void TestSemanticTree(this IDocument document, SemanticTreeNode? semanticTreeRootNode)\n    {\n        Settings.EnableCaching = false;\n        Settings.EnableDebugging = false;\n\n        var canvas = new SemanticAwareDocumentCanvas();\n        var settings = new DocumentSettings { PDFA_Conformance = PDFA_Conformance.PDFA_3A };\n        DocumentGenerator.RenderDocument(canvas, document, settings);\n\n        CompareSemanticTrees(canvas.SemanticTree, semanticTreeRootNode);\n    }\n\n    private static void CompareSemanticTrees(SemanticTreeNode? actualRoot, SemanticTreeNode? expectedRoot)\n    {\n        if (expectedRoot == null && actualRoot == null)\n            return;\n\n        if (expectedRoot == null)\n        {\n            Assert.Fail($\"Expected null but got node of type '{actualRoot?.Type}'\");\n            return;\n        }\n\n        if (actualRoot == null)\n        {\n            Assert.Fail($\"Expected node of type '{expectedRoot.Type}' but got null\");\n            return;\n        }\n        \n        var currentPath = new Stack<string>();\n        \n        try\n        {\n            Compare(actualRoot, expectedRoot);\n        }\n        catch\n        {\n            var pathText = string.Join(\" -> \", currentPath.Reverse());\n            Console.WriteLine(\"Problem location\");\n            Console.WriteLine(pathText);\n\n            throw;\n        }        \n\n        void Compare(SemanticTreeNode actual, SemanticTreeNode expected)\n        {\n            if (!currentPath.Any())\n                currentPath.Push(actual.Type);\n            \n            if (expected.NodeId != 0)\n                Assert.That(actual.NodeId, Is.EqualTo(expected.NodeId), \"NodeId mismatch\");\n            \n            Assert.That(actual.Type, Is.EqualTo(expected.Type), \"Type mismatch\");\n            Assert.That(actual.Alt, Is.EqualTo(expected.Alt), \"Alt mismatch\");\n            Assert.That(actual.Lang, Is.EqualTo(expected.Lang), \"Lang mismatch\");\n\n            CompareAttributes();\n            CompareChildren();\n\n            void CompareChildren()\n            {\n                Assert.That(actual.Children.Count, Is.EqualTo(expected.Children.Count), \"Children count mismatch\");\n                \n                var hasMultipleChildren = actual.Children.Count > 1;\n            \n                foreach (var (actualChild, expectedChild) in actual.Children.Zip(expected.Children))\n                {\n                    var prefix = hasMultipleChildren ? $\"{actual.Children.IndexOf(actualChild)}:\" : \"\";\n                    currentPath.Push(prefix + actualChild.Type);\n                \n                    Compare(actualChild, expectedChild);\n                \n                    currentPath.Pop();\n                }\n            }\n            \n            void CompareAttributes()\n            {\n                Assert.That(actual.Attributes.Count, Is.EqualTo(expected.Attributes.Count), \"Attribute count mismatch\");\n\n                var actualList = actual.Attributes.OrderBy(a => a.Owner).ThenBy(a => a.Name);\n                var expectedList = expected.Attributes.OrderBy(a => a.Owner).ThenBy(a => a.Name);\n\n                foreach (var (actualAttribute, expectedAttribute) in actualList.Zip(expectedList))\n                {\n                    Assert.That(actualAttribute.Owner, Is.EqualTo(expectedAttribute.Owner), \"Attribute owner mismatch\");\n                    Assert.That(actualAttribute.Name, Is.EqualTo(expectedAttribute.Name), \"Attribute name mismatch\");\n                    Assert.That(actualAttribute.Value, Is.EqualTo(expectedAttribute.Value), $\"Attribute value mismatch for '{expectedAttribute.Owner}:{expectedAttribute.Name}\");\n                }\n            }   \n        }\n    }\n}\n\ninternal static class ExpectedSemanticTree\n{\n    public static SemanticTreeNode DocumentRoot(Action<SemanticTreeNode> configuration)\n    {\n        var root = new SemanticTreeNode\n        {\n            Type = \"Document\"\n        };\n        \n        configuration(root);\n        return root;\n    }\n\n    public static void Child(this SemanticTreeNode parent, string type, Action<SemanticTreeNode>? configuration = null)\n    {\n        var child = new SemanticTreeNode\n        {\n            Type = type\n        };\n\n        configuration?.Invoke(child);\n        parent.Children.Add(child);\n    }\n    \n    public static SemanticTreeNode Id(this SemanticTreeNode node, int id)\n    {\n        node.NodeId = id;\n        return node;\n    }\n    \n    public static SemanticTreeNode Attribute(this SemanticTreeNode node, string owner, string name, object value)\n    {\n        var attribute = new SemanticTreeNode.Attribute\n        {\n            Owner = owner,\n            Name = name,\n            Value = value\n        };\n        \n        node.Attributes.Add(attribute);\n        return node;\n    }\n    \n    public static SemanticTreeNode Alt(this SemanticTreeNode node, string alt)\n    {\n        node.Alt = alt;\n        return node;\n    }\n    \n    public static SemanticTreeNode Lang(this SemanticTreeNode node, string lang)\n    {\n        node.Lang = lang;\n        return node;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/TestEngine/VeraPdfConformanceTestRunner.cs",
    "content": "using System.Diagnostics;\nusing System.Text;\nusing System.Text.Json;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests.TestEngine;\n\npublic static class VeraPdfConformanceTestRunner\n{\n    public class ValidationResult\n    {\n        public bool IsDocumentValid => !FailedRules.Any();\n        public ICollection<FailedRule> FailedRules { get; set; } = [];\n    \n        public class FailedRule\n        {\n            public string Profile { get; set; }\n            public string Specification { get; set; }\n            public string Clause { get; set; }\n            public string Description { get; set; }\n            public string ErrorMessage { get; set; }\n            public string Context { get; set; }\n        }\n\n        public string GetErrorMessage()\n        {\n            var errorMessage = new StringBuilder();\n            \n            foreach (var failedRule in FailedRules)\n            {\n                errorMessage.AppendLine($\"🟥\\t{failedRule.Profile}\");\n                errorMessage.AppendLine($\"\\t{failedRule.Specification}\");\n                errorMessage.AppendLine($\"\\t{failedRule.Clause}\");\n                errorMessage.AppendLine($\"\\t{failedRule.Description}\");\n                errorMessage.AppendLine();\n                errorMessage.AppendLine($\"\\t{failedRule.ErrorMessage}\");\n                errorMessage.AppendLine();\n                errorMessage.AppendLine($\"\\t{failedRule.Context}\");\n                errorMessage.AppendLine();\n            }\n\n            return errorMessage.ToString();\n        }\n    }\n    \n    public static void TestConformanceWithVeraPdf(this IDocument document)\n    {\n        var filePath = Path.Combine(Path.GetTempPath(), $\"{Guid.NewGuid()}.pdf\");\n        document.GeneratePdf(filePath);\n        \n        var result = RunVeraPDF(filePath);\n\n        if (!result.IsDocumentValid)\n        {\n            Console.WriteLine(result.GetErrorMessage());\n            Assert.Fail();\n        }\n        \n        File.Delete(filePath);\n    }\n    \n    public static void TestConformance(string filePath)\n    {\n        var result = RunVeraPDF(filePath);\n\n        if (!result.IsDocumentValid)\n        {\n            Console.WriteLine(result.GetErrorMessage());\n            Assert.Fail();\n        }\n    }\n    \n    private static ValidationResult RunVeraPDF(string pdfFilePath)\n    {\n        if (!File.Exists(pdfFilePath))\n            throw new FileNotFoundException($\"PDF file not found: {pdfFilePath}\");\n        \n        var arguments = $\"--format json \\\"{pdfFilePath}\\\"\";\n        var executablePath = Environment.GetEnvironmentVariable(\"VERAPDF_EXECUTABLE_PATH\");\n        \n        if (string.IsNullOrEmpty(executablePath))\n            throw new Exception(\"The location path of the VeraPDF executable is not set. Set the VERAPDF_EXECUTABLE_PATH environment variable to the path of the VeraPDF executable.\");\n\n        var process = new Process\n        {\n            StartInfo = new ProcessStartInfo\n            {\n                FileName = executablePath,\n                Arguments = arguments,\n                RedirectStandardOutput = true,\n                RedirectStandardError = true,\n                UseShellExecute = false,\n                CreateNoWindow = true\n            }\n        };\n\n        process.Start();\n        var output = process.StandardOutput.ReadToEnd();\n        process.WaitForExit();\n\n        var result = new ValidationResult();\n\n        var profileResults = JsonDocument\n            .Parse(output)\n            .RootElement\n            .GetProperty(\"report\")\n            .GetProperty(\"jobs\")[0]\n            .GetProperty(\"validationResult\");\n        \n        foreach (var profileValidationResult in profileResults.EnumerateArray())\n        {\n            var failedRules = profileValidationResult\n                .GetProperty(\"details\")\n                .GetProperty(\"ruleSummaries\");\n\n            foreach (var failedRule in failedRules.EnumerateArray())\n            {\n                foreach (var check in failedRule.GetProperty(\"checks\").EnumerateArray())\n                {\n                    result.FailedRules.Add(new ValidationResult.FailedRule\n                    {\n                        Profile = profileValidationResult.GetProperty(\"profileName\").GetString().Split(\" \").First(),\n                        Specification = failedRule.GetProperty(\"specification\").GetString(),\n                        Clause = failedRule.GetProperty(\"clause\").GetString(),\n                        Description = failedRule.GetProperty(\"description\").GetString(),\n                        ErrorMessage = check.GetProperty(\"errorMessage\").GetString(),\n                        Context = check.GetProperty(\"context\").GetString()\n                    });\n                }\n            }\n        }\n\n        return result;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/TestsSetup.cs",
    "content": "﻿using System.Runtime.CompilerServices;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests\n{\n    public class TestsSetup\n    {\n        [ModuleInitializer]\n        public static void Setup()\n        {\n            QuestPDF.Settings.License = LicenseType.Community;\n            QuestPDF.Settings.UseEnvironmentFonts = false;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ConformanceTests/ZugferdTests.cs",
    "content": "using QuestPDF.ConformanceTests.TestEngine;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ConformanceTests;\n\ninternal class ZugferdTests\n{\n    [Test]\n    public void ZugferdValidation_WithMustang()\n    {\n        var guid = Guid.NewGuid();\n        var invoicePath = Path.Combine(Path.GetTempPath(), $\"{guid}.pdf\");\n\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(60);\n\n                    page.Content()\n                        .Text(\"Conformance Test: ZUGFeRD\")\n                        .FontSize(24)\n                        .FontColor(Colors.Blue.Darken2)\n                        .Bold();\n                });\n            })\n            .WithMetadata(new DocumentMetadata\n            {\n                Title = \"Conformance Test: ZUGFeRD\",\n                Author = \"SampleCompany\",\n                Subject = \"ZUGFeRD Test Document\",\n                Language = \"en-US\"\n            })\n            .WithSettings(new DocumentSettings\n            {\n                PDFA_Conformance = PDFA_Conformance.PDFA_3B\n            })\n            .GeneratePdf(invoicePath);\n        \n        VeraPdfConformanceTestRunner.TestConformance(invoicePath);\n        \n        var zugferdInvoicePath = Path.Combine(Path.GetTempPath(), $\"zugferd-{guid}.pdf\");\n\n        var facturPath = Path.Combine(\"Resources\", \"zugferd-factur-x.xml\");\n        var metadataPath = Path.Combine(\"Resources\", \"zugferd-xmp-metadata.xml\");\n\n        DocumentOperation\n            .LoadFile(invoicePath)\n            .AddAttachment(new DocumentOperation.DocumentAttachment\n            {\n                Key = \"factur-zugferd\",\n                FilePath = facturPath,\n                AttachmentName = \"factur-x.xml\",\n                MimeType = \"text/xml\",\n                Description = \"Factur-X Invoice\",\n                Relationship = DocumentOperation.DocumentAttachmentRelationship.Source,\n                CreationDate = DateTime.UtcNow,\n                ModificationDate = DateTime.UtcNow\n            })\n            .ExtendMetadata(File.ReadAllText(metadataPath))\n            .Save(zugferdInvoicePath);\n        \n        VeraPdfConformanceTestRunner.TestConformance(zugferdInvoicePath);\n        MustangConformanceTestRunner.TestConformance(zugferdInvoicePath); \n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/AccessibilityExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class AccessibilityExamples\n{\n    [Test]\n    public void MinimalExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.Margin(30);\n\n                    page.Header()\n                        .PaddingBottom(15)\n                        .SemanticHeader1()\n                        .Text(\"Accessibility Test Document\")\n                        .FontColor(Colors.Blue.Darken3)\n                        .FontSize(24)\n                        .Bold();\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(20);\n                            \n                            column.Item()\n                                .SemanticSection()\n                                .Column(column =>\n                                {\n                                    column.Item()\n                                        .PaddingBottom(10)\n                                        .SemanticHeader2()\n                                        .Text(\"Section with text content\")\n                                        .FontColor(Colors.Blue.Darken1)\n                                        .FontSize(16);\n                                    \n                                    column.Item()\n                                        .Text(Placeholders.Paragraphs())\n                                        .FontSize(12)\n                                        .ParagraphSpacing(8);\n                                });\n                            \n                            column.Item()\n                                .PreventPageBreak()\n                                .SemanticSection()\n                                .Column(column =>\n                                {\n                                    column.Item()\n                                        .PaddingBottom(10)\n                                        .SemanticHeader2()\n                                        .Text(\"Section with image\")\n                                        .FontColor(Colors.Blue.Darken1)\n                                        .FontSize(16);\n                                    \n                                    column.Item()\n                                        .Width(250)\n                                        .SemanticImage(\"Image showing a laptop\")\n                                        .Image(\"Resources/product.jpg\");\n                                });\n                        });\n                });\n            })\n            .WithMetadata(new DocumentMetadata\n            {\n                Language = \"en-US\",\n                Title = \"Accessibility Test\",\n                Subject = \"This document shows how easy it is to create accessible PDF documents with QuestPDF\"\n            })\n            .WithSettings(new DocumentSettings\n            {\n                PDFA_Conformance = PDFA_Conformance.PDFA_3A,\n                PDFUA_Conformance = PDFUA_Conformance.PDFUA_1\n            })\n            .GeneratePdf(\"accessibility-minimal-example.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/AlignmentExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class AlignmentExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(300)\n                        .Height(300)\n                        .AlignBottom()\n                        .AlignCenter()\n                        .Background(Colors.Grey.Lighten2)\n                        .Padding(10)\n                        .Text(\"Lorem ipsum\");\n                });\n            })\n            .GenerateImages(x => \"alignment.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/AspectRatioExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class AspectRatioExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(300)\n                        .Height(300)\n                        .AspectRatio(3f/4f, AspectRatioOption.FitArea)\n                        .Background(Colors.Grey.Lighten2)\n                        .AlignCenter()\n                        .AlignMiddle()\n                        .Text(\"3:4 Content Area\");\n                });\n            })\n            .GenerateImages(x => \"aspect-ratio.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/BackgroundExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class BackgroundExamples\n{\n    [Test]\n    public void SolidColor()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.PageColor(Colors.White);\n                    page.Margin(25);\n\n                    var colors = new[]\n                    {\n                        Colors.LightBlue.Darken4,\n                        Colors.LightBlue.Darken3,\n                        Colors.LightBlue.Darken2,\n                        Colors.LightBlue.Darken1,\n    \n                        Colors.LightBlue.Medium,\n    \n                        Colors.LightBlue.Lighten1,\n                        Colors.LightBlue.Lighten2,\n                        Colors.LightBlue.Lighten3,\n                        Colors.LightBlue.Lighten4,\n                        Colors.LightBlue.Lighten5,\n    \n                        Colors.LightBlue.Accent1,\n                        Colors.LightBlue.Accent2,\n                        Colors.LightBlue.Accent3,\n                        Colors.LightBlue.Accent4,\n                    };\n                    \n                    page.Content()\n                        .Height(150)\n                        .Width(420)\n                        .Row(row =>\n                        {\n                            foreach (var color in colors)\n                                row.RelativeItem().Background(color);\n                        });\n                });\n            })\n            .GenerateImages(x => \"background-solid.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Gradient() \n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(350, 0));\n                    page.MaxSize(new PageSize(350, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.PageColor(Colors.White);\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n \n                            column.Item()\n                                .BackgroundLinearGradient(0, [Colors.Red.Lighten2, Colors.Blue.Lighten2])\n                                .AspectRatio(2);\n\n                            column.Item()\n                                .BackgroundLinearGradient(45, [Colors.Green.Lighten2, Colors.LightGreen.Lighten2, Colors.Yellow.Lighten2])\n                                .AspectRatio(2);\n                            \n                            column.Item()\n                                .BackgroundLinearGradient(90, [Colors.Yellow.Lighten2, Colors.Amber.Lighten2, Colors.Orange.Lighten2])\n                                .AspectRatio(2);\n                        });\n                });\n            })\n            .GenerateImages(x => \"background-gradient.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void RoundedCorners() \n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {   \n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.PageColor(Colors.White);\n                    page.Margin(25);\n\n                    page.Content()\n                        .Shrink()\n                        .Background(Colors.Grey.Lighten2)\n                        .CornerRadius(25)\n                        .Padding(25)\n                        .Text(\"Content with rounded corners\");\n                });\n            })\n            .GenerateImages(x => \"background-rounded-corners.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/BarcodeExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing ZXing;\nusing ZXing.OneD;\nusing ZXing.QrCode;\nusing ZXing.Rendering;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class BarcodeExamples\n{\n    [Test]\n    public void BarcodeExample()\n    {\n        Settings.UseEnvironmentFonts = false;\n\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(550, 0));\n                    page.MaxSize(new PageSize(550, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(16));\n                    \n                    page.Content()\n                        .Background(Colors.Grey.Lighten3)\n                        .Padding(25)\n                        .Row(row =>\n                        {\n                            var productId = Random.Shared.NextInt64() % 10_000_000;\n                            \n                            row.Spacing(20);\n\n                            row.RelativeItem().Text(text =>\n                            {\n                                text.ParagraphSpacing(10);\n                                \n                                text.Span(\"Product ID: \").Bold();\n                                text.Line(productId.ToString(\"D7\"));\n                                \n                                text.Span(\"Name: \").Bold();\n                                text.Line(Placeholders.Label());\n           \n                                text.Span(\"Description: \").Bold();\n                                text.Span(Placeholders.Sentence());\n                            });\n\n                            row.AutoItem()\n                                .Background(Colors.White)\n                                .AlignCenter()\n                                .AlignMiddle()\n                                .Width(200)\n                                .Height(75)\n                                .Svg(size =>\n                                {\n                                    var content = productId.ToString(\"D7\");\n                                    \n                                    var writer = new EAN8Writer();\n                                    var eanCode = writer.encode(content, BarcodeFormat.EAN_8, (int)size.Width, (int)size.Height);\n                                    var renderer = new SvgRenderer { FontName = \"Lato\", FontSize = 16 };\n                                    return renderer.Render(eanCode, BarcodeFormat.EAN_8, content).Content;\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"barcode.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void QRCodeExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(550, 0));\n                    page.MaxSize(new PageSize(550, 1000)); \n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    \n                    page.Content()\n                        .Background(Colors.Grey.Lighten3)\n                        .Padding(25)\n                        .Row(row =>\n                        {\n                            const string url = \"https://en.wikipedia.org/wiki/Algorithm\";\n                            \n                            row.Spacing(20);\n\n                            row.RelativeItem()\n                                .AlignMiddle()\n                                .Text(text =>\n                                {\n                                    text.Justify();\n                                    text.Span(\"In mathematics and computer science, \");\n                                    text.Span(\"an algorithm\").Bold().BackgroundColor(Colors.White);\n                                    text.Span(\" is a finite sequence of mathematically rigorous instructions, typically used to solve a class of specific problems or to perform a computation. \");\n                                    text.Hyperlink(\"Learn more\", url).Underline().FontColor(Colors.Blue.Darken2);\n                                });\n                            \n                            row.ConstantItem(5, Unit.Centimetre)\n                                .AspectRatio(1)\n                                .Background(Colors.White)\n                                .Svg(size =>\n                                {\n                                    var writer = new QRCodeWriter();\n                                    var qrCode = writer.encode(url, BarcodeFormat.QR_CODE, (int)size.Width, (int)size.Height);\n                                    var renderer = new SvgRenderer { FontName = \"Lato\" };\n                                    return renderer.Render(qrCode, BarcodeFormat.EAN_13, null).Content;\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"qrcode.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/BorderExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class BorderExamples\n{\n    [Test]\n    public void SimpleExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(450);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n                    \n                    page.Content()\n                        .Border(3, Colors.Blue.Darken4)\n                        .Background(Colors.Blue.Lighten5)\n                        .Padding(25) \n                        .Text(text =>\n                        {\n                            text.DefaultTextStyle(x => x.FontColor(Colors.Blue.Darken4).FontSize(16));\n                            text.Span(\"TIP: \").Bold();\n                            text.Span(\"You can use borders to create visual separation between elements in your document. Borders can be applied to any element, including text, images, and containers.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"border-simple.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Multiple()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n                    \n                    page.Content()\n                        .Shrink()\n                        \n                        .BorderVertical(5)\n                        .BorderColor(Colors.Green.Darken2)\n                        .BorderAlignmentInside()\n\n                        .Container()\n\n                        .BorderHorizontal( 10)\n                        .BorderColor(Colors.Blue.Lighten1)\n                        .BorderAlignmentInside()\n                        \n                        .Background(Colors.Grey.Lighten2)\n                        .PaddingVertical(25)\n                        .PaddingHorizontal(50)\n                        .Text(\"Content\");\n                });\n            })\n            .GenerateImages(x => \"border-multiple.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void ConsistentThickness()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(550, 0));\n                    page.MaxSize(new PageSize(550, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(25);\n                            \n                            row.RelativeItem()\n                                .Border(1, Colors.Black)\n                                .Padding(10)\n                                .AlignCenter()\n                                .Text(\"Thin\");\n                            \n                            row.RelativeItem()\n                                .Border(3, Colors.Black)\n                                .Padding(10)\n                                .AlignCenter()\n                                .Text(\"Medium\");\n                            \n                            row.RelativeItem()\n                                .Border(9, Colors.Black)\n                                .Padding(10)\n                                .AlignCenter()\n                                .Text(\"Bold\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"border-thickness-consistent.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n\n    [Test]\n    public void VariousThickness()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .BorderLeft(4)\n                        .BorderTop(6)\n                        .BorderRight(8) \n                        .BorderBottom(10)\n                        .Padding(25)\n                        .Text(\"Sample text\");\n                });\n            })\n            .GenerateImages(x => \"border-thickness-various.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Alignment()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(725, 0));\n                    page.MaxSize(new PageSize(725, 1000)); \n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(25);\n                            \n                            row.RelativeItem()\n                                .Background(Colors.Grey.Lighten1)\n                                .Padding(25)\n                                .Text(\"No Border\");\n                            \n                            row.RelativeItem()\n                                .Border(10, Colors.Grey.Darken2)\n                                .BorderAlignmentInside()\n                                .Padding(25)\n                                .Text(\"Border Inside\");\n                            \n                            row.RelativeItem()\n                                .Border(10, Colors.Grey.Darken2)\n                                .BorderAlignmentMiddle()\n                                .Padding(25)\n                                .Text(\"Border Middle\");\n                            \n                            row.RelativeItem()\n                                .Border(10, Colors.Grey.Darken2)\n                                .BorderAlignmentOutside()\n                                .Padding(25)\n                                .Text(\"Border Outside\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"border-alignment.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void RoundedCorners1()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .CornerRadius(10)\n                        .Border(1, Colors.Black)\n                        .Background(Colors.Grey.Lighten2)\n                        .Padding(25)\n                        .Text(\"Border with rounded corners\"); \n                });\n            })\n            .GenerateImages(x => \"border-rounded-corners-1.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void RoundedCorners2()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .CornerRadius(10)\n                        .BorderLeft(10)\n                        .BorderAlignmentInside()\n                        .BorderColor(Colors.Green.Darken2)\n                        .Background(Colors.Green.Lighten4)\n                        .Padding(25)\n                        .PaddingLeft(10)\n                        .DefaultTextStyle(x => x.FontColor(Colors.Green.Darken4))\n                        .Column(column =>\n                        {\n                            column.Item().Text(\"Completed\").Bold();\n                            column.Item().Height(5);\n                            column.Item().Text(\"The invoice has been paid in full.\").FontSize(16);\n                        });\n                });\n            })\n            .GenerateImages(x => \"border-rounded-corners-2.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void SolidColor()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(450);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n                    \n                    page.Content()\n                        .Row(row =>\n                        {\n                            var colors = new[]\n                            {\n                                Colors.Red.Medium,\n                                Colors.Green.Medium,\n                                Colors.Blue.Medium\n                            };\n                            \n                            row.Spacing(25);\n                            \n                            foreach (var color in colors)\n                            {\n                                row.RelativeItem()\n                                    .Border(5)\n                                    .BorderColor(color)\n                                    .Padding(15)\n                                    .Text(color)\n                                    .FontColor(color);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"border-color-solid.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Gradient()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n                            \n                            column.Item()\n                                .Border(5)\n                                .BorderLinearGradient(0, [Colors.Red.Darken1, Colors.Blue.Darken1])\n                                .BorderAlignmentInside()\n                                .Padding(25)\n                                .Text(\"Horizontal gradient\");\n                            \n                            column.Item()\n                                .Border(10)\n                                .BorderLinearGradient(45, [Colors.Green.Darken1, Colors.LightGreen.Darken1, Colors.Yellow.Darken1])\n                                .BorderAlignmentInside()\n                                .Padding(25)\n                                .Text(\"Diagonal gradient\");\n                            \n                            column.Item()\n                                .Border(10)\n                                .BorderLinearGradient(90, [Colors.Yellow.Darken1, Colors.Amber.Darken1, Colors.Orange.Darken1])\n                                .CornerRadius(20)\n                                .Padding(25)\n                                .Text(\"Vertical gradient\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"border-color-gradient.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ChartExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing ScottPlot;\nusing Colors = QuestPDF.Helpers.Colors;\nusing ImageFormat = QuestPDF.Infrastructure.ImageFormat;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ChartExamples\n{\n    [Test]\n    public void PieChartExample()\n    {\n        Settings.UseEnvironmentFonts = true;\n\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(350, 0));\n                    page.MaxSize(new PageSize(350, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n                            \n                            column.Item().Text(\"US energy consumption [%]\\nby source in 2021\").AlignCenter().Bold();\n                            \n                            column.Item()\n                                .AspectRatio(1)\n                                .Svg(size =>\n                                {\n                                    using ScottPlot.Plot plot = new();\n                                    \n                                    var slices = new PieSlice[]\n                                    {\n                                        new() { Value = 8, FillColor = new ScottPlot.Color(Colors.Yellow.Medium.Hex), Label = \"Nuclear\" },\n                                        new() { Value = 12, FillColor = new ScottPlot.Color(Colors.Green.Medium.Hex), Label = \"Renewable\" },\n                                        new() { Value = 32, FillColor = new ScottPlot.Color(Colors.Blue.Medium.Hex), Label = \"Natural gas\" },\n                                        new() { Value = 11, FillColor = new ScottPlot.Color(Colors.Grey.Medium.Hex), Label = \"Coal\" },\n                                        new() { Value = 36, FillColor = new ScottPlot.Color(Colors.Brown.Medium.Hex), Label = \"Petroleum\" }\n                                    };\n\n                                    var pie = plot.Add.Pie(slices);\n                                    pie.DonutFraction = 0.5;\n                                    pie.SliceLabelDistance = 1.5;\n                                    pie.LineColor = ScottPlot.Colors.White;\n                                    pie.LineWidth = 3;\n                                    \n                                    foreach (var pieSlice in pie.Slices)\n                                    {\n                                        pieSlice.LabelStyle.FontName = \"Lato\";\n                                        pieSlice.LabelStyle.FontSize = 16;\n                                    }\n\n                                    plot.Axes.Frameless();\n                                    plot.HideGrid();\n\n                                    return plot.GetSvgXml((int)size.Width, (int)size.Height);\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"chart-pie.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void BarExample()\n    {\n        Settings.UseEnvironmentFonts = true;\n\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(650, 0));\n                    page.MaxSize(new PageSize(650, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n                            \n                            column.Item().Text(\"Popularity of C# versions in 2023\").AlignCenter().Bold();\n                            \n                            column.Item()\n                                .AspectRatio(2)\n                                .Svg(size =>\n                                {\n                                    ScottPlot.Plot plot = new();\n                                    \n                                    var bars = new Bar[]\n                                    {\n                                        new() { Position = 1, Value = 2 },\n                                        new() { Position = 2, Value = 3 },\n                                        new() { Position = 3, Value = 8 },\n                                        new() { Position = 4, Value = 13 },\n                                        new() { Position = 5, Value = 17 },\n                                        new() { Position = 6, Value = 17 },\n                                        new() { Position = 7, Value = 32 },\n                                        new() { Position = 8, Value = 42 }\n                                    };\n                                    \n                                    foreach (var bar in bars)\n                                    {\n                                        bar.FillColor = new ScottPlot.Color(Colors.Grey.Medium.Hex);\n                                        bar.LineWidth = 0;\n                                        bar.Size = 0.5;\n                                    }\n\n                                    plot.Add.Bars(bars);\n                                    \n                                    Tick[] ticks = [\n                                        new(1, \"Other\"),\n                                        new(2, \"C# 5\"),\n                                        new(3, \"C# 6\"),\n                                        new(4, \"C# 7\"),\n                                        new(5, \"C# 8\"),\n                                        new(6, \"C# 9\"),\n                                        new(7, \"C# 10\"),\n                                        new(8, \"C# 11\")\n                                    ];\n\n                                    plot.Axes.Bottom.TickGenerator = new ScottPlot.TickGenerators.NumericManual(ticks);\n                                    plot.Axes.Bottom.MajorTickStyle.Length = 0;\n                                    plot.Axes.Bottom.TickLabelStyle.FontName = \"Lato\";\n                                    plot.Axes.Bottom.TickLabelStyle.FontSize = 16;\n                                    plot.Axes.Bottom.TickLabelStyle.OffsetY = 8;\n                                    plot.Grid.XAxisStyle.IsVisible = false;\n                                    \n                                    plot.Axes.Margins(bottom: 0, top: 0.25f);\n\n                                    return plot.GetSvgXml((int)size.Width, (int)size.Height);\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"chart-bars.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternAddressComponentExample.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternAddressComponentExample\n{\n    [Test]\n    public void Example()\n    {\n        var address = new Address\n        {\n            CompanyName = \"Apple\",\n            PostalCode = \"95014\",\n            Country = \"United States\",\n            City = \"Cupertino\",\n            Street = \"One Apple Park Way\"\n        };\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 1200));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Component(new AddressComponent(address));\n                });\n            })\n            .GenerateImages(x => $\"code-pattern-component-address.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n\n    public class Address\n    {\n        public string CompanyName { get; set; }\n        \n        public string PostalCode { get; set; }\n        public string Country { get; set; }\n        public string City { get; set; }\n        public string Street { get; set; }\n    }\n    \n    public class AddressComponent : IComponent\n    {\n        private Address Address { get; }\n\n        public AddressComponent(Address address)\n        {\n            Address = address;\n        }\n        \n        public void Compose(IContainer container)\n        {\n            container\n                .Column(column =>\n                {\n                    column.Spacing(10);\n                    \n                    AddItem(\"Company name\", Address.CompanyName);\n                    AddItem(\"Postal code\", Address.PostalCode);\n                    AddItem(\"Country\", Address.Country);\n                    AddItem(\"City\", Address.City);\n                    AddItem(\"Street\", Address.Street);\n                    \n                    void AddItem(string label, string value)\n                    {\n                        column.Item().Text(text =>\n                        {\n                            text.Span($\"{label}: \").Bold();\n                            text.Span(value);\n                        });\n                    }\n                });\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternCapturePositionExample.cs",
    "content": "using QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternCapturePositionExample\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(575);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Background(Colors.White)\n                        .Row(row =>\n                        {\n                            row.Spacing(25);\n\n                            row.ConstantItem(0).Dynamic(new DynamicTextSpanPositionCapture());\n\n                            row.RelativeItem().CaptureContentPosition(\"container\").Text(text =>\n                            {\n                                text.Justify();\n                                \n                                var mistakeTextStyle = TextStyle.Default\n                                    .FontColor(Colors.Red.Darken3)\n                                    .BackgroundColor(Colors.Red.Lighten4)\n                                    .Strikethrough()\n                                    .DecorationThickness(2);\n                                \n                                var correctionTextStyle = TextStyle.Default\n                                    .FontColor(Colors.Green.Darken3)\n                                    .BackgroundColor(Colors.Green.Lighten4);\n\n                                text.Span(\"Proofreading\").Bold().Underline().DecorationThickness(2);\n                                text.Span(\" technical documentation is a critical quality assurance step that ensures clarity, accuracy, and consistency across all written content. It involves more than just checking for grammar and \");\n                                text.Span(\"spilling\").Style(mistakeTextStyle);\n                                text.Span(\"spelling\").Style(correctionTextStyle);\n                                text.Element(TextInjectedElementAlignment.Middle).CaptureContentPosition(\"mistake\");\n                                text.Span(\" errors—it also includes verifying terminology, code syntax, formatting standards, and logical flow. A common best practice is to have the content reviewed by both a subject matter \");\n                                text.Span(\"export\").Style(mistakeTextStyle);\n                                text.Span(\"expert\").Style(correctionTextStyle);\n                                text.Element(TextInjectedElementAlignment.Middle).CaptureContentPosition(\"mistake\");\n                                text.Span(\" and a language specialist, ensuring that the material is technically sound while also being accessible to the intended audience.\");\n                            });\n                        });\n                });\n            })\n            .GenerateImages(x => \"code-pattern-element-position-locator.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n\n    public class DynamicTextSpanPositionCapture : IDynamicComponent\n    {\n        public DynamicComponentComposeResult Compose(DynamicContext context)\n        {\n            var containerLocation = context.GetContentCapturedPositions(\"container\").FirstOrDefault(x => x.PageNumber == context.PageNumber);\n            var mistakeLocations = context.GetContentCapturedPositions(\"mistake\").Where(x => x.PageNumber == context.PageNumber).ToList();\n            \n            if (containerLocation == null || mistakeLocations.Count == 0)\n            {\n                return new DynamicComponentComposeResult\n                {\n                    Content = context.CreateElement(_ => { }),\n                    HasMoreContent = false\n                };\n            }\n\n            var content = context.CreateElement(container =>\n            {\n                container.Layers(layers =>\n                {\n                    layers.PrimaryLayer();\n\n                    foreach (var mistakeLocation in mistakeLocations)\n                    {\n                        layers\n                            .Layer()\n                            .Unconstrained() \n                            .TranslateY(mistakeLocation.Y - containerLocation.Y)\n                            .TranslateX(-12)\n                            .TranslateY(-12)\n                            .Width(24)\n                            .Svg(\"Resources/proofreading.svg\");\n                    }\n                });\n            });\n\n            return new DynamicComponentComposeResult\n            {\n                Content = content,\n                HasMoreContent = false\n            };\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternComponentProgressbarComponentExample.cs",
    "content": "\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternComponentProgressbarComponentExample\n{\n    [Test]\n    public void Example()\n    {\n        var content = GenerateReport();\n        File.WriteAllBytes(\"code-pattern-dynamic-component-progressbar.pdf\", content);\n    }\n    \n    public byte[] GenerateReport()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A4);\n                    page.Margin(50);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Header().Column(column =>\n                    {\n                        column.Item()\n                            .Text(\"MyBrick Set\")\n                            .FontSize(48).FontColor(Colors.Blue.Darken2).Bold();\n                          \n                        column.Item()\n                            .Text(\"Building Instruction\")\n                            .FontSize(24);\n                        \n                        column.Item().Height(15);\n                        \n                        column.Item().Dynamic(new PageProgressbarComponent());\n                    });\n                        \n                    page.Content().PaddingVertical(25).Column(column =>\n                    {\n                        column.Spacing(25);\n                        \n                        foreach (var i in Enumerable.Range(1, 30))\n                        {\n                            column.Item()\n                                .Background(Colors.Grey.Lighten3)\n                                .Height(Random.Shared.Next(4, 8) * 25)\n                                .AlignCenter()\n                                .AlignMiddle()\n                                .Text($\"Step {i}\");\n                        }\n                    });\n\n                    page.Footer().Dynamic(new PageNumberSideComponent());\n                });\n            })\n            .GeneratePdf();\n    }\n    \n    public class PageProgressbarComponent : IDynamicComponent\n    {\n        public DynamicComponentComposeResult Compose(DynamicContext context)\n        {\n            var content = context.CreateElement(element =>\n            {\n                var width = context.AvailableSize.Width * context.PageNumber / context.TotalPages;\n                \n                element\n                    .Background(Colors.Blue.Lighten3)\n                    .Height(5)\n                    .Width(width)\n                    .Background(Colors.Blue.Darken2);\n            });\n\n            return new DynamicComponentComposeResult\n            {\n                Content = content,\n                HasMoreContent = false\n            };\n        }\n    }\n\n    public class PageNumberSideComponent : IDynamicComponent\n    {\n        public DynamicComponentComposeResult Compose(DynamicContext context)\n        {\n            var content = context.CreateElement(element =>\n            {\n                element\n                    .Element(x => context.PageNumber % 2 == 0 ? x.AlignRight() : x.AlignLeft())\n                    .Text(text =>\n                    {\n                        text.Span(\"Page \");\n                        text.CurrentPageNumber();\n                    });\n            });\n\n            return new DynamicComponentComposeResult\n            {\n                Content = content,\n                HasMoreContent = false\n            };\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternConfigurableComponentExample.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternConfigurableComponentExample\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 1200));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Component(BuildSampleSection());\n                });\n            })\n            .GenerateImages(x => $\"code-pattern-component-configurable.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n\n        IComponent BuildSampleSection()\n        {\n            var section = new SectionComponent();\n\n            section.Text(\"Product name\", Placeholders.Label());\n            section.Text(\"Description\", Placeholders.Sentence());\n            section.Text(\"Price\", Placeholders.Price());\n            section.Text(\"Date of production\", Placeholders.ShortDate());\n            section.Image(\"Photo of the product\", \"Resources/product.jpg\");\n            section.Custom(\"Status\").Text(\"Accepted\").FontColor(Colors.Green.Darken2).Bold();\n            \n            return section;\n        }\n    }\n\n    public class SectionComponent : IComponent\n    {\n        private List<(string Label, IContainer Content)> Fields { get; set; } = [];\n\n        public SectionComponent()\n        {\n            \n        }\n        \n        public void Compose(IContainer container)\n        {\n            container\n                .Border(1)\n                .Column(column =>\n                {\n                    foreach (var field in Fields)\n                    {\n                        column.Item().Row(row =>\n                        {\n                            row.RelativeItem()\n                                .Border(1)\n                                .BorderColor(Colors.Grey.Medium)\n                                .Background(Colors.Grey.Lighten3)\n                                .Padding(10)\n                                .Text(field.Label);\n\n                            row.RelativeItem(2)\n                                .Border(1)\n                                .BorderColor(Colors.Grey.Medium)\n                                .Padding(10)\n                                .Element(field.Content);\n                        });\n                    }\n                });\n        }\n\n        public void Text(string label, string text)\n        {\n            Custom(label).Text(text);\n        }\n        \n        public void Image(string label, string imagePath)\n        {\n            Custom(label).Image(imagePath);\n        }\n        \n        public IContainer Custom(string label)\n        {\n            var content = EmptyContainer.Create();\n            Fields.Add((label, content));\n            return content;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternContentStylingExample.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternContentStylingExample\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(650, 0));\n                    page.MaxSize(new PageSize(650, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.ConstantColumn(50);\n                                columns.RelativeColumn(1);\n                                columns.RelativeColumn(2);\n                            });\n                            \n                            table.Header(header =>\n                            {\n                                header.Cell().Element(Style).Text(\"#\");\n                                header.Cell().Element(Style).Text(\"Product Name\");\n                                header.Cell().Element(Style).Text(\"Description\");\n\n                                IContainer Style(IContainer container)\n                                {\n                                    return container\n                                        .Background(Colors.Blue.Lighten5)\n                                        .Padding(10)\n                                        .DefaultTextStyle(TextStyle.Default.FontColor(Colors.Blue.Darken4).Bold());\n                                }\n                            });\n\n                            foreach (var i in Enumerable.Range(1, 5))\n                            {\n                                table.Cell().Element(Style).Text(i.ToString());\n                                table.Cell().Element(Style).Text(Placeholders.Label());\n                                table.Cell().Element(Style).Text(Placeholders.Sentence());\n                            }\n\n                            IContainer Style(IContainer container)\n                            { \n                                return container\n                                    .BorderTop(2)\n                                    .BorderColor(Colors.Blue.Lighten3)\n                                    .Padding(10);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => $\"code-pattern-content-styling.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternDocumentStructureExample.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternDocumentStructureExample\n{\n    [Test]\n    public void Example()\n    {\n        var content = GenerateReport();\n        File.WriteAllBytes(\"code-pattern-document-structure.pdf\", content);\n    }\n\n    public byte[] GenerateReport()\n    {\n        return Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .PaddingBottom(15)\n                        .Column(column =>\n                        {\n                            column.Item().Element(ReportTitle);\n                            column.Item().PageBreak();\n                            column.Item().Element(RedSection);\n                            column.Item().PageBreak();\n                            column.Item().Element(GreenSection);\n                            column.Item().PageBreak();\n                            column.Item().Element(BlueSection);\n                        });\n\n                    page.Footer().AlignCenter().Text(text => text.CurrentPageNumber());\n                });\n            })\n            .GeneratePdf();\n    }\n\n    private void ReportTitle(IContainer container)\n    {\n        container.Extend()\n            .AlignCenter()\n            .AlignMiddle()\n            .Text(\"Multi-section report\")\n            .FontSize(48)\n            .Bold();\n    }\n    \n    private void RedSection(IContainer container)\n    {\n        container.Grid(grid =>\n        {\n            grid.Columns(3);\n            grid.Spacing(15);\n            \n            grid.Item(3 ).Text(\"Red section\")\n                .FontColor(Colors.Red.Darken2).FontSize(32).Bold();\n\n            grid.Item(3).Text(Placeholders.Paragraph()).Light();\n\n            foreach (var i in Enumerable.Range(0, 6))\n                grid.Item().AspectRatio(4 / 3f).Background(Colors.Red.Lighten4);\n        });\n    }\n    \n    private void GreenSection(IContainer container)\n    {\n        container.Grid(grid =>\n        {\n            grid.Columns(3);\n            grid.Spacing(15);\n            \n            grid.Item(3).Text(\"Green section\")\n                .FontColor(Colors.Green.Darken2).FontSize(32).Bold();\n\n            grid.Item(3).Text(Placeholders.Paragraph()).Light();\n\n            foreach (var i in Enumerable.Range(0, 12))\n                grid.Item().AspectRatio(4 / 3f).Background(Colors.Green.Lighten4);\n        });\n    }\n    \n    private void BlueSection(IContainer container)\n    {\n        container.Grid(grid =>\n        {\n            grid.Columns(3);\n            grid.Spacing(15);\n            \n            grid.Item(3).Text(\"Blue section\")\n                .FontColor(Colors.Blue.Darken2).FontSize(32).Bold();\n\n            grid.Item(3).Text(Placeholders.Paragraph()).Light();\n\n            foreach (var i in Enumerable.Range(0, 18))\n                grid.Item().AspectRatio(4 / 3f).Background(Colors.Blue.Lighten4);\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternDynamicComponentExample.cs",
    "content": "using System.Globalization;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternDynamicComponentExample\n{ \n    [Test]\n    public static void Dynamic()\n    {\n        var items = Enumerable.Range(0, 25).Select(x => new OrderItem()).ToList();\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A4);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n\n                    page.Content()\n                        .Decoration(decoration =>\n                        {\n                            decoration\n                                .Before()\n                                .PaddingBottom(10)\n                                .Text(text =>\n                                {\n                                    text.DefaultTextStyle(TextStyle.Default.Bold().FontColor(Colors.Blue.Darken2));\n                                    text.Span(\"Page \");\n                                    text.CurrentPageNumber();\n                                    text.Span(\" of \");\n                                    text.TotalPages();\n                                });\n                            \n                            decoration\n                                .Content()\n                                .Dynamic(new OrdersTableWithPageSubtotalsComponent(items));\n                        });\n                });\n            })\n            .GeneratePdf(\"code-pattern-dynamic-component-table-with-per-page-subtotals.pdf\");\n    }\n    \n    public class OrderItem\n    {\n        public string ItemName { get; set; } = Placeholders.Label();\n        public int Price { get; set; } = Placeholders.Random.Next(1, 11) * 10;\n        public int Count { get; set; } = Placeholders.Random.Next(1, 11);\n    }\n\n    public struct OrdersTableWithPageSubtotalsComponentState\n    {\n        public int ShownItemsCount { get; set; }\n    }\n    \n    public class OrdersTableWithPageSubtotalsComponent : IDynamicComponent<OrdersTableWithPageSubtotalsComponentState>\n    {\n        private ICollection<OrderItem> Items { get; }\n        public OrdersTableWithPageSubtotalsComponentState State { get; set; }\n\n        public OrdersTableWithPageSubtotalsComponent(ICollection<OrderItem> items)\n        {\n            Items = items;\n\n            State = new OrdersTableWithPageSubtotalsComponentState\n            {\n                ShownItemsCount = 0\n            };\n        }\n        \n        public DynamicComponentComposeResult Compose(DynamicContext context)\n        {\n            var header = ComposeHeader(context);\n            var sampleFooter = ComposeFooter(context, []);\n            var decorationHeight = header.Size.Height + sampleFooter.Size.Height;\n            \n            var rows = GetItemsForPage(context, decorationHeight).ToList();\n            var footer = ComposeFooter(context, rows.Select(x => x.Item));\n\n            var content = context.CreateElement(container =>\n            {\n                container.Shrink().Decoration(decoration =>\n                {\n                    decoration.Before().Element(header);\n\n                    decoration.Content().Column(column =>\n                    {\n                        foreach (var row in rows)\n                            column.Item().Element(row.Element);\n                    });\n\n                    decoration.After().Element(footer);\n                });\n            });\n\n            State = new OrdersTableWithPageSubtotalsComponentState\n            {\n                ShownItemsCount = State.ShownItemsCount + rows.Count\n            };\n\n            return new DynamicComponentComposeResult\n            {\n                Content = content,\n                HasMoreContent = State.ShownItemsCount < Items.Count\n            };\n        }\n\n        private static IDynamicElement ComposeHeader(DynamicContext context)\n        {\n            return context.CreateElement(element =>\n            {\n                element\n                    .Width(context.AvailableSize.Width)\n                    .BorderBottom(1)\n                    .BorderColor(Colors.Grey.Darken2)\n                    .Padding(10)\n                    .DefaultTextStyle(TextStyle.Default.SemiBold())\n                    .Row(row =>\n                    {\n                        row.ConstantItem(50).Text(\"#\");\n                        row.RelativeItem().Text(\"Item name\");\n                        row.ConstantItem(75).AlignRight().Text(\"Count\");\n                        row.ConstantItem(75).AlignRight().Text(\"Price\");\n                        row.ConstantItem(75).AlignRight().Text(\"Total\");\n                    });\n            });\n        }\n        \n        private static IDynamicElement ComposeFooter(DynamicContext context, IEnumerable<OrderItem> items)\n        {\n            var total = items.Sum(x => x.Count * x.Price);\n\n            return context.CreateElement(element =>\n            {\n                element\n                    .Width(context.AvailableSize.Width)\n                    .Padding(10)\n                    .AlignRight()\n                    .Text($\"Subtotal: {total}$\")\n                    .Bold();\n            });\n        }\n        \n        private IEnumerable<(OrderItem Item, IDynamicElement Element)> GetItemsForPage(DynamicContext context, float decorationHeight)\n        {\n            var totalHeight = decorationHeight;\n\n            foreach (var index in Enumerable.Range(State.ShownItemsCount, Items.Count - State.ShownItemsCount))\n            {\n                var item = Items.ElementAt(index);\n                \n                var element = context.CreateElement(content =>\n                {\n                    content\n                        .Width(context.AvailableSize.Width)\n                        .BorderBottom(1)\n                        .BorderColor(Colors.Grey.Lighten2)\n                        .Padding(10)\n                        .Row(row =>\n                        {\n                            row.ConstantItem(50).Text((index + 1).ToString(CultureInfo.InvariantCulture));\n                            row.RelativeItem().Text(item.ItemName);\n                            row.ConstantItem(75).AlignRight().Text(item.Count.ToString(CultureInfo.InvariantCulture));\n                            row.ConstantItem(75).AlignRight().Text($\"{item.Price}$\");\n                            row.ConstantItem(75).AlignRight().Text($\"{item.Count*item.Price}$\");\n                        });\n                });\n\n                var elementHeight = element.Size.Height;\n\n                // it is important to use the Size.Epsilon constant to avoid floating point comparison issues\n                if (totalHeight + elementHeight > context.AvailableSize.Height + Size.Epsilon)\n                    break;\n                    \n                totalHeight += elementHeight;\n                yield return (item, element);\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternExecutionOrderExample.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternExecutionOrderExample\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(400, 0));\n                    page.MaxSize(new PageSize(400, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n\n                            column.Item()\n                                .Border(1)\n                                .Background(Colors.Blue.Lighten4)\n                                .Padding(15)\n                                .Text(\"border → background → padding\");\n                            \n                            column.Item()\n                                .Border(1)\n                                .Padding(15)\n                                .Background(Colors.Blue.Lighten4)\n                                .Text(\"border → padding → background\");\n    \n                            column.Item()\n                                .Background(Colors.Blue.Lighten4)\n                                .Padding(15)\n                                .Border(1)\n                                .Text(\"background → padding → border\");\n                            \n                            column.Item()\n                                .Padding(15)\n                                .Border(1)\n                                .Background(Colors.Blue.Lighten4)\n                                .Text(\"padding → border → background\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"code-pattern-execution-order.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternExtesionMethodExample.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternExtensionMethodExample\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(600, 0));\n                    page.MaxSize(new PageSize(600, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(14));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Border(1)\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn(2);\n                                columns.RelativeColumn(3);\n                                columns.RelativeColumn(2);\n                                columns.RelativeColumn(3);\n                            });\n                            \n                            table.Cell().TableLabelCell(\"Product name\");\n                            table.Cell().TableValueCell().Text(Placeholders.Label());\n                            \n                            table.Cell().TableLabelCell(\"Description\");\n                            table.Cell().TableValueCell().Text(Placeholders.Sentence());\n                            \n                            table.Cell().TableLabelCell(\"Price\");\n                            table.Cell().TableValueCell().Text(Placeholders.Price());\n                            \n                            table.Cell().TableLabelCell(\"Date of production\");\n                            table.Cell().TableValueCell().Text(Placeholders.ShortDate());\n                            \n                            table.Cell().ColumnSpan(2).TableLabelCell(\"Photo of the product\");\n                            table.Cell().ColumnSpan(2).TableValueCell().AspectRatio(16 / 9f).Image(Placeholders.Image);\n                        });\n                });\n            })\n            .GenerateImages(x => \"code-pattern-extension-methods.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}\n\npublic static class TableExtensions\n{\n    private static IContainer TableCellStyle(this IContainer container, string backgroundColor)\n    {\n        return container\n            .Border(1)\n            .BorderColor(Colors.Black)\n            .Background(backgroundColor)\n            .Padding(10);\n    }\n    \n    public static void TableLabelCell(this IContainer container, string text)\n    {\n        container\n            .TableCellStyle(Colors.Grey.Lighten3)\n            .Text(text)\n            .Bold();\n    }\n    \n    public static IContainer TableValueCell(this IContainer container)\n    {\n        return container.TableCellStyle(Colors.Transparent);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CodePatterns/CodePatternLocalHelpersExample.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.CodePatterns;\n\npublic class CodePatternLocalHelpersExample\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(15);\n\n                            column.Item().Text(\"Business details:\").FontSize(24).Bold().FontColor(Colors.Blue.Darken2);\n                            \n                            AddContactItem(\"Resources/Icons/phone.svg\", Placeholders.PhoneNumber());\n                            AddContactItem(\"Resources/Icons/email.svg\", Placeholders.Email());\n                            AddContactItem(\"Resources/Icons/web.svg\", Placeholders.WebpageUrl());\n\n                            void AddContactItem(string iconPath, string label)\n                            {\n                                column.Item().Row(row =>\n                                {\n                                    row.ConstantItem(32).AspectRatio(1).Svg(iconPath);\n                                    row.ConstantItem(15);\n                                    row.AutoItem().AlignMiddle().Text(label);\n                                });\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => $\"code-pattern-local-helpers.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ColorsExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ColorsExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content() \n                        .Width(175)\n                        .Padding(20)\n                        .Border(1)\n                        .BorderColor(\"#03A9F4\")\n                        .Background(Colors.LightBlue.Lighten5)\n                        .Padding(20)\n                        .Text(\"Blue text\")\n                        .Bold()\n                        .FontColor(Colors.LightBlue.Darken4)\n                        .Underline()\n                        .DecorationWavy()\n                        .DecorationColor(0xFF0000);\n                });\n            })\n            .GenerateImages(x => \"colors.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ColumnExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ColumnExamples\n{\n    [Test]\n    public void SimpleExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(250, 0));\n                    page.MaxSize(new PageSize(250, 1000));\n                    page.Margin(25);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().Background(Colors.Grey.Medium).Height(50);\n                            column.Item().Background(Colors.Grey.Lighten1).Height(75);\n                            column.Item().Background(Colors.Grey.Lighten2).Height(100);\n                        });\n                });\n            })\n            .GenerateImages(x => \"column-simple.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void SpacingExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(250, 0));\n                    page.MaxSize(new PageSize(250, 1000));\n                    page.Margin(25);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n                            \n                            column.Item().Background(Colors.Grey.Medium).Height(50);\n                            column.Item().Background(Colors.Grey.Lighten1).Height(75);\n                            column.Item().Background(Colors.Grey.Lighten2).Height(100);\n                        });\n                });\n            })\n            .GenerateImages(x => \"column-spacing.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void CustomSpacingExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(250, 0));\n                    page.MaxSize(new PageSize(250, 1000));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().Background(Colors.Grey.Darken1).Height(50);\n                            column.Item().Height(10);\n                            column.Item().Background(Colors.Grey.Medium).Height(50);\n                            column.Item().Height(20);\n                            column.Item().Background(Colors.Grey.Lighten1).Height(50);\n                            column.Item().Height(30);\n                            column.Item().Background(Colors.Grey.Lighten2).Height(50);\n                        });\n                });\n            })\n            .GenerateImages(x => \"column-spacing-custom.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n        \n    [Test]\n    public void DisableUniformItemsWidthExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(400, 0));\n                    page.MaxSize(new PageSize(400, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(15);\n                            \n                            column.Item()\n                                .Element(LabelStyle)\n                                .Text(\"REST API\");\n                            \n                            column.Item()\n                                .Element(LabelStyle)\n                                .Text(\"Garbage Collection\");\n                            \n                            column.Item()\n                                .Element(LabelStyle)\n                                .Text(\"Object-Oriented Programming\");\n                            \n                            static IContainer LabelStyle(IContainer container) => container\n                                .ShrinkHorizontal()\n                                .Background(Colors.Grey.Lighten3)\n                                .CornerRadius(15)\n                                .Padding(15);\n                        });\n                });\n            })\n            .GenerateImages(x => \"column-uniform-width-disabled.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ComplexGraphicsExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ComplexGraphicsExamples\n{\n    [Test]\n    public void RoundedRectangleWithGradient()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    \n                    page.Content()\n                        .Layers(layers =>\n                        {\n                            layers.Layer().Svg(size =>\n                            {\n                                return $\"\"\"\n                                        <svg width=\"{size.Width}\" height=\"{size.Height}\" xmlns=\"http://www.w3.org/2000/svg\">\n                                            <defs>\n                                              <linearGradient id=\"backgroundGradient\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n                                                <stop stop-color=\"#00E5FF\" offset=\"0%\"/>\n                                                <stop stop-color=\"#2979FF\" offset=\"100%\"/>\n                                              </linearGradient>\n                                            </defs>\n                                        \n                                            <rect x=\"0\" y=\"0\" width=\"{size.Width}\" height=\"{size.Height}\" rx=\"{size.Height / 2}\" ry=\"{size.Height / 2}\" fill=\"url(#backgroundGradient)\" />\n                                        </svg>\n                                        \"\"\";\n                            });\n\n                            layers.PrimaryLayer()\n                                .PaddingVertical(10)\n                                .PaddingHorizontal(20)\n                                .Text(\"QuestPDF\")\n                                .FontColor(Colors.White)\n                                .FontSize(32)\n                                .ExtraBlack();\n                        });\n                });\n            })\n            .GenerateImages(x => \"complex-graphics-rounded-rectangle-with-gradient.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void DottedLine()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(500, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(5);\n                            \n                            foreach (var i in Enumerable.Range(1, 5))\n                            {\n                                var pageNumber = i * 7 + 4;\n                                \n                                column.Item().Row(row =>\n                                {\n                                    row.AutoItem().Text($\"{i}.\");\n                                    row.ConstantItem(10);\n                                    row.AutoItem().Text(Placeholders.Label());\n\n                                    row.RelativeItem().PaddingHorizontal(3).TranslateY(20).Height(2).Svg(size =>\n                                    {\n                                        return $\"\"\"\n                                                <svg width=\"{size.Width}\" height=\"{size.Height}\" xmlns=\"http://www.w3.org/2000/svg\">\n                                                    <line x1=\"0\" y1=\"0\" x2=\"{size.Width}\" y2=\"0\" fill=\"none\" stroke=\"black\" stroke-width=\"2\" stroke-dasharray=\"2 6\" />\n                                                </svg>\n                                                \"\"\";\n                                    });\n\n                                    row.AutoItem().Text($\"{pageNumber}\");\n                                });\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"complex-graphics-dotted-line.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ConstrainedExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ConstrainedExamples\n{\n    [Test]\n    public void WidthExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(300)\n                        .Padding(25)\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n                            \n                            column.Item()\n                                .MinWidth(200)\n                                .Background(Colors.Grey.Lighten3)\n                                .Text(\"Lorem ipsum\");\n                            \n                            column.Item()\n                                .MaxWidth(100)\n                                .Background(Colors.Grey.Lighten3)\n                                .Text(\"dolor sit amet\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"width.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void HeightExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(300)\n                        .Padding(25)\n                        .Height(100)\n                        .AspectRatio(2f, AspectRatioOption.FitHeight)\n                        .Background(Colors.Grey.Lighten1);\n                });\n            })\n            .GenerateImages(x => \"height.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ContentDirectionExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ContentDirectionExamples\n{\n    [Test]\n    public void LeftToRightExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(250)\n                        .ContentFromLeftToRight()\n                        .Row(row =>\n                        {\n                            row.Spacing(5);\n    \n                            row.AutoItem().Height(50).Width(50).Background(Colors.Red.Lighten1);\n                            row.AutoItem().Height(50).Width(50).Background(Colors.Green.Lighten1);\n                            row.AutoItem().Height(50).Width(75).Background(Colors.Blue.Lighten1);\n                        });\n                });\n            })\n            .GenerateImages(x => \"content-direction-ltr.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void RightToLeftExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(250)\n                        .ContentFromRightToLeft()\n                        .Row(row =>\n                        {\n                            row.Spacing(5);\n    \n                            row.AutoItem().Height(50).Width(50).Background(Colors.Red.Lighten1);\n                            row.AutoItem().Height(50).Width(50).Background(Colors.Green.Lighten1);\n                            row.AutoItem().Height(50).Width(75).Background(Colors.Blue.Lighten1);\n                        });\n                });\n            })\n            .GenerateImages(x => \"content-direction-rtl.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/CustomFirstPageExample.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class CustomFirstPageExample\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.Margin(30);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n    \n                    page.Header().Column(column =>\n                    {\n                        column.Item().ShowOnce().Background(Colors.Blue.Lighten2).Height(80);\n                        column.Item().SkipOnce().Background(Colors.Green.Lighten2).Height(60);\n                    });\n    \n                    page.Content().PaddingVertical(20).Column(column =>\n                    {\n                        column.Spacing(20);\n\n                        foreach (var _ in Enumerable.Range(0, 20))\n                            column.Item().Background(Colors.Grey.Lighten3).Height(40);\n                    });\n    \n                    page.Footer().AlignCenter().Text(text =>\n                    {\n                        text.CurrentPageNumber();\n                        text.Span(\" / \");\n                        text.TotalPages();\n                    });\n                });\n            })\n            .GeneratePdf(\"example-custom-first-page.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/DebugAreaExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class DebugAreaExamples\n{\n    [Test]\n    public void LeftToRightExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(250)\n                        .Height(250)\n                        .Padding(25)\n                        .DebugArea(\"Grid example\", Colors.Blue.Medium)\n                        .Grid(grid =>\n                        {\n                            grid.Columns(3);\n                            grid.Spacing(5);\n\n                            foreach (var _ in Enumerable.Range(0, 8))\n                                grid.Item().Height(50).Placeholder();\n                        });\n                });\n            })\n            .GenerateImages(x => \"debug-area.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 216 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/DecorationExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class DecorationExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(350, 0));\n                    page.MaxSize(new PageSize(350, 300));\n                    page.Margin(25);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Background(Colors.Grey.Lighten3)\n                        .Padding(15)\n                        .Decoration(decoration =>\n                        {\n                            decoration\n                                .Before()\n                                .DefaultTextStyle(x => x.Bold())\n                                .Column(column =>\n                                {\n                                    column.Item().ShowOnce().Text(\"Customer Instructions:\");\n                                    column.Item().SkipOnce().Text(\"Customer Instructions [continued]:\");\n                                });\n\n                            decoration\n                                .Content()\n                                .PaddingTop(10)\n                                .Text(\"Please wrap the item in elegant gift paper and include a small blank card for a personal message. If possible, remove any price tags or invoices from the package. Make sure the wrapping is secure but easy to open without damaging the contents.\");\n                        });\n                });\n            })\n            .GenerateImages(x => $\"decoration-{x}.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/DefaultTextStyleExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class DefaultTextStyleExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(400)\n                        .Padding(25)\n                        .DefaultTextStyle(x => x.Bold().Underline())\n                        .Column(column =>\n                        { \n                            column.Spacing(10);\n                            \n                            column.Item().Text(\"Inherited bold and underline\");\n                            column.Item().Text(\"Disabled underline, inherited bold and adjusted font color\").Underline(false).FontColor(Colors.Green.Darken2);\n    \n                            column.Item()\n                                .DefaultTextStyle(x => x.DecorationWavy().FontColor(Colors.LightBlue.Darken3))\n                                .Text(\"Changed underline type and adjusted font color\");\n                        }); \n                });\n            })\n            .GenerateImages(x => \"default-text-style.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/DocumentOperationExamples.cs",
    "content": "using System.Runtime.InteropServices;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\n[TestFixture]\npublic class DocumentOperationExamples\n{\n    [Test]\n    public void MergeFiles()\n    {\n        const string prefix = \"document-operation-merge\";\n        \n        GenerateSampleDocument($\"{prefix}-source-red.pdf\", Colors.Red.Lighten3, 2);\n        GenerateSampleDocument($\"{prefix}-source-green.pdf\", Colors.Green.Lighten3, 3);\n        GenerateSampleDocument($\"{prefix}-source-blue.pdf\", Colors.Blue.Lighten3, 5);\n        \n        DocumentOperation\n            .LoadFile($\"{prefix}-source-red.pdf\")\n            .MergeFile($\"{prefix}-source-green.pdf\")\n            .MergeFile($\"{prefix}-source-blue.pdf\")\n            .Save($\"{prefix}-result.pdf\");\n    }\n    \n    [Test]\n    public void SelectEvenPages()\n    {\n        const string prefix = \"document-operation-select-even-pages\";\n        \n        GenerateSampleDocument($\"{prefix}-source.pdf\", Colors.Indigo.Lighten3, 11);\n        \n        DocumentOperation\n            .LoadFile($\"{prefix}-source.pdf\")\n            .TakePages(\"1-z:even\")\n            .Save($\"{prefix}-result.pdf\");\n    }\n\n    [Test]\n    public void Encrypt()\n    {\n        const string prefix = \"document-operation-encrypt\";\n        \n        GenerateSampleDocument($\"{prefix}-source.pdf\", Colors.Orange.Lighten3, 7);\n        \n        DocumentOperation\n            .LoadFile($\"{prefix}-source.pdf\")\n            .Encrypt(new DocumentOperation.Encryption256Bit()\n            {\n                UserPassword = \"user-password\",\n                OwnerPassword = \"owner-password\",\n                AllowContentExtraction = false,\n                AllowPrinting = false\n            })\n            .Save($\"{prefix}-result.pdf\");\n    }\n    \n    [Test]\n    public void AddAttachment()\n    {\n        const string prefix = \"document-operation-add-attachment\";\n        \n        GenerateSampleDocument($\"{prefix}-source.pdf\", Colors.Cyan.Lighten3, 7);\n        File.WriteAllText($\"{prefix}-content.txt\", \"Hello, World!\");\n        \n        DocumentOperation\n            .LoadFile($\"{prefix}-source.pdf\")\n            .AddAttachment(new DocumentOperation.DocumentAttachment\n            {\n                FilePath = $\"{prefix}-content.txt\",\n                AttachmentName = \"Attached message\"\n            })\n            .Save($\"{prefix}-result.pdf\");\n    }\n    \n    [Test]\n    public void Overlay()\n    {\n        const string prefix = \"document-operation-overlay\";\n        \n        GenerateSampleDocument($\"{prefix}-source.pdf\", Colors.Cyan.Lighten3, 7);\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(1, Unit.Centimetre);\n                    page.PageColor(Colors.Transparent);\n                    \n                    page.Content().Column(column =>\n                    {\n                        foreach (var i in Enumerable.Range(0, 6))\n                            column.Item().PageBreak();\n                    });\n\n                    page.Footer().AlignCenter().Text(text =>\n                    {\n                        text.DefaultTextStyle(x => x.FontSize(24).Bold().FontColor(Colors.White));\n                        text.Span(\"Page \");\n                        text.CurrentPageNumber();\n                        text.Span(\" of \");\n                        text.TotalPages();\n                    });\n                });\n            })\n            .GeneratePdf($\"{prefix}-content.pdf\");\n        \n        DocumentOperation\n            .LoadFile($\"{prefix}-source.pdf\")\n            .OverlayFile(new DocumentOperation.LayerConfiguration\n            {\n                FilePath = $\"{prefix}-content.pdf\"\n            })\n            .Save($\"{prefix}-result.pdf\");\n    }\n    \n    private void GenerateSampleDocument(string fileName, Color pageColor, int numberOfPages)\n    {\n        Document\n            .Create(container =>\n            {\n                container.Page(page =>\n                {\n                    page.Margin(1, Unit.Centimetre);\n                    page.PageColor(pageColor);\n                    \n                    page.Content().Column(column =>\n                    {\n                        foreach (var pageNumber in Enumerable.Range(1, numberOfPages))\n                        {\n                            column.Item()\n                                .Extend()\n                                .AlignCenter().AlignMiddle()\n                                .Text($\"{pageNumber}\")\n                                .FontSize(256)\n                                .FontColor(Colors.White)\n                                .Bold();\n                            \n                            if (pageNumber != numberOfPages)\n                                column.Item().PageBreak();\n                        }\n                    });\n                });\n            })\n            .GeneratePdf(fileName);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/EnsureSpaceExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class EnsureSpaceExamples\n{\n    [Test]\n    public void EnabledExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(30);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().Height(400).Background(Colors.Grey.Lighten3);\n                            column.Item().Height(30); \n                            \n                            column.Item()\n                                .EnsureSpace(100)\n                                .Table(table =>\n                                {\n                                    table.ColumnsDefinition(columns =>\n                                    {\n                                        columns.ConstantColumn(40);\n                                        columns.RelativeColumn();\n                                    });\n\n                                    foreach (var i in Enumerable.Range(1, 12))\n                                    {\n                                        table.Cell().Text($\"{i}.\");\n                                        table.Cell().ShowEntire().Text(Placeholders.Sentence());\n                                    }\n                                });\n                        });\n                });\n            })\n            .GeneratePdf(\"ensure-space-enabled.pdf\");\n    }\n    \n    [Test]\n    public void DisabledExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(30);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().Height(400).Background(Colors.Grey.Lighten3);\n                            column.Item().Height(30); \n                            \n                            column.Item()\n                                .Table(table =>\n                                {\n                                    table.ColumnsDefinition(columns =>\n                                    {\n                                        columns.ConstantColumn(40);\n                                        columns.RelativeColumn();\n                                    });\n\n                                    foreach (var i in Enumerable.Range(1, 12))\n                                    {\n                                        table.Cell().Text($\"{i}.\");\n                                        table.Cell().Text(Placeholders.Sentence());\n                                    }\n                                });\n                        });\n                });\n            })\n            .GeneratePdf(\"ensure-space-disabled.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/FlipExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class FlipExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(350, 0));\n                    page.MaxSize(new PageSize(350, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(15);\n\n                            column.Item()\n                                .Text(\"Read the message below by putting a mirror on the right side of the screen.\");\n                            \n                            column.Item()\n                                .AlignLeft()\n                                .Background(Colors.Red.Lighten5)\n                                .Padding(10)\n                                .FlipHorizontal()\n                                .Text(\"This is a secret message.\")\n                                .FontColor(Colors.Red.Darken2);\n                        });\n                });\n            })\n            .GenerateImages(x => \"flip.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/HyperlinkExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class HyperlinkExamples\n{\n    [Test]\n    public void ElementExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(400);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(25);\n                            \n                            column.Item()\n                                .Text(\"Clicking the NuGet logo will redirect you to the NuGet website.\");\n\n                            column.Item()\n                                .Width(150)\n                                .Hyperlink(\"https://www.nuget.org/\")\n                                .Svg(\"Resources/nuget-logo.svg\");\n                        });\n                });\n            })\n            .GeneratePdf(\"hyperlink-element.pdf\");\n    }\n    \n    [Test]\n    public void InsideTextExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(300);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"Click \");\n                            text.Hyperlink(\"here\", \"https://www.nuget.org/\").Underline().FontColor(Colors.Blue.Darken2);\n                            text.Span(\" to visit the official NuGet website.\");\n                        });\n                });\n            })\n            .GeneratePdf(\"hyperlink-text.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ImageExamples.cs",
    "content": "using QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing SkiaSharp;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ImageExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(400, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Grid(grid =>\n                        {\n                            grid.Columns(2);\n                            grid.Spacing(10);\n                            \n                            grid.Item(2).Text(\"My photo gallery:\").Bold();\n                            \n                            grid.Item().Image(\"Resources/Photos/photo-gallery-1.jpg\");\n                            grid.Item().Image(\"Resources/Photos/photo-gallery-2.jpg\");\n                            grid.Item().Image(\"Resources/Photos/photo-gallery-3.jpg\");\n                            grid.Item().Image(\"Resources/Photos/photo-gallery-4.jpg\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"image-example.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void ImageScaling()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1500));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().PaddingBottom(5).Text(\"FitWidth\").Bold();\n                            column.Item()\n                                .Width(200)\n                                .Height(150)\n                                .Border(4)\n                                .BorderColor(Colors.Red.Medium)\n                                .Image(\"Resources/Photos/photo.jpg\")\n                                .FitWidth();\n\n                            column.Item().Height(15);\n\n                            column.Item().PaddingBottom(5).Text(\"FitHeight\").Bold();\n                            column.Item()\n                                .Width(200)\n                                .Height(100)\n                                .Border(4)\n                                .BorderColor(Colors.Red.Medium)\n                                .Image(\"Resources/Photos/photo.jpg\")\n                                .FitHeight();\n                            \n                            column.Item().Height(15);\n\n                            column.Item().PaddingBottom(5).Text(\"FitArea 1\").Bold();\n                            column.Item()\n                                .Width(200)\n                                .Height(100)\n                                .Border(4)\n                                .BorderColor(Colors.Red.Medium)\n                                .Image(\"Resources/Photos/photo.jpg\")\n                                .FitArea();\n                            \n                            column.Item().Height(15);\n                            \n                            column.Item().PaddingBottom(5).Text(\"FitArea 2\").Bold();\n                            column.Item()\n                                .Width(200)\n                                .Height(150)\n                                .Border(4)\n                                .BorderColor(Colors.Red.Medium)\n                                .Image(\"Resources/Photos/photo.jpg\")\n                                .FitArea();\n                            \n                            column.Item().Height(15);\n\n                            column.Item().PaddingBottom(5).Text(\"FitUnproportionally\").Bold();\n                            column.Item()\n                                .Width(200)\n                                .Height(50)\n                                .Border(4)\n                                .BorderColor(Colors.Red.Medium)\n                                .Image(\"Resources/Photos/photo.jpg\")\n                                .FitUnproportionally();\n                        });\n                });\n            })\n            .GenerateImages(x => \"image-scaling.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void DpiSetting()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(400, 1000));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n    \n                            // lower raster dpi = lower resolution, pixelation\n                            column\n                                .Item()\n                                .Image(\"Resources/Photos/photo.jpg\")\n                                .WithRasterDpi(16);\n    \n                            // higher raster dpi = higher resolution\n                            column\n                                .Item()\n                                .Image(\"Resources/Photos/photo.jpg\")\n                                .WithRasterDpi(288);\n                        });\n                });\n            })\n            .GenerateImages(x => \"image-dpi.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void CompressionSetting()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(400, 1000));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n    \n                            // low quality = smaller output file\n                            column\n                                .Item()\n                                .Image(\"Resources/Photos/photo.jpg\")\n                                .WithCompressionQuality(ImageCompressionQuality.VeryLow);\n        \n                            // high quality / fidelity = larger output file\n                            column\n                                .Item()\n                                .Image(\"Resources/Photos/photo.jpg\")\n                                .WithCompressionQuality(ImageCompressionQuality.VeryHigh);\n                        });\n                });\n            })\n            .GenerateImages(x => \"image-compression.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void GlobalSettings()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Content().Image(\"Resources/Photos/photo.jpg\");\n                });\n            })\n            .WithSettings(new DocumentSettings\n            {\n                // default: ImageCompressionQuality.High;\n                ImageCompressionQuality = ImageCompressionQuality.Medium,\n\n                // default: 288\n                ImageRasterDpi = 14\n            })\n            .GeneratePdf(\"image-global-settings.pdf\");\n    }\n    \n    [Test]\n    public void SharedImages()\n    {\n        using var image = Image.FromFile(\"Resources/checkbox.png\");\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(350, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(15);\n                            \n                            foreach (var i in Enumerable.Range(0, 5))\n                            {\n                                column.Item().Row(row =>\n                                {\n                                    row.AutoItem().Width(28).Image(image);\n                                    row.RelativeItem().PaddingLeft(8).AlignMiddle().Text(Placeholders.Label());\n                                });\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"image-shared.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void DynamicImage()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(350, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.PageColor(Colors.Grey.Lighten3);\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n\n                            column.Item().Text(text =>\n                            {\n                                text.Span(\"The national flag of Poland\").Bold();\n                                text.Span(\" consists of two horizontal stripes of equal width, the upper one white and the lower one red.\");\n                            });\n                            \n                            column.Item()\n                                .AspectRatio(80 / 50f)\n                                .Border(2)\n                                .Image(GenerateNationalFlagOfPoland);\n                        });\n                    \n                    byte[]? GenerateNationalFlagOfPoland(GenerateDynamicImageDelegatePayload context)\n                    {\n                        using var whitePaint = new SKPaint\n                        {\n                            Color = SKColors.White,\n                        };\n                                    \n                        using var redPaint = new SKPaint\n                        {\n                            Color = SKColor.Parse(\"#BB0A30\"),\n                        };\n\n                        using var bitmap = new SKBitmap(context.ImageSize.Width, context.ImageSize.Height);\n                        using var canvas = new SKCanvas(bitmap);\n                                    \n                        canvas.DrawRect(0, 0, context.ImageSize.Width, context.ImageSize.Height / 2, whitePaint);\n                        canvas.DrawRect(0, context.ImageSize.Height / 2, context.ImageSize.Width, context.ImageSize.Height, redPaint);\n                        canvas.Flush();\n\n                        using var content = bitmap.Encode(SKEncodedImageFormat.Png, 100);\n                        return content.ToArray();\n                    }\n                });\n            })\n            .GenerateImages(x => \"image-dynamic.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void SvgSupport()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(250);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    \n                    var svgContent = File.ReadAllText(\"Resources/pdf-icon.svg\");\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().Text(\"The classic PDF icon looks like this:\").Bold();\n                            column.Item().Height(15);\n                            column.Item().Svg(svgContent);\n                        });\n                });\n            })\n            .GenerateImages(x => \"image-svg.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/InlinedExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class InlinedExamples\n{\n    [Test]\n    public void SimpleExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(450);\n\n                    page.Content()\n                        .Background(Colors.Grey.Lighten3)\n                        .Padding(25)\n                        .Border(1)\n                        .Background(Colors.White)\n                        .Inlined(inlined =>\n                        {\n                            inlined.Spacing(25);\n                            inlined.BaselineMiddle();\n                            inlined.AlignCenter();\n                            \n                            foreach (var _ in Enumerable.Range(0, 15))\n                                inlined.Item().Element(RandomBlock);\n                        });\n                });\n            })\n            .GenerateImages(x => \"inlined.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void SpacingExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(450);\n\n                    page.Content()\n                        .Background(Colors.Grey.Lighten3)\n                        .Padding(25)\n                        .Border(1)\n                        .Background(Colors.White)\n                        .Inlined(inlined =>\n                        {\n                            inlined.VerticalSpacing(15);\n                            inlined.HorizontalSpacing(30);\n                            \n                            foreach (var _ in Enumerable.Range(0, 10))\n                                inlined.Item().Element(RandomBlock);\n                        });\n                });\n            })\n            .GenerateImages(x => \"inlined-spacing.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    private void RandomBlock(IContainer container)\n    {\n        container\n            .Width(Random.Shared.Next(1, 4) * 25)\n            .Height(Random.Shared.Next(1, 4) * 25)\n            .Border(1)\n            .BorderColor(Colors.Grey.Darken2)\n            .Background(Placeholders.BackgroundColor());\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/LayersExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class LayersExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(450);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().PaddingBottom(15).Text(\"Proposed Business Card Design:\").Bold();\n                            \n                            column.Item()\n                                .AspectRatio(4 / 3f)\n                                .Layers(layers =>\n                                {\n                                    layers.Layer().Image(\"Resources/card-background.jpg\").FitUnproportionally();\n\n                                    layers.PrimaryLayer()\n                                        .TranslateY(75)\n                                        .Column(innerColumn =>\n                                        {\n                                            innerColumn.Item()\n                                                .AlignCenter()\n                                                .Text(\"Horizon Ventures\")\n                                                .Bold().FontSize(32).FontColor(Colors.Blue.Darken2);\n\n                                            innerColumn.Item().AlignCenter().Text(\"Your journey begins here\");\n                                        });\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"layers.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/LazyExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class LazyExamples\n{\n    class SimpleComponent : IComponent\n    {\n        public required int Start { get; init; }\n        public required int End { get; init; }\n        \n        public void Compose(IContainer container)\n        {\n            container.Decoration(decoration =>\n            {\n                decoration.Before()\n                    .Text($\"Numbers from {Start} to {End}\")\n                    .FontSize(20).Bold().FontColor(Colors.Blue.Darken2);\n            \n                decoration.Content().Column(column =>\n                {\n                    foreach (var i in Enumerable.Range(Start, End - Start + 1))\n                        column.Item().Text($\"Number {i}\").FontSize(10);\n                });\n            });\n        }\n    }\n\n    [Test]\n    [Ignore(\"This test is for manual testing only.\")]\n    public void Disabled()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(10);\n\n                    page.Content().Column(column =>\n                    {\n                        const int sectionSize = 1000;\n                        \n                        foreach (var i in Enumerable.Range(0, 1000))\n                        {\n                            column.Item().Component(new SimpleComponent\n                            {\n                                Start = i * sectionSize,\n                                End = i * sectionSize + sectionSize - 1\n                            });\n                        }\n                    });\n                });\n            })\n            .GeneratePdf(\"lazy-disabled.pdf\");\n    }\n\n    [Test]\n    [Ignore(\"This test is for manual testing only.\")]\n    public void Enabled()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(10);\n                    page.Content().Column(column =>\n                    {\n                        const int sectionSize = 1000;\n\n                        foreach (var i in Enumerable.Range(0, 1000))\n                        {\n                            var start = i * sectionSize;\n                            var end = start + sectionSize - 1;\n\n                            column.Item().Lazy(c =>\n                            {\n                                c.Component(new SimpleComponent\n                                {\n                                    Start = start,\n                                    End = end\n                                });\n                            });\n                        }\n                    });\n                });\n            })\n            .GeneratePdf(\"lazy-enabled.pdf\");\n    }\n    \n    [Test]\n    [Ignore(\"This test is for manual testing only.\")]\n    public void EnabledWithCache()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Margin(10);\n\n                    page.Content().Column(column =>\n                    {\n                        const int sectionSize = 1000;\n\n                        foreach (var i in Enumerable.Range(0, 1000))\n                        {\n                            var start = i * sectionSize;\n                            var end = start + sectionSize - 1;\n\n                            column.Item().LazyWithCache(c =>\n                            {\n                                c.Component(new SimpleComponent\n                                {\n                                    Start = start,\n                                    End = end\n                                });\n                            });\n                        }\n                    });\n                });\n            })\n            .GeneratePdf(\"lazy-enabled-with-cache.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/LicenseSetup.cs",
    "content": "using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\n[SetUpFixture]\npublic class LicenseSetup\n{\n    [OneTimeSetUp]\n    public static void Setup()\n    {\n        QuestPDF.Settings.License = LicenseType.Community;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/LineExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class LineExamples\n{\n    [Test]\n    public void VerticalLineExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.AutoItem().Text(\"Text on the left\");\n                            \n                            row.AutoItem()\n                                .PaddingHorizontal(15)\n                                .LineVertical(3)\n                                .LineColor(Colors.Blue.Medium);\n                            \n                            row.AutoItem().Text(\"Text on the right\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"line-vertical.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void HorizontalLineExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().Text(\"Text above the line\");\n                            \n                            column.Item()\n                                .PaddingVertical(10)\n                                .LineHorizontal(2)\n                                .LineColor(Colors.Blue.Medium);\n                            \n                            column.Item().Text(\"Text below the line\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"line-horizontal.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Thickness()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(20);\n    \n                            foreach (var thickness in new[] { 1, 2, 4, 8 })\n                            {\n                                column.Item()\n                                    .Width(200)\n                                    .LineHorizontal(thickness);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"line-thickness.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n\n    [Test]\n    public void SolidColor()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            var colors = new[]\n                            {\n                                Colors.Red.Medium,\n                                Colors.Green.Medium,\n                                Colors.Blue.Medium,\n                            };\n                            \n                            column.Spacing(20);\n                \n                            foreach (var color in colors)\n                            {\n                                column.Item()\n                                    .Width(200)\n                                    .LineHorizontal(5)\n                                    .LineColor(color);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"line-color-solid.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Gradient()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(20);\n\n                            column.Item()\n                                .Width(200)\n                                .LineHorizontal(5)\n                                .LineGradient([Colors.Red.Medium, Colors.Orange.Medium]);\n                \n                            column.Item()\n                                .Width(200)\n                                .LineHorizontal(5)\n                                .LineGradient([Colors.Orange.Medium, Colors.Yellow.Medium, Colors.Lime.Medium]);\n                \n                            column.Item()\n                                .Width(200)\n                                .LineHorizontal(5)\n                                .LineGradient([Colors.Blue.Lighten2, Colors.LightBlue.Lighten1, Colors.Cyan.Medium, Colors.Teal.Darken1, Colors.Green.Darken2]);\n                        });\n                });\n            })\n            .GenerateImages(x => \"line-color-gradient.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void DashPattern()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(20);\n\n                            column.Item()\n                                .Width(200)\n                                .LineHorizontal(5)\n                                .LineDashPattern([4f, 4f]);\n                \n                            column.Item()\n                                .Width(200)\n                                .LineHorizontal(5)\n                                .LineDashPattern([12f, 12f]);\n                \n                            column.Item()\n                                .Width(200)\n                                .LineHorizontal(5)\n                                .LineDashPattern([4f, 4f, 12f, 4f]);\n                        });\n                });\n            })\n            .GenerateImages(x => \"line-dash-pattern.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Complex()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Width(300)\n                        .LineHorizontal(8)\n                        .LineDashPattern([4, 4, 8, 8, 12, 12])\n                        .LineGradient([Colors.Red.Medium, Colors.Orange.Medium, Colors.Yellow.Medium]);\n                });\n            })\n            .GenerateImages(x => \"line-example.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ListExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ListExamples\n{\n    [Test]\n    public void BulletpointExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(350, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content() \n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n                            \n                            foreach (var i in Enumerable.Range(1, 7))\n                            {\n                                column.Item().Row(row =>\n                                {\n                                    row.ConstantItem(26).Image(\"Resources/bulletpoint.png\");\n                                    row.ConstantItem(5);\n                                    row.RelativeItem().Text(Placeholders.Label());\n                                });\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"list-unordered.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void OrderedExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content() \n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n                            \n                            foreach (var i in Enumerable.Range(1, 11))\n                            {\n                                column.Item().Row(row =>\n                                {\n                                    row.ConstantItem(35).Text($\"{i}.\");\n                                    row.RelativeItem().Text(Placeholders.Sentence());\n                                });\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"list-ordered.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Nested()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content() \n                        .Column(column =>\n                        {\n                            const float nestingSize = 25;\n                            \n                            column.Spacing(10);\n                            \n                            column.Item()\n                                .Text(\"Algorithm: Checking if a Number is Prime\")\n                                .FontSize(24).FontColor(Colors.Blue.Darken2);\n\n                            AddListItem(0, \"1.\", \"Handle special cases\");\n                            AddListItem(1, \"a)\", \"If n is less than 2, return false (not prime).\");\n                            AddListItem(1, \"b)\", \"If n is 2, return true (prime).\");\n                            \n                            AddListItem(0, \"2.\", \"Check divisibility\");\n                            AddListItem(1, \"-\", \"Iterate through numbers from 2 to n - 1:\");\n                            AddListItem(2, \"-\", \"If n is divisible by any of these numbers, return false.\");\n                            \n                            AddListItem(0, \"3.\", \"Return true (if no divisors were found, n is prime).\");\n\n                            void AddListItem(int nestingLevel, string bulletText, string text)\n                            {\n                                column.Item().Row(row =>\n                                {\n                                    row.ConstantItem(nestingSize * nestingLevel);\n                                    row.ConstantItem(nestingSize).Text(bulletText);\n                                    row.RelativeItem().Text(text);\n                                });\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"list-nested.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/MapExample.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\nstatic class MapboxStaticMapRenderer\n{\n    private const string MapboxBaseUrl = \"https://api.mapbox.com/styles/v1/mapbox/streets-v12/static\";\n    private const string AccessToken = \"pk.eyJ1IjoibWFyY2luLXppYWJlayIsImEiOiJjbTc5cHZkZTUwNmM4MmxxdGN2cnRxMTBpIn0.8G-_nwFqjjfNQUCmHSOqKw\";\n\n    public static async Task<byte[]?> FetchStaticMapAsync(double longitude, double latitude, float zoom, int width, int height)\n    {\n        var longitudeString = longitude.ToString(System.Globalization.CultureInfo.InvariantCulture);\n        var latitudeString = latitude.ToString(System.Globalization.CultureInfo.InvariantCulture);\n        var url = $\"{MapboxBaseUrl}/{longitudeString},{latitudeString},{zoom},0,0/{width}x{height}@2x?access_token={AccessToken}\";\n\n        using var client = new HttpClient();\n        \n        try\n        {\n            var response = await client.GetAsync(url);\n            return await response.Content.ReadAsByteArrayAsync();\n        }\n        catch (Exception ex)\n        {\n            return null;\n        }\n    }\n}\n\n\npublic class MapExample\n{\n    [Test]\n    public async Task SimpleExample()\n    {\n        var map = await MapboxStaticMapRenderer.FetchStaticMapAsync(19.9376052f, 50.0616087f, 10, 500, 400);\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.ContinuousSize(550);\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().Text(\"Map of Kraków\").FontSize(20).Bold();\n                            column.Item().Text(\"Capital of Lesser Poland Voivodeship\").FontSize(16).Light();\n                            column.Item().Height(15);\n\n                            column.Item()\n                                .Background(Colors.Grey.Lighten3)\n                                .ShowIf(map != null)\n                                .Image(map);\n                        });\n                });\n            })\n            .GenerateImages(x => \"map.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/MergingDocumentsExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class MergingDocumentsExamples\n{\n    [Test]\n    public async Task UseOriginalPageNumbersExample()\n    {\n        Document\n            .Merge(\n                GenerateReport(\"Short Document 1\", 5),\n                GenerateReport(\"Medium Document 2\", 10),\n                GenerateReport(\"Long Document 3\", 15))\n            .UseOriginalPageNumbers()\n            .GeneratePdf(\"merged.pdf\");\n    }\n    \n    [Test]\n    public async Task UseContinuousPageNumbersExample()\n    {\n        Document\n            .Merge(\n                GenerateReport(\"Short Document 1\", 5),\n                GenerateReport(\"Medium Document 2\", 10),\n                GenerateReport(\"Long Document 3\", 15))\n            .UseContinuousPageNumbers()\n            .GeneratePdf(\"merged.pdf\");\n    }\n    \n    \n    #region Example document\n\n    private static Document GenerateReport(string title, int itemsCount)\n    {\n        return Document.Create(document =>\n        {\n            document.Page(page =>\n            {\n                page.Size(PageSizes.A5);\n                page.Margin(0.5f, Unit.Inch);\n            \n                page.Header()\n                    .Text(title)\n                    .Bold()\n                    .FontSize(24)\n                    .FontColor(Colors.Blue.Accent2);\n            \n                page.Content()\n                    .PaddingVertical(20)\n                    .Column(column =>\n                    {\n                        column.Spacing(10);\n\n                        foreach (var i in Enumerable.Range(0, itemsCount))\n                        {\n                            column\n                                .Item()\n                                .Width(200)\n                                .Height(50)\n                                .Background(Colors.Grey.Lighten3)\n                                .AlignMiddle()\n                                .AlignCenter()\n                                .Text($\"Item {i}\")\n                                .FontSize(16);\n                        }\n                    });\n            \n                page.Footer()\n                    .AlignCenter()\n                    .PaddingVertical(20)\n                    .Text(text =>\n                    {\n                        text.DefaultTextStyle(TextStyle.Default.FontSize(16));\n                    \n                        text.CurrentPageNumber();\n                        text.Span(\" / \");\n                        text.TotalPages();\n                    });\n            });\n        });\n    }\n\n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/MultiColumnExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class MultiColumnExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(650, 0));\n                    page.MaxSize(new PageSize(650, 650));\n                    page.DefaultTextStyle(x => x.FontSize(12));\n                    page.Margin(25);\n\n                    page.Content()\n                        .MultiColumn(multiColumn =>\n                        {\n                            multiColumn.Columns(3);\n                            multiColumn.Spacing(25);\n    \n                            multiColumn\n                                .Content()\n                                .Column(column =>\n                                {\n                                    column.Spacing(15);\n\n                                    foreach (var sectionId in Enumerable.Range(0, 3))\n                                    {\n                                        foreach (var textId in Enumerable.Range(0, 3))\n                                            column.Item().Text(Placeholders.Paragraph()).Justify();\n\n                                        column.Item().AspectRatio(21 / 9f).Image(Placeholders.Image);\n                                    }\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"multicolumn-example.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.High, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void SpacerExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(450, 0));\n                    page.MaxSize(new PageSize(450, 550));\n                    page.DefaultTextStyle(x => x.FontSize(12));\n                    page.Margin(25);\n\n                    page.Content()\n                        .MultiColumn(multiColumn =>\n                        {\n                            multiColumn.Columns(2);\n                            multiColumn.Spacing(50);\n    \n                            multiColumn\n                                .Spacer()\n                                .AlignCenter()\n                                .LineVertical(2)\n                                .LineColor(Colors.Grey.Medium);\n                            \n                            multiColumn\n                                .Content()\n                                .Column(column =>\n                                {\n                                    column.Spacing(15);\n\n                                    foreach (var textId in Enumerable.Range(0, 5))\n                                        column.Item().Text(Placeholders.Paragraph()).Justify();\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"multicolumn-spacer.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.High, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void BalanceHeightWithExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A4);\n                    page.DefaultTextStyle(x => x.FontSize(14));\n                    page.Margin(30);\n\n                    page.Content()\n                        .MultiColumn(multiColumn =>\n                        {\n                            multiColumn.Spacing(30);\n                            multiColumn.BalanceHeight();\n\n                            multiColumn\n                                .Content()\n                                .Column(column =>\n                                {\n                                    column.Spacing(15);\n                                    \n                                    foreach (var textId in Enumerable.Range(0, 8))\n                                        column.Item().Text(Placeholders.Paragraph()).Justify();\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"multicolumn-balance-height-with.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.High, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/PaddingExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class PaddingExamples\n{\n    [Test]\n    public void SimpleExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(250)\n                        .PaddingVertical(10)\n                        .PaddingLeft(20)\n                        .PaddingRight(40)\n                        .Background(Colors.Grey.Lighten2)\n                        .Text(\"Sample text\");\n                });\n            })\n            .GenerateImages(x => \"padding-simple.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void NegativeExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(250)\n                        .Padding(50)\n                        .Background(Colors.Grey.Lighten2)\n                        .PaddingHorizontal(-25)\n                        .Text(\"Sample text with negative padding\");\n                });\n            })\n            .GenerateImages(x => \"padding-negative.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/PageBreakExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class PageBreakExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(300, 450);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .PaddingTop(15)\n                        .Column(column =>\n                        {\n                            var terms = new[]\n                            {\n                                (\"Garbage Collection\", \"An automatic memory management feature in many programming languages that identifies and removes unused objects to free up memory, preventing memory leaks.\"),\n                                (\"Constructor\", \"A special method in object-oriented programming that is automatically called when an object is created. It initializes the object's properties and sets up any necessary resources.\"),\n                                (\"Dependency\", \"A software component or external library that a program relies on to function correctly. Dependencies can include third-party modules, frameworks, or system-level packages that provide additional functionality without requiring developers to write everything from scratch.\")\n                            };\n                            \n                            column.Item()\n                                .Extend()\n                                .AlignCenter().AlignMiddle()\n                                .Text(\"Programming dictionary\").FontSize(24).Bold();\n                            \n                            foreach (var term in terms)\n                            {\n                                column.Item().PageBreak();\n                                column.Item().Element(c => GeneratePage(c, term.Item1, term.Item2));\n                            }\n\n                            static void GeneratePage(IContainer container, string term, string definition)\n                            {\n                                container.Text(text =>\n                                {\n                                    text.Span(term).Bold().FontColor(Colors.Blue.Darken2);\n                                    text.Span($\" - {definition}\");\n                                });\n                            }\n                        });\n                });\n            })\n            .GeneratePdf(\"page-break.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/PageExamples.cs",
    "content": "using QuestPDF.Companion;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class PageExamples\n{\n    [Test]\n    public void Simple()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.Margin(2, Unit.Centimetre);\n                    page.DefaultTextStyle(x => x.FontSize(24));\n\n                    page.Header()\n                        .Text(\"Hello, World!\")\n                        .FontSize(48).Bold();\n\n                    page.Content()\n                        .PaddingVertical(25)\n                        .Text(Placeholders.LoremIpsum())\n                        .Justify();\n        \n                    page.Footer()\n                        .AlignCenter() \n                        .Text(text =>\n                        {\n                            text.CurrentPageNumber();\n                            text.Span(\" / \");\n                            text.TotalPages();\n                        });\n                });\n            })\n            .GenerateImages(x => \"page-simple.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void MainSlots()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A4);\n                    page.Margin(2, Unit.Centimetre);\n                    page.DefaultTextStyle(x => x.FontSize(24));\n\n                    page.Header()\n                        .Background(Colors.Grey.Lighten1)\n                        .Height(125)\n                        .AlignCenter()\n                        .AlignMiddle()\n                        .Text(\"Header\");\n                    \n                    page.Content()\n                        .Background(Colors.Grey.Lighten2)\n                        .AlignCenter()\n                        .AlignMiddle()\n                        .Text(\"Content\");\n                    \n                    page.Footer()\n                        .Background(Colors.Grey.Lighten1)\n                        .Height(75)\n                        .AlignCenter()\n                        .AlignMiddle()\n                        .Text(\"Footer\");\n                });\n            })\n            .GenerateImages(x => \"page-main-slots.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Foreground()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A4);\n                    page.Margin(2, Unit.Centimetre);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Header()\n                        .PaddingBottom(1, Unit.Centimetre)\n                        .Text(\"Report\")\n                        .FontSize(30)\n                        .Bold();\n                    \n                    page.Content()\n                        .Text(Placeholders.Paragraphs())\n                        .ParagraphSpacing(1, Unit.Centimetre)\n                        .Justify();\n \n                    page.Foreground().Svg(\"Resources/draft-foreground.svg\").FitArea();\n                });\n            })\n            .GenerateImages(x => \"page-foreground.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.High, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Background()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                { \n                    page.Size(PageSizes.A4.Landscape());\n\n                    page.Background().Svg(\"Resources/certificate-background.svg\").FitArea();\n\n                    page.Content() \n                        .PaddingLeft(10, Unit.Centimetre)\n                        .PaddingRight(5 , Unit.Centimetre)\n                        .AlignMiddle()\n                        .Column(column =>\n                        {\n                            column.Item().Height(50).Svg(\"Resources/questpdf-logo.svg\");\n                            \n                            column.Item().Height(50);\n                            \n                            column.Item().Text(\"CERTIFICATE\").FontSize(64).ExtraBlack();\n                            \n                            column.Item().Height(25);\n                            \n                            column.Item()\n                                .Shrink().BorderBottom(1).Padding(10)\n                                .Text(\"Marcin Ziąbek\").FontSize(32).Italic();\n                            \n                            column.Item().Height(10); \n                            \n                            column.Item()\n                                .Text($\"has successfully completed the course \\\"QuestPDF Basics\\\" on {DateTime.Now:dd MMM yyyy}.\")\n                                .FontSize(20).Light();\n                        });\n                });\n            })\n            .GenerateImages(x => $\"page-background.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/PlaceholderExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class PlaceholderExamples\n{\n    [Test]\n    public void TextExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(15);\n\n                            AddItem(\"Name\", Placeholders.Name());\n                            AddItem(\"Email\", Placeholders.Email());\n                            AddItem(\"Phone\", Placeholders.PhoneNumber());\n                            AddItem(\"Date\", Placeholders.ShortDate());\n                            AddItem(\"Time\", Placeholders.Time());\n                            \n                            void AddItem(string label, string value)\n                            {\n                                column.Item().Text(text =>\n                                {\n                                    text.Span($\"{label}: \").Bold();\n                                    text.Span(value);\n                                });\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"placeholders-text.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void BackgroundColorExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(320, 0));\n                    page.MaxSize(new PageSize(320, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Grid(grid =>\n                        {\n                            grid.Columns(5);\n                            grid.Spacing(5);\n    \n                            foreach (var _ in Enumerable.Range(0, 25))\n                            {\n                                grid.Item()\n                                    .Height(50)\n                                    .Width(50)\n                                    .Background(Placeholders.BackgroundColor());\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"placeholders-color-background.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void ColorExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n                            \n                            foreach (var i in Enumerable.Range(0, 5))\n                            {\n                                column.Item()\n                                    .Text(Placeholders.Sentence())\n                                    .FontColor(Placeholders.Color());\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"placeholders-color.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void ImageExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Width(200)\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n\n                            // provide an exact image resolution\n                            column.Item()\n                                .Image(Placeholders.Image(100, 50));\n                            \n                            // specify physical width and height of the image\n                            column.Item()\n                                .Width(200)\n                                .Height(150)\n                                .Image(Placeholders.Image);\n                            \n                            // specify target physical width and aspect ratio\n                            column.Item()\n                                .Width(200)\n                                .AspectRatio(3 / 2f)\n                                .Image(Placeholders.Image);\n                        });\n                });\n            })\n            .GenerateImages(x => \"placeholders-image.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void ElementExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Header()\n                        .Height(100)\n                        .Placeholder(\"Header\");\n                    \n                    page.Content()\n                        .PaddingVertical(25)\n                        .Placeholder();\n                    \n                    page.Footer()\n                        .Height(100)\n                        .Placeholder(\"Footer\");\n                });\n            })\n            .GenerateImages(x => \"placeholder-element.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.High, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/PreventPageBreakExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class PreventPageBreakExamples\n{\n    [Test]\n    public void EnabledExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(30);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().Height(400).Background(Colors.Grey.Lighten3);\n                            column.Item().Height(30);\n\n                            column.Item()\n                                .PreventPageBreak()\n                                .Text(text =>\n                                {\n                                    text.ParagraphSpacing(15);\n                                    \n                                    text.Span(\"Optimizing Content Placement\").Bold().FontColor(Colors.Blue.Darken2).FontSize(24);\n                                    text.Span(\"\\n\");\n                                    text.Span(\"By carefully determining where to place a page break, you can avoid awkward text separations and maintain readability. Thoughtful formatting improves the overall user experience, making complex topics easier to digest.\");\n                                });\n                        }); \n                });\n            })\n            .GeneratePdf(\"prevent-page-break-enabled.pdf\");\n    }\n    \n    [Test]\n    public void DisabledExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(30);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Item().Height(400).Background(Colors.Grey.Lighten3);\n                            column.Item().Height(30);\n\n                            column.Item()\n                                .Text(text =>\n                                {\n                                    text.ParagraphSpacing(15);\n                                    \n                                    text.Span(\"Optimizing Content Placement\").Bold().FontColor(Colors.Blue.Darken2).FontSize(24);\n                                    text.Span(\"\\n\");\n                                    text.Span(\"By carefully determining where to place a page break, you can avoid awkward text separations and maintain readability. Thoughtful formatting improves the overall user experience, making complex topics easier to digest.\");\n                                });\n                        });\n                });\n            })\n            .GeneratePdf(\"prevent-page-break-disabled.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/QuestPDF.DocumentationExamples.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <ImplicitUsings>enable</ImplicitUsings>\n        <Nullable>enable</Nullable>\n        <SatelliteResourceLanguages>en</SatelliteResourceLanguages>\n\n        <IsPackable>false</IsPackable>\n        <IsTestProject>true</IsTestProject>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.13.0\" />\n        <PackageReference Include=\"NUnit\" Version=\"4.4.0\" />\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"4.11.2\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"6.1.0\" />\n        <PackageReference Include=\"ScottPlot\" Version=\"5.1.57\" />\n        <PackageReference Include=\"SkiaSharp\" Version=\"3.119.1\" />\n        <PackageReference Include=\"SkiaSharp.NativeAssets.Linux.NoDependencies\" Version=\"3.119.1\" />\n        <PackageReference Include=\"ZXing.Net\" Version=\"0.16.11\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <Using Include=\"NUnit.Framework\"/>\n    </ItemGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\QuestPDF\\QuestPDF.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <None Include=\"Resources\\**\\*.*\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n        </None>\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/RepeatExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class RepeatExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(600, 0));\n                    page.MaxSize(new PageSize(600, 600));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Decoration(decoration =>\n                        {\n                            var terms = new[]\n                            {\n                                (\"Algorithm\", \"A precise set of instructions that defines a process for solving a specific problem or performing a computation. Algorithms are the foundation of programming and are used to optimize tasks efficiently.\"),\n                                (\"Bug\", \"An error, flaw, or unintended behavior in a program that causes it to produce incorrect or unexpected results. Debugging is the process of identifying, analyzing, and fixing these issues to improve software reliability.\"),\n                                (\"Variable\", \"A named storage location in memory that holds a value, which can be modified during program execution. Variables make code dynamic and flexible by allowing data manipulation and retrieval.\"),\n                                (\"Compilation\", \"The process of transforming human-readable source code into machine code (binary instructions) that a computer can execute. This process is performed by a compiler and often includes syntax checks, optimizations, and linking dependencies.\")\n                            };\n                            \n                            decoration.Before().Text(\"Terms and their definitions:\").Bold();\n                            \n                            decoration.Content().PaddingTop(15).Column(column =>\n                            {\n                                foreach (var term in terms)\n                                {\n                                    column.Item().Row(row =>\n                                    {\n                                        row.RelativeItem(2)\n                                            .Border(1)\n                                            .Background(Colors.Grey.Lighten3)\n                                            .Padding(15)\n                                            .Repeat()\n                                            .Text(term.Item1);\n                                    \n                                        row.RelativeItem(3)\n                                            .Border(1)\n                                            .Padding(15)\n                                            .Text(term.Item2);\n                                    });\n                                }\n                            });\n                        });\n                });\n            })\n            .GenerateImages(x => $\"repeat-with-{x}.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/Resources/semantic-book-content.json",
    "content": "[\n  {\n    \"term\": \"Variable\",\n    \"description\": \"A storage location paired with an associated symbolic name, which contains some known or unknown quantity of information referred to as a value.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Data Types\",\n    \"thirdLevelCategory\": \"Primitives\"\n  },\n  {\n    \"term\": \"Function\",\n    \"description\": \"A block of reusable code that performs a specific task and can be called by name.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Control Flow\",\n    \"thirdLevelCategory\": \"Subroutines\"\n  },\n  {\n    \"term\": \"If-Else Statement\",\n    \"description\": \"A conditional statement that executes a block of code if a specified condition is true, and another block if it is false.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Control Flow\",\n    \"thirdLevelCategory\": \"Conditionals\"\n  },\n  {\n    \"term\": \"For Loop\",\n    \"description\": \"A control flow statement for specifying iteration, which allows code to be executed repeatedly.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Control Flow\",\n    \"thirdLevelCategory\": \"Loops\"\n  },\n  {\n    \"term\": \"Integer\",\n    \"description\": \"A data type that represents a whole number, without a fractional component.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Data Types\",\n    \"thirdLevelCategory\": \"Primitives\"\n  },\n  {\n    \"term\": \"String\",\n    \"description\": \"A data type representing a sequence of characters.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Data Types\",\n    \"thirdLevelCategory\": \"Primitives\"\n  },\n  {\n    \"term\": \"Boolean\",\n    \"description\": \"A data type with only two possible values: true or false.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Data Types\",\n    \"thirdLevelCategory\": \"Primitives\"\n  },\n  {\n    \"term\": \"Array\",\n    \"description\": \"A data structure consisting of a collection of elements, each identified by at least one array index or key.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Data Structures\",\n    \"thirdLevelCategory\": \"Linear\"\n  },\n  {\n    \"term\": \"Object\",\n    \"description\": \"A data structure that contains data in the form of key-value pairs.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Data Types\",\n    \"thirdLevelCategory\": \"Composite\"\n  },\n  {\n    \"term\": \"Null\",\n    \"description\": \"A special value representing the intentional absence of any object value.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Data Types\",\n    \"thirdLevelCategory\": \"Primitives\"\n  },\n  {\n    \"term\": \"Class\",\n    \"description\": \"A blueprint for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions).\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Object-Oriented\",\n    \"thirdLevelCategory\": \"Core Constructs\"\n  },\n  {\n    \"term\": \"Inheritance\",\n    \"description\": \"A mechanism where a new class derives properties and behavior from an existing class.\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Object-Oriented\",\n    \"thirdLevelCategory\": \"Principles\"\n  },\n  {\n    \"term\": \"Polymorphism\",\n    \"description\": \"The provision of a single interface to entities of different types, allowing objects to be treated as instances of their parent class.\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Object-Oriented\",\n    \"thirdLevelCategory\": \"Principles\"\n  },\n  {\n    \"term\": \"Encapsulation\",\n    \"description\": \"The bundling of data with the methods that operate on that data, or the restricting of direct access to some of an object's components.\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Object-Oriented\",\n    \"thirdLevelCategory\": \"Principles\"\n  },\n  {\n    \"term\": \"Abstraction\",\n    \"description\": \"The concept of hiding the complex reality while exposing only the necessary parts.\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Object-Oriented\",\n    \"thirdLevelCategory\": \"Principles\"\n  },\n  {\n    \"term\": \"Algorithm\",\n    \"description\": \"A finite sequence of well-defined, computer-implementable instructions to solve a class of problems.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Algorithms\",\n    \"thirdLevelCategory\": \"Fundamentals\"\n  },\n  {\n    \"term\": \"Linked List\",\n    \"description\": \"A linear collection of data elements whose order is not given by their physical placement in memory. Each element points to the next.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Data Structures\",\n    \"thirdLevelCategory\": \"Linear\"\n  },\n  {\n    \"term\": \"Stack\",\n    \"description\": \"A linear data structure that follows the Last-In, First-Out (LIFO) principle.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Data Structures\",\n    \"thirdLevelCategory\": \"Linear\"\n  },\n  {\n    \"term\": \"Queue\",\n    \"description\": \"A linear data structure that follows the First-In, First-Out (FIFO) principle.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Data Structures\",\n    \"thirdLevelCategory\": \"Linear\"\n  },\n  {\n    \"term\": \"Tree\",\n    \"description\": \"A hierarchical data structure with a root value and subtrees of children with a parent node, represented as a set of linked nodes.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Data Structures\",\n    \"thirdLevelCategory\": \"Non-Linear\"\n  },\n  {\n    \"term\": \"Graph\",\n    \"description\": \"A data structure consisting of a set of vertices (or nodes) and a set of edges that connect these vertices.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Data Structures\",\n    \"thirdLevelCategory\": \"Non-Linear\"\n  },\n  {\n    \"term\": \"Hash Table\",\n    \"description\": \"A data structure that implements an associative array abstract data type, a structure that can map keys to values.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Data Structures\",\n    \"thirdLevelCategory\": \"Key-Value\"\n  },\n  {\n    \"term\": \"Binary Search\",\n    \"description\": \"A search algorithm that finds the position of a target value within a sorted array.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Algorithms\",\n    \"thirdLevelCategory\": \"Searching\"\n  },\n  {\n    \"term\": \"Bubble Sort\",\n    \"description\": \"A simple sorting algorithm that repeatedly steps through the list, compares adjacent elements and swaps them if they are in the wrong order.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Algorithms\",\n    \"thirdLevelCategory\": \"Sorting\"\n  },\n  {\n    \"term\": \"Merge Sort\",\n    \"description\": \"An efficient, comparison-based, divide and conquer sorting algorithm.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Algorithms\",\n    \"thirdLevelCategory\": \"Sorting\"\n  },\n  {\n    \"term\": \"Big O Notation\",\n    \"description\": \"A mathematical notation that describes the limiting behavior of a function when the argument tends towards a particular value or infinity, used to classify algorithms according to their running time or space requirements.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Complexity\",\n    \"thirdLevelCategory\": \"Asymptotic Analysis\"\n  },\n  {\n    \"term\": \"Recursion\",\n    \"description\": \"A method of solving a problem where the solution depends on solutions to smaller instances of the same problem.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Control Flow\",\n    \"thirdLevelCategory\": \"Subroutines\"\n  },\n  {\n    \"term\": \"API (Application Programming Interface)\",\n    \"description\": \"A set of rules and protocols for building and interacting with software applications.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Architecture\",\n    \"thirdLevelCategory\": \"Integration\"\n  },\n  {\n    \"term\": \"REST (Representational State Transfer)\",\n    \"description\": \"An architectural style for designing networked applications, often used for creating web services.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Architecture\",\n    \"thirdLevelCategory\": \"Integration\"\n  },\n  {\n    \"term\": \"HTTP (Hypertext Transfer Protocol)\",\n    \"description\": \"The foundation of data communication for the World Wide Web.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Protocols\",\n    \"thirdLevelCategory\": \"Communication\"\n  },\n  {\n    \"term\": \"JSON (JavaScript Object Notation)\",\n    \"description\": \"A lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Data Formats\",\n    \"thirdLevelCategory\": \"Serialization\"\n  },\n  {\n    \"term\": \"HTML (Hypertext Markup Language)\",\n    \"description\": \"The standard markup language for documents designed to be displayed in a web browser.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Frontend\",\n    \"thirdLevelCategory\": \"Markup\"\n  },\n  {\n    \"term\": \"CSS (Cascading Style Sheets)\",\n    \"description\": \"A style sheet language used for describing the presentation of a document written in a markup language like HTML.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Frontend\",\n    \"thirdLevelCategory\": \"Styling\"\n  },\n  {\n    \"term\": \"JavaScript\",\n    \"description\": \"A high-level, interpreted programming language that conforms to the ECMAScript specification, primarily used for web development.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Frontend\",\n    \"thirdLevelCategory\": \"Scripting\"\n  },\n  {\n    \"term\": \"DOM (Document Object Model)\",\n    \"description\": \"A programming interface for HTML and XML documents. It represents the page so that programs can change the document structure, style, and content.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Frontend\",\n    \"thirdLevelCategory\": \"APIs\"\n  },\n  {\n    \"term\": \"Frontend\",\n    \"description\": \"The part of a website or application that the user interacts with directly; also known as client-side.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"General Concepts\",\n    \"thirdLevelCategory\": \"Client-Side\"\n  },\n  {\n    \"term\": \"Backend\",\n    \"description\": \"The server-side of a website or application, responsible for storing and organizing data and ensuring everything on the client-side works.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"General Concepts\",\n    \"thirdLevelCategory\": \"Server-Side\"\n  },\n  {\n    \"term\": \"Database\",\n    \"description\": \"An organized collection of data, generally stored and accessed electronically from a computer system.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Data Storage\",\n    \"thirdLevelCategory\": \"Systems\"\n  },\n  {\n    \"term\": \"SQL (Structured Query Language)\",\n    \"description\": \"A domain-specific language used in programming and designed for managing data held in a relational database management system.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Data Storage\",\n    \"thirdLevelCategory\": \"Query Languages\"\n  },\n  {\n    \"term\": \"NoSQL\",\n    \"description\": \"A database that provides a mechanism for storage and retrieval of data that is modeled in means other than the tabular relations used in relational databases.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Data Storage\",\n    \"thirdLevelCategory\": \"Systems\"\n  },\n  {\n    \"term\": \"Git\",\n    \"description\": \"A distributed version-control system for tracking changes in source code during software development.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Version Control\",\n    \"thirdLevelCategory\": \"Systems\"\n  },\n  {\n    \"term\": \"Commit\",\n    \"description\": \"An operation in version control which saves the current state of changes to the local repository.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Version Control\",\n    \"thirdLevelCategory\": \"Operations\"\n  },\n  {\n    \"term\": \"Branch\",\n    \"description\": \"A parallel version of a repository in version control, allowing for independent development without affecting the main line.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Version Control\",\n    \"thirdLevelCategory\": \"Concepts\"\n  },\n  {\n    \"term\": \"Merge\",\n    \"description\": \"An operation in version control that integrates changes from different branches into a single branch.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Version Control\",\n    \"thirdLevelCategory\": \"Operations\"\n  },\n  {\n    \"term\": \"Repository\",\n    \"description\": \"A central location in which data is stored and managed, commonly used for source code.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Version Control\",\n    \"thirdLevelCategory\": \"Concepts\"\n  },\n  {\n    \"term\": \"Compiler\",\n    \"description\": \"A special program that processes statements written in a particular programming language and turns them into machine language or 'code' that a computer's processor uses.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Language Processors\",\n    \"thirdLevelCategory\": \"Translation\"\n  },\n  {\n    \"term\": \"Interpreter\",\n    \"description\": \"A computer program that directly executes instructions written in a programming or scripting language, without requiring them to have been previously compiled into a machine language program.\",\n    \"firstLevelCategory\": \"Tools &Technologies\",\n    \"secondLevelCategory\": \"Language Processors\",\n    \"thirdLevelCategory\": \"Execution\"\n  },\n  {\n    \"term\": \"IDE (Integrated Development Environment)\",\n    \"description\": \"A software application that provides comprehensive facilities to computer programmers for software development.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Development Tools\",\n    \"thirdLevelCategory\": \"Editors\"\n  },\n  {\n    \"term\": \"Debugger\",\n    \"description\": \"A computer program used to test and find bugs (errors) in other programs.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Development Tools\",\n    \"thirdLevelCategory\": \"Testing\"\n  },\n  {\n    \"term\": \"Library\",\n    \"description\": \"A collection of non-volatile resources used by computer programs, often for software development.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Code Reusability\",\n    \"thirdLevelCategory\": \"Collections\"\n  },\n  {\n    \"term\": \"Framework\",\n    \"description\": \"A pre-written, structured body of code that provides a standard way to build and deploy applications.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Code Reusability\",\n    \"thirdLevelCategory\": \"Scaffolding\"\n  },\n  {\n    \"term\": \"Agile\",\n    \"description\": \"A set of practices for software development under which requirements and solutions evolve through the collaborative effort of self-organizing cross-functional teams.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Methodologies\",\n    \"thirdLevelCategory\": \"Iterative\"\n  },\n  {\n    \"term\": \"Scrum\",\n    \"description\": \"An agile framework for managing knowledge work, with an emphasis on software development.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Methodologies\",\n    \"thirdLevelCategory\": \"Frameworks\"\n  },\n  {\n    \"term\": \"Waterfall Model\",\n    \"description\": \"A sequential design process in which progress is seen as flowing steadily downwards (like a waterfall) through the phases of conception, initiation, analysis, design, construction, testing, deployment and maintenance.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Methodologies\",\n    \"thirdLevelCategory\": \"Sequential\"\n  },\n  {\n    \"term\": \"Unit Testing\",\n    \"description\": \"A level of software testing where individual units or components of a software are tested.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Testing\",\n    \"thirdLevelCategory\": \"Levels\"\n  },\n  {\n    \"term\": \"Integration Testing\",\n    \"description\": \"A level of software testing where individual units are combined and tested as a group.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Testing\",\n    \"thirdLevelCategory\": \"Levels\"\n  },\n  {\n    \"term\": \"CI/CD (Continuous Integration/Continuous Deployment)\",\n    \"description\": \"The combined practices of continuous integration and either continuous delivery or continuous deployment, aimed at frequent and reliable software releases.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"DevOps\",\n    \"thirdLevelCategory\": \"Automation\"\n  },\n  {\n    \"term\": \"DevOps\",\n    \"description\": \"A set of practices that combines software development (Dev) and IT operations (Ops) to shorten the systems development life cycle and provide continuous delivery with high software quality.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"DevOps\",\n    \"thirdLevelCategory\": \"Culture\"\n  },\n  {\n    \"term\": \"Syntax\",\n    \"description\": \"The set of rules that defines the combinations of symbols that are considered to be correctly structured statements or expressions in a language.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Language Fundamentals\",\n    \"thirdLevelCategory\": \"Grammar\"\n  },\n  {\n    \"term\": \"Semantics\",\n    \"description\": \"The meaning of a programming language's statements.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Language Fundamentals\",\n    \"thirdLevelCategory\": \"Meaning\"\n  },\n  {\n    \"term\": \"Functional Programming\",\n    \"description\": \"A programming paradigm where programs are constructed by applying and composing functions.\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Functional\",\n    \"thirdLevelCategory\": \"Core Concepts\"\n  },\n  {\n    \"term\": \"Pure Function\",\n    \"description\": \"A function whose return value is only determined by its input values, without observable side effects.\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Functional\",\n    \"thirdLevelCategory\": \"Principles\"\n  },\n  {\n    \"term\": \"Immutability\",\n    \"description\": \"A principle where an object's state cannot be modified after it is created.\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Functional\",\n    \"thirdLevelCategory\": \"Principles\"\n  },\n  {\n    \"term\": \"Higher-Order Function\",\n    \"description\": \"A function that either takes one or more functions as arguments or returns a function as its result.\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Functional\",\n    \"thirdLevelCategory\": \"Core Concepts\"\n  },\n  {\n    \"term\": \"Asynchronous\",\n    \"description\": \"Operations that allow a program to start a potentially long-running task and still be able to be responsive to other events while that task runs.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Execution Model\",\n    \"thirdLevelCategory\": \"Concurrency\"\n  },\n  {\n    \"term\": \"Promise\",\n    \"description\": \"An object representing the eventual completion or failure of an asynchronous operation.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Execution Model\",\n    \"thirdLevelCategory\": \"Concurrency\"\n  },\n  {\n    \"term\": \"Thread\",\n    \"description\": \"The smallest sequence of programmed instructions that can be managed independently by a scheduler.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Execution Model\",\n    \"thirdLevelCategory\": \"Parallelism\"\n  },\n  {\n    \"term\": \"Garbage Collection\",\n    \"description\": \"A form of automatic memory management that attempts to reclaim memory occupied by objects that are no longer in use by the program.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Memory Management\",\n    \"thirdLevelCategory\": \"Automatic\"\n  },\n  {\n    \"term\": \"Pointer\",\n    \"description\": \"A variable whose value is the memory address of another variable.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Memory Management\",\n    \"thirdLevelCategory\": \"Manual\"\n  },\n  {\n    \"term\": \"SDK (Software Development Kit)\",\n    \"description\": \"A collection of software development tools in one installable package.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Development Tools\",\n    \"thirdLevelCategory\": \"Tooling\"\n  },\n  {\n    \"term\": \"Node.js\",\n    \"description\": \"A JavaScript runtime built on Chrome's V8 JavaScript engine, used for building server-side applications.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Backend\",\n    \"thirdLevelCategory\": \"Runtimes\"\n  },\n  {\n    \"term\": \"React\",\n    \"description\": \"A JavaScript library for building user interfaces, particularly for single-page applications.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Frontend\",\n    \"thirdLevelCategory\": \"Libraries\"\n  },\n  {\n    \"term\": \"Angular\",\n    \"description\": \"A platform and framework for building single-page client applications using HTML and TypeScript.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Frontend\",\n    \"thirdLevelCategory\": \"Frameworks\"\n  },\n  {\n    \"term\": \"Vue.js\",\n    \"description\": \"A progressive framework for building user interfaces.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Frontend\",\n    \"thirdLevelCategory\": \"Frameworks\"\n  },\n  {\n    \"term\": \"Docker\",\n    \"description\": \"A set of platform-as-a-service products that use OS-level virtualization to deliver software in packages called containers.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Deployment\",\n    \"thirdLevelCategory\": \"Containerization\"\n  },\n  {\n    \"term\": \"Kubernetes\",\n    \"description\": \"An open-source container-orchestration system for automating computer application deployment, scaling, and management.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Deployment\",\n    \"thirdLevelCategory\": \"Orchestration\"\n  },\n  {\n    \"term\": \"Microservices\",\n    \"description\": \"An architectural style that structures an application as a collection of loosely coupled services.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Architecture\",\n    \"thirdLevelCategory\": \"Design Patterns\"\n  },\n  {\n    \"term\": \"Monolithic Architecture\",\n    \"description\": \"An architectural style where an application is built as a single, indivisible unit.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Architecture\",\n    \"thirdLevelCategory\": \"Design Patterns\"\n  },\n  {\n    \"term\": \"Cookie\",\n    \"description\": \"A small piece of data sent from a website and stored on the user's computer by the user's web browser while the user is browsing.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Protocols\",\n    \"thirdLevelCategory\": \"State Management\"\n  },\n  {\n    \"term\": \"Session\",\n    \"description\": \"A way to store information (in variables) to be used across multiple pages on a server.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Protocols\",\n    \"thirdLevelCategory\": \"State Management\"\n  },\n  {\n    \"term\": \"Cache\",\n    \"description\": \"A hardware or software component that stores data so that future requests for that data can be served faster.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Performance\",\n    \"thirdLevelCategory\": \"Optimization\"\n  },\n  {\n    \"term\": \"Time Complexity\",\n    \"description\": \"The computational complexity that describes the amount of computer time it takes to run an algorithm.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Complexity\",\n    \"thirdLevelCategory\": \"Performance\"\n  },\n  {\n    \"term\": \"Space Complexity\",\n    \"description\": \"The amount of memory space required to solve an instance of the computational problem as a function of the input size.\",\n    \"firstLevelCategory\": \"Data Structures & Algorithms\",\n    \"secondLevelCategory\": \"Complexity\",\n    \"thirdLevelCategory\": \"Memory\"\n  },\n  {\n    \"term\": \"Procedural Programming\",\n    \"description\": \"A programming paradigm based upon the concept of procedure calls, where statements are structured into procedures (or subroutines).\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Procedural\",\n    \"thirdLevelCategory\": \"Core Concepts\"\n  },\n  {\n    \"term\": \"Operator\",\n    \"description\": \"A symbol that tells the compiler or interpreter to perform specific mathematical, relational, or logical operations.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Language Fundamentals\",\n    \"thirdLevelCategory\": \"Expressions\"\n  },\n  {\n    \"term\": \"Expression\",\n    \"description\": \"A combination of one or more constants, variables, operators, and functions that the programming language interprets and computes to produce another value.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Language Fundamentals\",\n    \"thirdLevelCategory\": \"Expressions\"\n  },\n  {\n    \"term\": \"Deployment\",\n    \"description\": \"The process of making a software system available for use.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Deployment\",\n    \"thirdLevelCategory\": \"Process\"\n  },\n  {\n    \"term\": \"Middleware\",\n    \"description\": \"Software that lies between an operating system and the applications running on it, enabling communication and data management.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Backend\",\n    \"thirdLevelCategory\": \"Architecture\"\n  },\n  {\n    \"term\": \"Endpoint\",\n    \"description\": \"One end of a communication channel. When an API interacts with another system, the touchpoints of this communication are considered endpoints.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Architecture\",\n    \"thirdLevelCategory\": \"Integration\"\n  },\n  {\n    \"term\": \"Type System\",\n    \"description\": \"A set of rules that assigns a property called type to the various constructs of a computer program.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Data Types\",\n    \"thirdLevelCategory\": \"Typing\"\n  },\n  {\n    \"term\": \"Static Typing\",\n    \"description\": \"Type checking is performed during compile-time.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Data Types\",\n    \"thirdLevelCategory\": \"Typing\"\n  },\n  {\n    \"term\": \"Dynamic Typing\",\n    \"description\": \"Type checking is performed at run-time.\",\n    \"firstLevelCategory\": \"Core Concepts\",\n    \"secondLevelCategory\": \"Data Types\",\n    \"thirdLevelCategory\": \"Typing\"\n  },\n  {\n    \"term\": \"Lambda Function\",\n    \"description\": \"An anonymous function that can be defined without being bound to an identifier.\",\n    \"firstLevelCategory\": \"Programming Paradigms\",\n    \"secondLevelCategory\": \"Functional\",\n    \"thirdLevelCategory\": \"Core Concepts\"\n  },\n  {\n    \"term\": \"Environment Variable\",\n    \"description\": \"A variable whose value is set outside the program, typically through functionality built into the operating system or microservice.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Configuration\",\n    \"thirdLevelCategory\": \"Runtime\"\n  },\n  {\n    \"term\": \"CLI (Command-Line Interface)\",\n    \"description\": \"A text-based user interface used to view and manage computer files.\",\n    \"firstLevelCategory\": \"Tools & Technologies\",\n    \"secondLevelCategory\": \"Interfaces\",\n    \"thirdLevelCategory\": \"Text-Based\"\n  },\n  {\n    \"term\": \"HTTPS\",\n    \"description\": \"An extension of the Hypertext Transfer Protocol for secure communication over a computer network.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Protocols\",\n    \"thirdLevelCategory\": \"Security\"\n  },\n  {\n    \"term\": \"Authentication\",\n    \"description\": \"The process of verifying the identity of a user or process.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Security\",\n    \"thirdLevelCategory\": \"Access Control\"\n  },\n  {\n    \"term\": \"Authorization\",\n    \"description\": \"The process of specifying access rights/privileges to resources.\",\n    \"firstLevelCategory\": \"Web Development\",\n    \"secondLevelCategory\": \"Security\",\n    \"thirdLevelCategory\": \"Access Control\"\n  },\n  {\n    \"term\": \"Regression Testing\",\n    \"description\": \"A type of software testing to confirm that a recent program or code change has not adversely affected existing features.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Testing\",\n    \"thirdLevelCategory\": \"Types\"\n  },\n  {\n    \"term\": \"Code Review\",\n    \"description\": \"A software quality assurance activity in which one or several humans check a program mainly by viewing and reading parts of its source code.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Quality Assurance\",\n    \"thirdLevelCategory\": \"Practices\"\n  },\n  {\n    \"term\": \"Refactoring\",\n    \"description\": \"The process of restructuring existing computer code—changing the factoring—without changing its external behavior.\",\n    \"firstLevelCategory\": \"Software Development Lifecycle\",\n    \"secondLevelCategory\": \"Maintenance\",\n    \"thirdLevelCategory\": \"Code Improvement\"\n  }\n]"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/RotateExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class RotateExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.AutoItem()\n                                .RotateLeft()\n                                .AlignCenter()\n                                .Text(\"Definition\")\n                                .Bold().FontColor(Colors.Blue.Darken2);\n                            \n                            row.AutoItem()\n                                .PaddingHorizontal(15)\n                                .LineVertical(2).LineColor(Colors.Blue.Medium);\n                            \n                            row.RelativeItem()\n                                .Background(Colors.Blue.Lighten5)\n                                .Padding(15)\n                                .Text(text =>\n                                {\n                                    text.Span(\"A variable\").Bold();\n                                    text.Span(\" is a named storage location in memory that holds a value which can be modified during program execution.\");\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"rotate.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void FreeExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n\n                    page.Content()\n                        .Background(Colors.Grey.Lighten2)\n                        .Padding(25)\n                        .Row(row =>\n                        {\n                            row.Spacing(25);\n                            \n                            AddIcon(0);\n                            AddIcon(30);\n                            AddIcon(45);\n                            AddIcon(80);\n\n                            void AddIcon(float angle)\n                            {\n                                const float itemSize = 100;\n                                \n                                row.AutoItem()\n                                    .Width(itemSize)\n                                    .AspectRatio(1)\n                                    \n                                    .TranslateX(itemSize / 2)\n                                    .TranslateY(itemSize / 2)\n                                    \n                                    .Rotate(angle)\n                                    \n                                    .TranslateX(-itemSize / 2)\n                                    .TranslateY(-itemSize / 2)\n                                    \n                                    .Svg(\"Resources/compass.svg\");\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"rotate-free.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/RoundedCornersExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class RoundedCornersExamples\n{\n    [Test]\n    public void Consistent()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Border(1, Colors.Black)\n                        .Background(Colors.Grey.Lighten3)\n                        .CornerRadius(25)\n                        .Padding(25)\n                        .Text(\"Container with consistently rounded corners\");\n                });\n            })\n            .GenerateImages(x => \"rounded-corners-consistent.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Various()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Border(1, Colors.Black)\n                        .Background(Colors.Grey.Lighten3)\n                        .CornerRadiusTopLeft(5)\n                        .CornerRadiusTopRight(10)\n                        .CornerRadiusBottomRight(20)\n                        .CornerRadiusBottomLeft(40)\n                        .Padding(25)\n                        .Text(\"Container with rounded corners\");\n                });\n            })\n            .GenerateImages(x => \"rounded-corners-various.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Complex()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(550, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Border(1, Colors.Black)\n                        .CornerRadius(15)\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.ConstantColumn(100);\n                                columns.RelativeColumn();\n                                columns.ConstantColumn(150);\n                            });\n                            \n                            table.Header(header =>\n                            {\n                                header.Cell().Element(Style).Text(\"Index\");\n                                header.Cell().Element(Style).Text(\"Label\");\n                                header.Cell().Element(Style).Text(\"Price\");\n\n                                IContainer Style(IContainer container)\n                                {\n                                    return container\n                                        .Border(1, Colors.Grey.Darken2)\n                                        .Background(Colors.Grey.Lighten3)\n                                        .PaddingVertical(10)\n                                        .PaddingHorizontal(15)\n                                        .DefaultTextStyle(x => x.Bold());\n                                }\n                            });\n\n                            foreach (var index in Enumerable.Range(1, 5))\n                            {\n                                table.Cell().Element(Style).Text(index.ToString());\n                                table.Cell().Element(Style).Text(Placeholders.Label());\n                                table.Cell().Element(Style).Text(Placeholders.Price());\n                                \n                                IContainer Style(IContainer container)\n                                {\n                                    return container\n                                        .Border(1, Colors.Grey.Darken2)\n                                        .PaddingVertical(10)\n                                        .PaddingHorizontal(15);\n                                }\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"rounded-corners-complex.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Image()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(450, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .CornerRadius(25)\n                        .Image(\"Resources/landscape.jpg\");\n                });\n            })\n            .GenerateImages(x => \"rounded-corners-image.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/RowExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class RowExamples\n{\n    [Test]\n    public void SimpleExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Padding(25)\n                        .Width(325)\n                        .Row(row =>\n                        {\n                            row.ConstantItem(100)\n                                .Background(Colors.Grey.Medium)\n                                .Padding(10)\n                                .Text(\"100pt\");\n    \n                            row.RelativeItem()\n                                .Background(Colors.Grey.Lighten1)\n                                .Padding(10)\n                                .Text(\"75pt\");\n    \n                            row.RelativeItem(2)\n                                .Background(Colors.Grey.Lighten2)\n                                .Padding(10)\n                                .Text(\"150pt\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"row-simple.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void SpacingExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Padding(25)\n                        .Width(220)\n                        .Height(50)\n                        .Row(row =>\n                        {\n                            row.Spacing(10);\n        \n                            row.RelativeItem(2).Background(Colors.Grey.Medium);\n                            row.RelativeItem(3).Background(Colors.Grey.Lighten1);\n                            row.RelativeItem(5).Background(Colors.Grey.Lighten2);\n                        });\n                });\n            })\n            .GenerateImages(x => \"row-spacing.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void CustomSpacingExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(250, 0));\n                    page.MaxSize(new PageSize(250, 1000));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Height(50)\n                        .Row(row =>\n                        {\n                            row.RelativeItem().Background(Colors.Grey.Darken1);\n                            row.ConstantItem(10);\n                            row.RelativeItem().Background(Colors.Grey.Medium);\n                            row.ConstantItem(20);\n                            row.RelativeItem().Background(Colors.Grey.Lighten1);\n                            row.ConstantItem(30);\n                            row.RelativeItem().Background(Colors.Grey.Lighten2);\n                        });\n                });\n            })\n            .GenerateImages(x => \"row-spacing-custom.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void DisableUniformItemsHeightExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(700, 0));\n                    page.MaxSize(new PageSize(700, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(15);\n                            \n                            row.RelativeItem()\n                                .Element(LabelStyle)\n                                .Text(\"Programming is both a science and an art — it demands precision, creativity, and patience. At its core, it’s about understanding how to break down complex problems into small, logical steps that a computer can execute.\");\n                            \n                            row.RelativeItem()\n                                .Element(LabelStyle)\n                                .Text(\"Programming is the art of turning ideas into logic, logic into code, and code into something that solves real problems.\");\n                            \n                            static IContainer LabelStyle(IContainer container) => container\n                                .ShrinkVertical()\n                                .Background(Colors.Grey.Lighten3)\n                                .CornerRadius(15)\n                                .Padding(15);\n                        });\n                });\n            })\n            .GenerateImages(x => \"row-uniform-height-enabled.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.High, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ScaleExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ScaleExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(350)\n                        .Padding(25)\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n                            \n                            var scales = new[] { 0.75f, 1f, 1.25f, 1.5f };\n\n                            foreach (var scale in scales)\n                            {\n                                column\n                                    .Item()\n                                    .Background(Colors.Grey.Lighten3)\n                                    .Scale(scale)\n                                    .Padding(10)\n                                    .Text($\"Content scale: {scale}\")\n                                    .FontSize(20);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"scale.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ScaleToFitExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ScaleToFitExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            const string text = \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\";\n\n                            foreach (var i in Enumerable.Range(4, 5))\n                            {\n                                column\n                                    .Item()\n                                    .Shrink()\n                                    .Border(1)\n                                    .Padding(15)\n                                    .Width(i * 50) // sizes from 200x100 to 450x175\n                                    .Height(i * 25)\n                                    .ScaleToFit()\n                                    .Text(text);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"scale-to-fit.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.High, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/SectionExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class SectionExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5.Landscape());\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            var terms = new[]\n                            {\n                                (\"Bit\", \"The smallest unit of data in computing, representing either a 0 or a 1. Multiple bits are combined to form bytes, which are used to store larger data values.\"),\n                                (\"Byte\", \"A unit of digital information that consists of 8 bits. A byte is commonly used to store a single character of text, such as a letter or a number, in computer memory.\"),\n                                (\"Binary\", \"A number system that uses only two digits, 0 and 1, which are the fundamental building blocks of computer operations. Computers process and store all data in binary format, including text, images, and instructions.\"),\n                                (\"Array\", \"A data structure that stores a fixed-size sequence of elements, all of the same type, in a contiguous block of memory. Arrays allow quick access to elements using an index and are commonly used to manage collections of data.\")\n                            };\n\n                            // title\n                            column.Item().Extend().AlignMiddle().AlignCenter().Text(\"Programming Glossary\").FontSize(32).Bold();\n                            column.Item().PageBreak();\n                            \n                            // table of contents\n                            column.Item().PaddingBottom(25).Text(\"Table of Contents\").FontSize(24).Bold().Underline();\n                            \n                            foreach (var term in terms)\n                            {\n                                column.Item()\n                                    .PaddingBottom(10)\n                                    .SectionLink($\"term-{term}\")\n                                    .Text(text =>\n                                    {\n                                        text.Span(\"Term \");\n                                        text.Span(term.Item1).Bold();\n                                        text.Span(\" on page \");\n                                        text.BeginPageNumberOfSection($\"term-{term}\");\n                                    });\n                            }\n                            \n                            // content\n                            foreach (var term in terms)\n                            {\n                                column.Item().PageBreak();\n                                \n                                column.Item()\n                                    .Section($\"term-{term}\")\n                                    .Text(text =>\n                                    {\n                                        text.Span(term.Item1).Bold().FontColor(Colors.Blue.Darken2);\n                                        text.Span(\" - \");\n                                        text.Span(term.Item2);\n                                    });\n                            }\n                        });\n                });\n            })\n            .GeneratePdf(\"sections.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/SemanticExamples.cs",
    "content": "using System.Text.Json;\nusing System.Text.Json.Serialization;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class SemanticExamples\n{\n    [Test]\n    public void HeaderAndFooter()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 250));\n                    page.DefaultTextStyle(x => x.FontSize(16));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Border(1)\n                        .BorderColor(Colors.Grey.Lighten1)\n                        .SemanticTable()\n                        .Table(table =>\n                        {\n                            var pageSizes = new List<(string name, double width, double height)>()\n                            {\n                                (\"Letter (ANSI A)\", 8.5f, 11),\n                                (\"Legal\", 8.5f, 14),\n                                (\"Ledger (ANSI B)\", 11, 17),\n                                (\"Tabloid (ANSI B)\", 17, 11),\n                                (\"ANSI C\", 22, 17),\n                                (\"ANSI D\", 34, 22),\n                                (\"ANSI E\", 44, 34)\n                            };\n\n                            const int inchesToPoints = 72;\n\n                            IContainer DefaultCellStyle(IContainer container, string backgroundColor)\n                            {\n                                return container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten1)\n                                    .Background(backgroundColor)\n                                    .PaddingVertical(5)\n                                    .PaddingHorizontal(10)\n                                    .AlignCenter()\n                                    .AlignMiddle();\n                            }\n\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn();\n\n                                columns.ConstantColumn(80);\n                                columns.ConstantColumn(80);\n\n                                columns.ConstantColumn(80);\n                                columns.ConstantColumn(80);\n                            });\n\n                            table.Header(header =>\n                            {\n                                // please be sure to call the 'header' handler!\n\n                                header.Cell().RowSpan(2).Element(CellStyle).ExtendHorizontal().AlignLeft()\n                                    .Text(\"Document type\").Bold();\n\n                                header.Cell().ColumnSpan(2).Element(CellStyle).Text(\"Inches\").Bold();\n                                header.Cell().ColumnSpan(2).Element(CellStyle).Text(\"Points\").Bold();\n\n                                header.Cell().Element(CellStyle).Text(\"Width\");\n                                header.Cell().Element(CellStyle).Text(\"Height\");\n\n                                header.Cell().Element(CellStyle).Text(\"Width\");\n                                header.Cell().Element(CellStyle).Text(\"Height\");\n\n                                // you can extend existing styles by creating additional methods\n                                IContainer CellStyle(IContainer container) =>\n                                    DefaultCellStyle(container, Colors.Grey.Lighten3);\n                            });\n\n                            foreach (var page in pageSizes)\n                            {\n                                table.Cell().Element(CellStyle).ExtendHorizontal().AlignLeft().Text(page.name);\n\n                                // inches\n                                table.Cell().Element(CellStyle).Text(page.width);\n                                table.Cell().Element(CellStyle).Text(page.height);\n\n                                // points\n                                table.Cell().Element(CellStyle).Text(page.width * inchesToPoints);\n                                table.Cell().Element(CellStyle).Text(page.height * inchesToPoints);\n\n                                IContainer CellStyle(IContainer container) =>\n                                    DefaultCellStyle(container, Colors.White).ShowOnce();\n                            }\n                        });\n                });\n            })\n            .GeneratePdf();\n    }\n    \n    \n    public class BookTermModel\n    {\n        public string Term { get; set; }\n        public string Description { get; set; }\n        public string FirstLevelCategory { get; set; }\n        public string SecondLevelCategory { get; set; }\n        public string ThirdLevelCategory { get; set; }\n    }\n    \n    [Test]\n    public async Task GenerateBook()\n    {\n        QuestPDF.Settings.EnableCaching = false;\n        QuestPDF.Settings.EnableDebugging = false;\n        \n        var serializerSettings = new JsonSerializerOptions\n        {\n            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,\n            WriteIndented = true\n        };\n        \n        var bookData = await File.ReadAllTextAsync(\"Resources/semantic-book-content.json\");\n        var terms = JsonSerializer.Deserialize<ICollection<BookTermModel>>(bookData, serializerSettings);\n        var categories = terms\n            .GroupBy(x => x.FirstLevelCategory)\n            .Select(x => new\n            {\n                Category = x.Key,\n                Terms = x\n                    .GroupBy(y => y.SecondLevelCategory)\n                    .Select(y => new\n                    {\n                        Category = y.Key,\n                        Terms = y\n                            .GroupBy(z => z.ThirdLevelCategory)\n                            .Select(z => new\n                            {\n                                Category = z.Key,\n                                Terms = z.ToList()\n                            })\n                            .ToList()\n                    })\n                    .ToList()\n            })\n            .ToList();\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A4);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n                    page.PageColor(Colors.White);\n\n                    page.Header()\n                        .Text(\"Programming Terms\")\n                        .Bold()\n                        .FontSize(36);\n                    \n                    page.Content()\n                        .PaddingVertical(24)\n                        .Column(column =>\n                        {\n                            foreach (var category1 in categories)\n                            {\n                                column.Item()\n                                    .SemanticSection()\n                                    .EnsureSpace(100)\n                                    .Column(column =>\n                                    {\n                                        column.Spacing(24);\n                                        \n                                        column.Item()\n                                            .PaddingBottom(8)\n                                            .SemanticHeader1()\n                                            .Text(category1.Category)\n                                            .FontSize(24)\n                                            .FontColor(Colors.Blue.Darken4)\n                                            .Bold();\n\n                                        foreach (var category2 in category1.Terms)\n                                        {\n                                            column.Item()\n                                                .SemanticSection()\n                                                .EnsureSpace(100)\n                                                .Column(column =>\n                                                {\n                                                    column.Spacing(8);\n                                                    \n                                                    column.Item()\n                                                        .PaddingBottom(8)\n                                                        .SemanticHeader2()\n                                                        .Text(category2.Category)\n                                                        .FontSize(20)\n                                                        .FontColor(Colors.Blue.Darken2)\n                                                        .Bold();\n\n                                                    foreach (var category3 in category2.Terms)\n                                                    {\n                                                        column.Item()\n                                                            .SemanticSection()\n                                                            .EnsureSpace(100)\n                                                            .Column(column =>\n                                                            {\n                                                                column.Spacing(8);\n                                                                \n                                                                column.Item()\n                                                                    .PaddingBottom(8)\n                                                                    .SemanticHeader3()\n                                                                    .Text(category3.Category)\n                                                                    .FontSize(16)\n                                                                    .FontColor(Colors.Blue.Medium)\n                                                                    .Bold();\n\n                                                                foreach (var term in category3.Terms)\n                                                                {\n                                                                    column.Item()\n                                                                        .SemanticParagraph()\n                                                                        .Text(text =>\n                                                                        {\n                                                                            text.Span(term.Term).Bold();\n                                                                            text.Span(\" - \");\n                                                                            text.Span(term.Description);\n                                                                        });\n                                                                }\n                                                            });\n                                                    }\n                                                });\n                                        }\n                                    });\n                                \n                                column.Item().PageBreak();\n                            }\n                        });\n\n                    page.Footer()\n                        .AlignCenter()\n                        .Text(text =>\n                        {\n                            text.Span(\"Page \");\n                            text.CurrentPageNumber();\n                            text.Span(\" of \");\n                            text.TotalPages();\n                        });\n                });\n            })\n            .WithMetadata(new DocumentMetadata()\n            {\n                Title = \"Programming Terms\",\n                Language = \"en-US\"\n            })\n            .GeneratePdf();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ShadowExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ShadowExamples\n{\n    [Test]\n    public void Simple()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Border(1, Colors.Black)\n                        .Shadow(new BoxShadowStyle\n                        {\n                            Color = Colors.Grey.Medium, \n                            Blur = 5, \n                            Spread = 5,\n                            OffsetX = 5, \n                            OffsetY = 5\n                        })\n                        .Background(Colors.White)\n                        .Padding(15)\n                        .Text(\"Important content\");\n                });\n            })\n            .GenerateImages(x => $\"shadow-simple.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void OffsetX()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(50);\n                            \n                            foreach (var offsetX in new[] { -10, 0, 10 })\n                            {\n                                row.ConstantItem(100)\n                                    .AspectRatio(1)\n                                    .Shadow(new BoxShadowStyle\n                                    {\n                                        Color = Colors.Grey.Darken1,\n                                        Blur = 10,\n                                        OffsetX = offsetX\n                                    })\n                                    .Background(Colors.White);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => $\"shadow-offset-x.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void OffsetY()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(50);\n                            \n                            foreach (var offsetY in new[] { -10, 0, 10 })\n                            {\n                                row.ConstantItem(100)\n                                    .AspectRatio(1)\n                                    .Shadow(new BoxShadowStyle\n                                    {\n                                        Color = Colors.Grey.Darken2,\n                                        Blur = 10,\n                                        OffsetY = offsetY\n                                    })\n                                    .Background(Colors.White);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => $\"shadow-offset-y.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Color()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(50);\n                            \n                            var colors = new[]\n                            {\n                                Colors.Red.Darken2,\n                                Colors.Green.Darken2,\n                                Colors.Blue.Darken2\n                            };\n                            \n                            foreach (var color in colors)\n                            {\n                                row.ConstantItem(100)\n                                    .AspectRatio(1)\n                                    .Shadow(new BoxShadowStyle\n                                    {\n                                        Color = color,\n                                        Blur = 10\n                                    })\n                                    .Background(Colors.White);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => $\"shadow-color.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Blur()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(50);\n\n                            foreach (var blur in new[] { 5, 10, 20 })\n                            {\n                                row.ConstantItem(100)\n                                    .AspectRatio(1)\n                                    .Shadow(new BoxShadowStyle\n                                    {\n                                        Color = Colors.Grey.Darken1,\n                                        Blur = blur\n                                    })\n                                    .Background(Colors.White);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => $\"shadow-blur.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Spread()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(50);\n\n                            foreach (var spread in new[] { 0, 5, 10 })\n                            {\n                                row.ConstantItem(100)\n                                    .AspectRatio(1)\n                                    .Shadow(new BoxShadowStyle\n                                    {\n                                        Color = Colors.Grey.Darken1,\n                                        Blur = 5,\n                                        Spread = spread\n                                    })\n                                    .Background(Colors.White);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => $\"shadow-spread.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void NoBlur()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(50);\n                    page.PageColor(Colors.White);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(50);\n\n                            row.ConstantItem(100)\n                                .AspectRatio(1)\n                                .Shadow(new BoxShadowStyle\n                                {\n                                    Color = Colors.Grey.Lighten1,\n                                    Blur = 0, \n                                    OffsetX = 8,\n                                    OffsetY = 8\n                                })\n                                .Border(1, Colors.Black)\n                                .Background(Colors.White);\n                            \n                            row.ConstantItem(100)\n                                .AspectRatio(1)\n                                .Shadow(new BoxShadowStyle\n                                {\n                                    Color = Colors.Grey.Lighten1,\n                                    Blur = 0,\n                                    OffsetX = 8,\n                                    OffsetY = 8\n                                })\n                                .Border(1, Colors.Black)\n                                .CornerRadius(16)\n                                .Background(Colors.White);\n                        });\n                });\n            })\n            .GenerateImages(x => $\"shadow-no-blur.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ShowEntireExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ShowEntireExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(500, 500);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content() \n                        .Decoration(decoration =>\n                        {\n                            var terms = new[]\n                            {\n                                (\"Function\", \"A reusable block of code designed to perform a specific task. Functions take input parameters, process them, and return results, making code modular, readable, and maintainable. They are an essential component of all programming languages.\"),\n                                (\"Recursion\", \"A programming technique where a function calls itself in order to solve a problem by breaking it down into smaller, similar subproblems. Recursion is often used for complex algorithms, such as searching, sorting, and tree traversal.\"),\n                                (\"Framework\", \"A pre-built collection of code, tools, and best practices that provides a structured foundation for developing software. Frameworks simplify development by handling common functionalities, such as database access, user authentication, and UI rendering.\"),\n                                (\"Package\", \"A self-contained collection of code, typically consisting of functions, classes, and modules, that provides specific functionality. Packages help organize large projects and allow developers to reuse and distribute their code easily.\"),\n                            };\n                            \n                            decoration.Before().Text(\"Terms and their definitions:\").FontSize(24).Bold().Underline();\n                            \n                            decoration.Content().PaddingTop(15).Column(column =>\n                            {\n                                column.Spacing(15);\n                                \n                                foreach (var term in terms)\n                                {\n                                    column.Item()\n                                        .ShowEntire()\n                                        .Text(text =>\n                                        {\n                                            text.Span(term.Item1).Bold().FontColor(Colors.Blue.Darken2);\n                                            text.Span($\" - {term.Item2}\");\n                                        });\n                                }\n                            });\n                        });\n                });\n            })\n            .GenerateImages(x => $\"show-entire-with-{x}.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ShowOnceExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ShowOnceExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(350, 500);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Decoration(decoration =>\n                        {\n                            decoration.Before().Column(column =>\n                            {\n                                column.Item()\n                                    .ShowOnce()\n                                    .Row(row =>\n                                    {\n                                        row.ConstantItem(80).AspectRatio(4 / 3f).Placeholder();\n                                        row.ConstantItem(10);\n                                        row.RelativeItem()\n                                            .AlignMiddle()\n                                            .Column(innerColumn =>\n                                            {\n                                                innerColumn.Item().Text(\"Invoice #1234\").FontSize(24).Bold();\n                                                innerColumn.Item().Text($\"Generated on {DateTime.Now:d}\").FontSize(16).Light();\n                                            });\n                                    });\n                                \n                                column.Item()\n                                    .SkipOnce()\n                                    .Text(\"Invoice #1234\").FontSize(24).Bold();\n                            });\n                            \n                            // generate dummy content\n                            decoration.Content()\n                                .PaddingTop(15)\n                                .ExtendHorizontal()\n                                .Column(column =>\n                                {\n                                    column.Spacing(10);\n                                    \n                                    foreach (var i in Enumerable.Range(1, 15))\n                                    {\n                                        column.Item()\n                                            .Height(30)\n                                            .Background(Colors.Grey.Lighten3)\n                                            .AlignCenter()\n                                            .AlignMiddle()\n                                            .Text($\"{i}\");\n                                    }\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => $\"show-once-{x}.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/SkiaSharpHelpers.cs",
    "content": "using System.Text;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\nusing SkiaSharp;\n\nnamespace QuestPDF.SkiaSharpIntegration;\n\npublic static class SkiaSharpHelpers\n{\n    public static void SkiaSharpSvgCanvas(this IContainer container, Action<SKCanvas, Size> drawOnCanvas)\n    {\n        container.Svg(size =>\n        {\n            using var stream = new MemoryStream();\n\n            using (var canvas = SKSvgCanvas.Create(new SKRect(0, 0, size.Width, size.Height), stream))\n                drawOnCanvas(canvas, size);\n            \n            var svgData = stream.ToArray();\n            return Encoding.UTF8.GetString(svgData);\n        });\n    }\n    \n    public static void SkiaSharpRasterizedCanvas(this IContainer container, Action<SKCanvas, ImageSize> drawOnCanvas)\n    {\n        container.Image(payload =>\n        {\n            using var bitmap = new SKBitmap(payload.ImageSize.Width, payload.ImageSize.Height);\n\n            using (var canvas = new SKCanvas(bitmap))\n            {\n                canvas.Scale(payload.ImageSize.Width / payload.AvailableSpace.Width, payload.ImageSize.Height / payload.AvailableSpace.Height);\n                drawOnCanvas(canvas, new ImageSize((int)payload.AvailableSpace.Width, (int)payload.AvailableSpace.Height));\n            }\n        \n            return bitmap.Encode(SKEncodedImageFormat.Png, 100).ToArray();\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/SkiaSharpIntegrationExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.SkiaSharpIntegration;\nusing SkiaSharp;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class SkiaSharpIntegrationExamples\n{\n    [Test]\n    public void Svg()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(350, 350);\n                    page.Margin(25);\n\n                    page.Content()\n                        .Width(300)\n                        .Height(300)\n                        .SkiaSharpSvgCanvas((canvas, size) =>\n                        {\n                            var centerX = size.Width / 2;\n                            var centerY = size.Height / 2;\n                            var radius = Math.Min(centerX, centerY);\n\n                            // draw clock face\n                            using var facePaint = new SKPaint\n                            {\n                                Color = new SKColor(Colors.Blue.Lighten4)\n                            };\n\n                            canvas.DrawCircle(centerX, centerY, radius, facePaint);\n\n                            // draw clock ticks\n                            using var tickPaint = new SKPaint\n                            {\n                                Color = new SKColor(Colors.Blue.Darken4), \n                                StrokeWidth = 4, \n                                StrokeCap = SKStrokeCap.Round\n                            };\n\n                            canvas.Save();\n                            canvas.Translate(centerX, centerY);\n\n                            foreach (var i in Enumerable.Range(0, 12))\n                            {\n                                canvas.DrawLine(new SKPoint(0, radius * 0.85f), new SKPoint(0, radius * 0.95f), tickPaint);\n                                canvas.RotateDegrees(30);\n                            }\n\n                            canvas.Restore();\n\n                            // draw clock hands\n                            using var hourHandPaint = new SKPaint\n                            {\n                                Color = new SKColor(Colors.Blue.Darken4),\n                                StrokeWidth = 8,\n                                StrokeCap = SKStrokeCap.Round\n                            };\n\n                            using var minuteHandPaint = new SKPaint\n                            {\n                                Color = new SKColor(Colors.Blue.Darken2),\n                                StrokeWidth = 4,\n                                StrokeCap = SKStrokeCap.Round\n                            };\n\n                            canvas.Translate(centerX, centerY);\n\n                            canvas.Save();\n                            canvas.RotateDegrees(6 * DateTime.Now.Minute);\n                            canvas.DrawLine(new SKPoint(0, 0), new SKPoint(0, -radius * 0.7f), minuteHandPaint);\n                            canvas.Restore();\n                            \n                            canvas.Save();\n                            canvas.RotateDegrees(30 * DateTime.Now.Hour + DateTime.Now.Minute / 2);\n                            canvas.DrawLine(new SKPoint(0, 0), new SKPoint(0, -radius * 0.5f), hourHandPaint);\n                            canvas.Restore();\n                        });\n                });\n            })\n            .GenerateImages(x => \"skiasharp-integration-svg.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Resterized()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(new PageSize(500, 400));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Padding(25)\n                        .SkiaSharpRasterizedCanvas((canvas, size) =>\n                        {\n                            // add padding to properly display the shadow effect\n                            const float padding = 25;\n                            canvas.Translate(padding, padding);\n                            \n                            // load image and scale canvas space\n                            using var bitmap = SKBitmap.Decode(\"Resources/landscape.jpg\");\n                            \n                            var targetBitmapSize = new SKSize(size.Width - 2 * padding, size.Height - 2 * padding);\n                            var scale = Math.Min(targetBitmapSize.Width / bitmap.Width, targetBitmapSize.Height / bitmap.Height);\n                            canvas.Scale(scale);\n\n                            var drawingArea = new SKRoundRect(new SKRect(0, 0, bitmap.Width, bitmap.Height), 32, 32);\n                            \n                            // draw drop shadow\n                            using var dropShadowFilter = SKImageFilter.CreateDropShadow(8, 8, 16, 16, SKColors.Black);\n                            using var paint = new SKPaint\n                            {\n                                ImageFilter = dropShadowFilter\n                            };\n\n                            canvas.DrawRoundRect(drawingArea, paint);\n                            \n                            // draw image\n                            canvas.ClipRoundRect(drawingArea, antialias: true);\n                            canvas.DrawBitmap(bitmap, SKPoint.Empty);\n                        });\n                });\n            })\n            .GenerateImages(x => \"skiasharp-integration-rasterized.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/SkipOnceExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class SkipOnceExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(500, 500);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            var terms = new[]\n                            {\n                                (\"Repository\", \"A centralized storage location for source code and related files, typically managed using version control systems like Git. Repositories allow multiple developers to collaborate on projects, track changes, and maintain version history.\"),\n                                (\"Version Control\", \"A system that tracks changes to code over time, enabling developers to collaborate efficiently, revert to previous versions, and maintain a structured development workflow. Popular version control tools include Git, Mercurial, and Subversion.\"),\n                                (\"Abstraction\", \"A programming concept that hides complex implementation details and exposes only the necessary parts. Abstraction helps simplify code and allows developers to focus on high-level design rather than low-level implementation details.\"),\n                                (\"Namespace\", \"A container that groups related identifiers, such as variables, functions, and classes, to prevent naming conflicts in a program. Namespaces are commonly used in large projects to organize code efficiently.\"),\n                            };\n                            \n                            column.Spacing(15);\n                            \n                            foreach (var term in terms)\n                            {\n                                column.Item().Decoration(decoration =>\n                                {\n                                    decoration.Before()\n                                        .DefaultTextStyle(x => x.FontSize(24).Bold().FontColor(Colors.Blue.Darken2))\n                                        .Column(innerColumn =>\n                                        {\n                                            innerColumn.Item().ShowOnce().Text(term.Item1);\n                                            \n                                            innerColumn.Item().SkipOnce().Text(text =>\n                                            {\n                                                text.Span(term.Item1);\n                                                text.Span(\" (continued)\").Light().Italic();\n                                            });\n                                        });\n\n                                    decoration.Content().Text(term.Item2);\n                                });\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => $\"skip-once-{x}.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/StopPagingExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class StopPagingExamples\n{\n    [Test]\n    public void Example()\n    {\n        const string bookDescription = \"\\\"Master Modern C# Development\\\" is a comprehensive guide that takes you from the basics to advanced concepts in C# programming. Perfect for beginners and intermediate developers looking to enhance their skills with practical examples and real-world applications. Covering object-oriented programming, LINQ, asynchronous programming, and the latest .NET features, this book provides step-by-step explanations to help you write clean, efficient, and scalable code. Whether you're building desktop, web, or cloud applications, this resource equips you with the knowledge and best practices to become a confident C# developer.\";\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Width(400)\n                        .Height(300)\n                        .StopPaging()\n                        .Decoration(decoration =>\n                        {\n                            decoration.Before().Text(\"Book description:\").Bold();\n                            decoration.Content().Text(bookDescription);\n                        });\n                });\n            })\n            .GeneratePdf(\"stop-paging-enabled.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/TableExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class TableExamples\n{\n    [Test]\n    public void Basic()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.ConstantColumn(50);\n                                columns.RelativeColumn();\n                                columns.ConstantColumn(125);\n                            });\n            \n                            table.Header(header =>\n                            {\n                                header.Cell().BorderBottom(2).Padding(8).Text(\"#\");\n                                header.Cell().BorderBottom(2).Padding(8).Text(\"Product\");\n                                header.Cell().BorderBottom(2).Padding(8).AlignRight().Text(\"Price\");\n                            });\n                            \n                            foreach (var i in Enumerable.Range(0, 6))\n                            {\n                                var price = Math.Round(Random.Shared.NextDouble() * 100, 2);\n                                 \n                                table.Cell().Padding(8).Text($\"{i + 1}\");\n                                table.Cell().Padding(8).Text(Placeholders.Label());\n                                table.Cell().Padding(8).AlignRight().Text($\"${price}\");\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"table-simple.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void CellStyleExample()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    string[] weatherIcons = [\"cloudy.svg\", \"lightning.svg\", \"pouring.svg\", \"rainy.svg\", \"snowy.svg\", \"windy.svg\"];\n                    \n                    page.Content()\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn();\n                                columns.ConstantColumn(125);\n                                columns.ConstantColumn(125);\n                            });\n\n                            table.Header(header =>\n                            {\n                                header.Cell().Element(CellStyle).Text(\"Day\");\n                                header.Cell().Element(CellStyle).AlignCenter().Text(\"Weather\");\n                                header.Cell().Element(CellStyle).AlignRight().Text(\"Temp\");\n\n                                static IContainer CellStyle(IContainer container)\n                                {\n                                    return container\n                                        .Background(Colors.Blue.Darken2)\n                                        .DefaultTextStyle(x => x.FontColor(Colors.White).Bold())\n                                        .PaddingVertical(8)\n                                        .PaddingHorizontal(16);\n                                }\n                            });\n\n                            foreach (var i in Enumerable.Range(0, 7))\n                            {\n                                var weatherIndex = Random.Shared.Next(0, weatherIcons.Length);\n\n                                table.Cell().Element(CellStyle)\n                                    .Text(new DateTime(2025, 2, 26).AddDays(i).ToString(\"dd MMMM\"));\n                                \n                                table.Cell().Element(CellStyle).AlignCenter().Height(24)\n                                    .Svg($\"Resources/WeatherIcons/{weatherIcons[weatherIndex]}\");\n                                \n                                table.Cell().Element(CellStyle).AlignRight()\n                                    .Text($\"{Random.Shared.Next(-10, 35)}°\");\n\n                                IContainer CellStyle(IContainer container)\n                                {\n                                    var backgroundColor = i % 2 == 0 \n                                        ? Colors.Blue.Lighten5 \n                                        : Colors.Blue.Lighten4;\n\n                                    return container\n                                        .Background(backgroundColor)\n                                        .PaddingVertical(8)\n                                        .PaddingHorizontal(16);\n                                }\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"table-cell-style.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void OverlappingCells()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(700, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(16));\n                    page.Margin(25);\n\n                    string[] dayNames = [\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\"];\n                     \n                    page.Content()\n                        .Border(1)\n                        .BorderColor(Colors.Grey.Lighten1)\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                // hour column\n                                columns.ConstantColumn(60);\n                                \n                                // day columns\n                                foreach (var i in Enumerable.Range(0, 5))\n                                    columns.RelativeColumn();\n                            });\n                            \n                            // even/odd columns background\n                            foreach (var column in Enumerable.Range(0, 7))\n                            {\n                                var backgroundColor = column % 2 == 0 ? Colors.Grey.Lighten3 : Colors.White;\n                                table.Cell().Column((uint)column).RowSpan(24).Background(backgroundColor); \n                            }\n                            \n                            // hours and hour lines\n                            foreach (var hour in Enumerable.Range(6, 10))\n                            {\n                                table.Cell().Column(1).Row((uint)hour)\n                                    .PaddingVertical(5).PaddingHorizontal(10).AlignRight()\n                                    .Text($\"{hour}\");\n                                \n                                table.Cell().Row((uint)hour).ColumnSpan(6)\n                                    .Border(1).BorderColor(Colors.Grey.Lighten1).Height(20);\n                            }\n                            \n                            // dates and day names\n                            foreach (var i in Enumerable.Range(0, 5))\n                            {\n                                table.Cell()\n                                    .Column((uint) i + 2).Row(1).Padding(5)\n                                    .Column(column =>\n                                    {\n                                        column.Item().AlignCenter().Text($\"{17  + i}\").FontSize(24).Bold();\n                                        column.Item().AlignCenter().Text(dayNames[i]).Light();\n                                    });\n                            }\n                            \n                            // standup events\n                            foreach (var i in Enumerable.Range(1, 4))\n                                AddEvent((uint)i, 8, 1, \"Standup\", Colors.Blue.Lighten4, Colors.Blue.Darken3);\n                            \n                            // other events\n                            AddEvent(2, 11, 2, \"Interview\", Colors.Red.Lighten4, Colors.Red.Darken3);\n                            AddEvent(3, 12, 3, \"Demo\", Colors.Red.Lighten4, Colors.Red.Darken3);\n                            AddEvent(5, 5, 17, \"PTO\", Colors.Green.Lighten4, Colors.Green.Darken3);\n\n                            void AddEvent(uint day, uint hour, uint length, string name, Color backgroundColor, Color textColor)\n                            {\n                                table.Cell()\n                                    .Column(day + 1).Row(hour).RowSpan(length)\n                                    .Padding(5).Background(backgroundColor).Padding(5)\n                                    .AlignCenter().AlignMiddle() \n                                    .Text(name).FontColor(textColor);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"table-overlapping-cells.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void ManualCellPlacement()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(700, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(16 ));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.ConstantColumn(75);\n                                columns.ConstantColumn(150);\n                                columns.ConstantColumn(200);\n                                columns.ConstantColumn(200);\n                            });\n            \n                            table.Cell().Row(1).Column(3).ColumnSpan(2)\n                                .Element(HeaderCellStyle)\n                                .Text(\"Predicted condition\").Bold();\n                            \n                            table.Cell().Row(3).Column(1).RowSpan(2)\n                                .Element(HeaderCellStyle).RotateLeft()\n                                .Text(\"Actual\\ncondition\").Bold().AlignCenter();\n            \n                            table.Cell().Row(2).Column(3)\n                                .Element(HeaderCellStyle)\n                                .Text(\"Positive (PP)\");\n                            \n                            table.Cell().Row(2).Column(4)\n                                .Element(HeaderCellStyle)\n                                .Text(\"Negative (PN)\");\n            \n                            table.Cell().Row(3).Column(2)\n                                .Element(HeaderCellStyle).Text(\"Positive (P)\");\n                            \n                            table.Cell().Row(4).Column(2)\n                                .Element(HeaderCellStyle)\n                                .Text(\"Negative (N)\");\n            \n                            table.Cell()\n                                .Row(3).Column(3).Element(GoodCellStyle)\n                                .Text(\"True positive (TP)\");\n                            \n                            table.Cell()\n                                .Row(3).Column(4).Element(BadCellStyle)\n                                .Text(\"False negative (FN)\");\n            \n                            table.Cell().Row(4).Column(3)\n                                .Element(BadCellStyle).Text(\"False positive (FP)\");\n                            \n                            table.Cell().Row(4).Column(4)\n                                .Element(GoodCellStyle).Text(\"True negative (TN)\");\n\n                            static IContainer CellStyle(IContainer container, Color color)\n                                => container.Border(1).Background(color).PaddingHorizontal(10).PaddingVertical(15).AlignCenter().AlignMiddle();\n\n                            static IContainer HeaderCellStyle(IContainer container) \n                                => CellStyle(container, Colors.Grey.Lighten4 );\n                            \n                            static IContainer GoodCellStyle(IContainer container) \n                                => CellStyle(container, Colors.Green.Lighten4).DefaultTextStyle(x => x.FontColor(Colors.Green.Darken2));\n                            \n                            static IContainer BadCellStyle(IContainer container) \n                                => CellStyle(container, Colors.Red.Lighten4).DefaultTextStyle(x => x.FontColor(Colors.Red.Darken2));\n                        });\n                });\n            })\n            .GenerateImages(x => \"table-manual-cell-placement.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void ColumnsDefinition()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(700, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(16));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Width(450)\n                        .Table(table =>\n                        {\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.ConstantColumn(150);\n                                columns.RelativeColumn(2);\n                                columns.RelativeColumn(3);\n                            });\n\n                            table.Cell().ColumnSpan(3)\n                                .Background(Colors.Grey.Lighten2).Element(CellStyle)\n                                .Text(\"Total width: 450px\");\n                            \n                            table.Cell().Element(CellStyle).Text(\"Constant: 150px\");\n                            table.Cell().Element(CellStyle).Text(\"Relative: 2*\");\n                            table.Cell().Element(CellStyle).Text(\"Relative: 3*\");\n                            \n                            table.Cell().Element(CellStyle).Text(\"150px\");\n                            table.Cell().Element(CellStyle).Text(\"120px\");\n                            table.Cell().Element(CellStyle).Text(\"180px\");\n\n                            static IContainer CellStyle(IContainer container)\n                                => container.Border(1).Padding(10);\n                        });\n                });\n            })\n            .GenerateImages(x => \"table-columns-definition.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void HeaderAndFooter()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 250));\n                    page.DefaultTextStyle(x => x.FontSize(16));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Border(1)\n                        .BorderColor(Colors.Grey.Lighten1)\n                        .Table(table =>\n                        {\n                            var pageSizes = new List<(string name, double width, double height)>()\n                            {\n                                (\"Letter (ANSI A)\", 8.5f, 11),\n                                (\"Legal\", 8.5f, 14),\n                                (\"Ledger (ANSI B)\", 11, 17),\n                                (\"Tabloid (ANSI B)\", 17, 11),\n                                (\"ANSI C\", 22, 17),\n                                (\"ANSI D\", 34, 22),\n                                (\"ANSI E\", 44, 34)\n                            };\n\n                            const int inchesToPoints = 72;\n\n                            IContainer DefaultCellStyle(IContainer container, string backgroundColor)\n                            {\n                                return container\n                                    .Border(1)\n                                    .BorderColor(Colors.Grey.Lighten1)\n                                    .Background(backgroundColor)\n                                    .PaddingVertical(5)\n                                    .PaddingHorizontal(10)\n                                    .AlignCenter()\n                                    .AlignMiddle();\n                            }\n\n                            table.ColumnsDefinition(columns =>\n                            {\n                                columns.RelativeColumn();\n\n                                columns.ConstantColumn(80);\n                                columns.ConstantColumn(80);\n\n                                columns.ConstantColumn(80);\n                                columns.ConstantColumn(80);\n                            });\n\n                            table.Header(header =>\n                            {\n                                // please be sure to call the 'header' handler!\n\n                                header.Cell().RowSpan(2).Element(CellStyle).ExtendHorizontal().AlignLeft()\n                                    .Text(\"Document type\").Bold();\n\n                                header.Cell().ColumnSpan(2).Element(CellStyle).Text(\"Inches\").Bold();\n                                header.Cell().ColumnSpan(2).Element(CellStyle).Text(\"Points\").Bold();\n\n                                header.Cell().Element(CellStyle).Text(\"Width\");\n                                header.Cell().Element(CellStyle).Text(\"Height\");\n\n                                header.Cell().Element(CellStyle).Text(\"Width\");\n                                header.Cell().Element(CellStyle).Text(\"Height\");\n\n                                // you can extend existing styles by creating additional methods\n                                IContainer CellStyle(IContainer container) =>\n                                    DefaultCellStyle(container, Colors.Grey.Lighten3);\n                            });\n\n                            foreach (var page in pageSizes)\n                            {\n                                table.Cell().Element(CellStyle).ExtendHorizontal().AlignLeft().Text(page.name);\n\n                                // inches\n                                table.Cell().Element(CellStyle).Text(page.width);\n                                table.Cell().Element(CellStyle).Text(page.height);\n\n                                // points\n                                table.Cell().Element(CellStyle).Text(page.width * inchesToPoints);\n                                table.Cell().Element(CellStyle).Text(page.height * inchesToPoints);\n\n                                IContainer CellStyle(IContainer container) =>\n                                    DefaultCellStyle(container, Colors.White).ShowOnce();\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => $\"table-header-and-footer-{x}.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/Text/ParagraphStyleExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.Text;\n\npublic class ParagraphStyleExamples\n{\n    [Test]\n    public void DefaultTextStyle()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(400, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.DefaultTextStyle(x => x.Light().LetterSpacing(-0.1f).WordSpacing(0.1f));\n\n                            text.Span(\"Changing typography settings helps creating \");\n                            text.Span(\"significant\").LetterSpacing(0.2f).Black().BackgroundColor(Colors.Grey.Lighten2);\n                            text.Span(\" visual contrast.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-paragraph-default-style.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void TextAlignment()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(400, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(20);\n                            \n                            column.Item()\n                                .Element(CellStyle)\n                                .Text(\"This is an example of left-aligned text, showcasing how the text starts from the left margin and continues naturally across the container.\")\n                                .AlignLeft();\n\n                            column.Item()\n                                .Element(CellStyle)\n                                .Text(\"This text is centered within its container, creating a balanced look, especially for titles or headers.\")\n                                .AlignCenter();\n\n                            column.Item()\n                                .Element(CellStyle)\n                                .Text(\"This example demonstrates right-aligned text, often used for dates, numbers, or aligning text to the right margin.\")\n                                .AlignRight();\n\n                            column.Item()\n                                .Element(CellStyle)\n                                .Text(\"Justified text adjusts the spacing between words so that both the left and right edges of the text block are aligned, creating a clean, newspaper-like look.\")\n                                .Justify();\n    \n                            static IContainer CellStyle(IContainer container) \n                                => container.Background(Colors.Grey.Lighten3).Padding(10);\n                        });\n\n                });\n            })\n            .GenerateImages(x => \"text-paragraph-alignment.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void FirstLineIndentation()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1200));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(Placeholders.Paragraphs())\n                        .ParagraphFirstLineIndentation(40);\n                });\n            })\n            .GenerateImages(x => \"text-paragraph-first-line-indentation.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.High, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Spacing()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1200));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(Placeholders.Paragraphs())\n                        .ParagraphSpacing(10);\n                });\n            })\n            .GenerateImages(x => \"text-paragraph-spacing.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.High, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void ClampLines()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n                    \n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n\n                            var paragraph = Placeholders.Paragraph();\n\n                            column.Item()\n                                .Background(Colors.Grey.Lighten3)\n                                .Padding(5)\n                                .Text(paragraph);\n                            \n                            column.Item()\n                                .Background(Colors.Grey.Lighten3)\n                                .Padding(5)\n                                .Text(paragraph)\n                                .ClampLines(3);\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-paragraph-clamp-lines.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void ClampLinesWithCustomEllipsis()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(Placeholders.Paragraph())\n                        .ClampLines(3, \" [...]\");\n                });\n            })\n            .GenerateImages(x => \"text-paragraph-clamp-lines-custom-ellipsis.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/Text/TextBasicExamples.cs",
    "content": "using System.Security.Cryptography;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.Text;\n\npublic class TextBasicExamples\n{\n    [Test]\n    public void Basic()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(\"Sample text\");\n                });\n            })\n            .GenerateImages(x => \"text-basic.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void BasicWithStyle()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n\n                            column.Item()\n                                .Element(CellStyle)\n                                .Text(\"Text with blue color\")\n                                .FontColor(Colors.Blue.Darken1);\n\n                            column.Item()\n                                .Element(CellStyle)\n                                .Text(\"Bold and underlined text\")\n                                .Bold()\n                                .Underline();\n\n                            column.Item()\n                                .Element(CellStyle)\n                                .Text(\"Centered small text\")\n                                .FontSize(12)\n                                .AlignCenter();\n\n                            static IContainer CellStyle(IContainer container) =>\n                                container.Background(Colors.Grey.Lighten3).Padding(10);\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-basic-descriptor.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Rich()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.AlignCenter();\n\n                            text.Span(\"The \");\n                            text.Span(\"chemical formula\").Underline();\n                            text.Span(\" of \");\n                            text.Span(\"sulfuric acid\").BackgroundColor(Colors.Amber.Lighten3);\n                            text.Span(\" is H\");\n                            text.Span(\"2\").Subscript();\n                            text.Span(\"SO\");\n                            text.Span(\"4\").Subscript();\n                            text.Span(\".\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-rich.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void StyleInheritance()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .DefaultTextStyle(style => style.FontSize(20))\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n                            \n                            column.Item().Text(\"Products\").ExtraBold().Underline().DecorationThickness(2);\n                            \n                            column.Item().Text(\"Comments: \" + Placeholders.Sentence());\n                            \n                            column.Item()\n                                .DefaultTextStyle(style => style.FontSize(14))\n                                .Table(table =>\n                                {\n                                    table.ColumnsDefinition(columns =>\n                                    {\n                                        columns.ConstantColumn(30);\n                                        columns.RelativeColumn(1);\n                                        columns.RelativeColumn(2);\n                                    });\n                            \n                                    table.Header(header =>\n                                    {\n                                        header.Cell().Element(Style).Text(\"ID\");\n                                        header.Cell().Element(Style).Text(\"Name\");\n                                        header.Cell().Element(Style).Text(\"Description\");\n\n                                        IContainer Style(IContainer container)\n                                        {\n                                            return container\n                                                .Background(Colors.Grey.Lighten3)\n                                                .BorderBottom(1)\n                                                .PaddingHorizontal(5)\n                                                .PaddingVertical(10)\n                                                .DefaultTextStyle(x => x.Bold().FontColor(Colors.Blue.Medium));\n                                        }\n                                    });\n\n                                    foreach (var i in Enumerable.Range(0, 5))\n                                    {\n                                        table.Cell().Element(Style).Text(i.ToString()).Bold();\n                                        table.Cell().Element(Style).Text(Placeholders.Label());\n                                        table.Cell().Element(Style).Text(Placeholders.Sentence());\n                                    }\n                                \n                                    IContainer Style(IContainer container)\n                                    {\n                                        return container.Padding(5);\n                                    }\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-style-inheritance.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void PageNumber()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Extend()\n                        .Placeholder();\n                    \n                    page.Footer()\n                        .PaddingTop(25)\n                        .AlignCenter()\n                        .Text(\"3 / 10\");\n                        // .Text(text =>\n                        // {\n                        //     text.CurrentPageNumber();\n                        //     text.Span(\" / \");\n                        //     text.TotalPages();\n                        // });\n                });\n            })\n            .GenerateImages(x => \"text-page-number.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void PageNumberFormat()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A5);\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.CurrentPageNumber().Format(FormatWithLeadingZeros);\n                        });\n                    \n                    static string FormatWithLeadingZeros(int? pageNumber)\n                    {\n                        const int expectedLength = 3;\n                        pageNumber ??= 1;\n                        return pageNumber.Value.ToString($\"D{expectedLength}\");\n                    }\n                });\n            })\n            .GenerateImages(x => \"text-page-number-format.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Hyperlink()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A6.Landscape());\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            var hyperlinkStyle = TextStyle.Default\n                                .FontColor(Colors.Blue.Medium)\n                                .Underline();\n        \n                            text.Span(\"To learn more about QuestPDF, please visit its \");\n                            text.Hyperlink(\"homepage\", \"https://www.questpdf.com/\").Style(hyperlinkStyle);\n                            text.Span(\", \");\n                            text.Hyperlink(\"GitHub repository\", \"https://github.com/QuestPDF/QuestPDF\").Style(hyperlinkStyle);\n                            text.Span(\" and \");\n                            text.Hyperlink(\"NuGet package page\", \"https://www.nuget.org/packages/QuestPDF\").Style(hyperlinkStyle);\n                            text.Span(\".\");\n                        });\n                });\n            })\n            .GeneratePdf(\"text-hyperlink.pdf\");\n    }\n\n    \n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/Text/TextInjectContent.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.Text;\n\npublic class TextInjectContent\n{\n    [Test]\n    public void InjectImage()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"A unit test can either \");\n                            text.Element().PaddingBottom(-4).Height(24).Image(\"Resources/unit-test-completed-icon.png\");\n                            text.Span(\" pass\").FontColor(Colors.Green.Medium);\n                            text.Span(\" or \");\n                            text.Element().PaddingBottom(-4).Height(24).Image(\"Resources/unit-test-failed-icon.png\");\n                            text.Span(\" fail\").FontColor(Colors.Red.Medium);\n                            text.Span(\".\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-inject-image.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void InjectSvg()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(350, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"To synchronize your email inbox, please click the \");\n                            text.Element().PaddingBottom(-4).Height(24).Svg(\"Resources/mail-synchronize-icon.svg\");\n                            text.Span(\" icon.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-inject-svg.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void InjectPosition()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(400, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"This \");\n    \n                            text.Element(TextInjectedElementAlignment.AboveBaseline)\n                                .Width(12).Height(12)\n                                .Background(Colors.Green.Medium);\n    \n                            text.Span(\" element is positioned above the baseline, while this \");\n    \n                            text.Element(TextInjectedElementAlignment.BelowBaseline)\n                                .Width(12).Height(12)\n                                .Background(Colors.Blue.Medium);\n    \n                            text.Span(\" element is positioned below the baseline.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-inject-position.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/Text/TextStyleExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples.Text;\n\npublic class TextStyleExamples\n{\n    [Test]\n    public void FontSize()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n\n                            column.Item()\n                                .Text(\"This is small text (16pt)\")\n                                .FontSize(16);\n\n                            column.Item()\n                                .Text(\"This is medium text (24pt)\")\n                                .FontSize(24);\n\n                            column.Item()\n                                .Text(\"This is large text (36pt)\")\n                                .FontSize(36);\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-font-size.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void FontFamily()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(10);\n\n                            column.Item().Text(\"This is text with default font (Lato)\");\n\n                            column.Item().Text(\"This is text with Times New Roman font\")\n                                .FontFamily(\"Times New Roman\");\n\n                            column.Item().Text(\"This is text with Courier New font\")\n                                .FontFamily(\"Courier New\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-font-family.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void FontColor()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"Each pixel consists of three sub-pixels: \");\n                            text.Span(\"red\").FontColor(Colors.Red.Medium);\n                            text.Span(\", \");\n                            text.Span(\"green\").FontColor(Colors.Green.Medium);\n                            text.Span(\" and \");\n                            text.Span(\"blue\").FontColor(Colors.Blue.Medium);\n                            text.Span(\".\");\n                        });\n                    });\n            })\n            .GenerateImages(x => \"text-font-color.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void BackgroundColor()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"The term \");\n                            text.Span(\"algorithm\").BackgroundColor(Colors.Yellow.Lighten3).Bold();\n                            text.Span(\" refers to a set of rules or steps used to solve a problem.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-font-background.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Italic()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"In this sentence, the word \");\n                            text.Span(\"important\").Italic();\n                            text.Span(\" is emphasized using italics.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-font-italic.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void FontWeight()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"This sentence demonstrates \");\n                            text.Span(\"bold\").Bold();\n                            text.Span(\", \");\n                            text.Span(\"normal\").NormalWeight();\n                            text.Span(\", \");\n                            text.Span(\"light\").Light();\n                            text.Span(\" and \");\n                            text.Span(\"thin\").Thin();\n                            text.Span(\" font weights.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-font-weight.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Subscript()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"H\");\n                            text.Span(\"2\").Subscript();\n                            text.Span(\"O is the chemical formula for water.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-subscript.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void Superscript()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"E = mc\");\n                            text.Span(\"2\").Superscript();\n                            text.Span(\" is the equation of mass-energy equivalence.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-superscript.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void LineHeight()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(20);\n\n                            float[] lineHeights = [0.75f, 1f, 2f];\n                            var paragraph = Placeholders.Paragraph();\n                            \n                            foreach (var lineHeight in lineHeights)\n                            {\n                                column\n                                    .Item()\n                                    .Background(Colors.Grey.Lighten3)\n                                    .Padding(5)\n                                    .Text(paragraph)\n                                    .FontSize(16)\n                                    .LineHeight(lineHeight);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-line-height.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void LetterSpacing()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(20);\n                            \n                            var letterSpacing = new[] { -0.08f, 0f, 0.2f };\n                            var paragraph = Placeholders.Sentence();\n\n                            foreach (var spacing in letterSpacing)\n                            {\n                                column\n                                    .Item()\n                                    .Background(Colors.Grey.Lighten3)\n                                    .Padding(5)\n                                    .Text(paragraph)\n                                    .FontSize(18)\n                                    .LetterSpacing(spacing);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-letter-spacing.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void WordSpacing()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Column(column =>\n                        {\n                            column.Spacing(20);\n                            \n                            var wordSpacing = new[] { -0.2f, 0f, 0.4f };\n                            var paragraph = Placeholders.Sentence();\n\n                            foreach (var spacing in wordSpacing)\n                            {\n                                column.Item()\n                                    .Background(Colors.Grey.Lighten3)\n                                    .Padding(5)\n                                    .Text(paragraph)\n                                    .FontSize(16)\n                                    .WordSpacing(spacing);\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-word-spacing.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void FontFallback()\n    {\n        Settings.UseEnvironmentFonts = false;\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(\"The Arabic word for programming is البرمجة.\")\n                        .FontFamily(\"Lato\", \"Noto Sans Arabic\");\n                });\n            })\n            .GenerateImages(x => \"text-font-fallback.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void FontFallbackEmoji()\n    {\n        Settings.UseEnvironmentFonts = false;\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(600, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(\"Popular emojis include 😊, 😂, ❤️, 👍, and 😎.\")\n                        .FontFamily(\"Lato\", \"Noto Emoji\");\n                });\n            })\n            .GenerateImages(x => \"text-font-fallback-emoji.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void TextFontFeatures()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Row(row =>\n                        {\n                            row.Spacing(25);\n    \n                            row.RelativeItem()\n                                .Background(Colors.Grey.Lighten3)\n                                .Padding(10)\n                                .Column(column =>\n                                {\n                                    column.Item().Text(\"Without ligatures\").FontSize(16);\n                                    \n                                    column.Item()\n                                        .Text(\"fly and fight\")\n                                        .FontSize(32)\n                                        .DisableFontFeature(FontFeatures.StandardLigatures);\n                                });\n    \n                            row.RelativeItem()\n                                .Background(Colors.Grey.Lighten3)\n                                .Padding(10)\n                                .Column(column =>\n                                {\n                                    column.Item().Text(\"With ligatures\").FontSize(16);\n                                    \n                                    column.Item().Text(\"fly and fight\")\n                                        .FontSize(32)\n                                        .EnableFontFeature(FontFeatures.StandardLigatures);\n                                });\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-font-features.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void DecorationTypes()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"There are a couple of available text decorations: \");\n                            text.Span(\"underline\").Underline().FontColor(Colors.Red.Medium);\n                            text.Span(\", \");\n                            text.Span(\"strikethrough\").Strikethrough().FontColor(Colors.Green.Medium);\n                            text.Span(\" and \");\n                            text.Span(\"overline\").Overline().FontColor(Colors.Blue.Medium);\n                            text.Span(\". \");\n                        });\n                }); \n            })\n            .GenerateImages(x => \"text-decoration-types.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void DecorationStyles()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"Moreover, the decoration can be \");\n                            \n                            text.Span(\"solid\").FontColor(Colors.Indigo.Medium).Underline().DecorationSolid();\n                            text.Span(\", \");\n                            text.Span(\"double\").FontColor(Colors.Blue.Medium).Underline().DecorationDouble();\n                            text.Span(\", \");\n                            text.Span(\"wavy\").FontColor(Colors.LightBlue.Medium).Underline().DecorationWavy();\n                            text.Span(\", \");\n                            text.Span(\"dotted\").FontColor(Colors.Cyan.Medium).Underline().DecorationDotted();\n                            text.Span(\" or \");\n                            text.Span(\"dashed\").FontColor(Colors.Green.Medium)\n                                .Underline().DecorationDashed();\n                            text.Span(\".\");\n                        });\n                }); \n            })\n            .GenerateImages(x => \"text-decoration-styles.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n    \n    [Test]\n    public void DecorationsAdvanced()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(500, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .Text(text =>\n                        {\n                            text.Span(\"This text contains a \");\n                            \n                            text.Span(\"seriuos\")\n                                .Underline()\n                                .DecorationWavy()\n                                .DecorationColor(Colors.Red.Medium)\n                                .DecorationThickness(2);\n                            \n                            text.Span(\" typo.\");\n                        });\n                });\n            })\n            .GenerateImages(x => \"text-decoration-advanced.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.Best, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/TranslateExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class TranslateExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(400, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Padding(50)\n                        .Background(Colors.Blue.Lighten3)\n                        .TranslateX(25)\n                        .TranslateY(25)\n                        .Border(4)\n                        .BorderColor(Colors.Blue.Darken2)\n                        .Padding(50)\n                        .Text(\"Moved content\")\n                        .FontSize(25);\n                });\n            })\n            .GenerateImages(x => \"translate.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/UnconstrainedExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class UnconstrainedExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n\n                    page.Content()\n                        .Width(400)\n                        .Height(350)\n                        .Padding(25)\n                        .PaddingLeft(50) \n                        .Column(column =>\n                        {\n                            column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten3);\n\n                            column\n                                .Item()\n                                .Unconstrained()\n                                .TranslateX(-50)\n                                .TranslateY(-50)\n                                .Width(100)\n                                .Height(100)\n                                .Background(Colors.Blue.Darken2);\n\n                            column.Item().Width(300).Height(150).Background(Colors.Blue.Lighten2);\n                        });\n                });\n            })\n            .GenerateImages(x => \"unconstrained.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.DocumentationExamples/ZIndexExamples.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.DocumentationExamples;\n\npublic class ZIndexExamples\n{\n    [Test]\n    public void Example()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(650, 0));\n                    page.MaxSize(new PageSize(650, 1000));\n                    page.DefaultTextStyle(x => x.FontSize(20));\n                    page.Margin(25);\n\n                    page.Content()\n                        .PaddingVertical(15)\n                        .Border(2)\n                        .Row(row =>\n                        {\n                            row.RelativeItem()\n                                .Background(Colors.Grey.Lighten3)\n                                .Element(c => AddPricingItem(c, \"Community\", \"Free\"));\n                            \n                            row.RelativeItem()\n                                .ZIndex(1) // -1 or 0 or 1\n                                .Padding(-15)\n                                .Border(1)\n                                .Background(Colors.Grey.Lighten1)\n                                .PaddingTop(15)\n                                .Element(c => AddPricingItem(c, \"Professional\", \"$699\"));\n                            \n                            row.RelativeItem()\n                                .Background(Colors.Grey.Lighten3)\n                                .Element(c => AddPricingItem(c, \"Enterprise\", \"$1999\")); \n\n                            void AddPricingItem(IContainer container, string name, string formattedPrice)\n                            {\n                                container\n                                    .Padding(25)\n                                    .Column(column =>\n                                    {\n                                        column.Item().AlignCenter().Text(name).FontSize(24).Black();\n                                        column.Item().AlignCenter().Text(formattedPrice).FontSize(20).SemiBold();\n                                        \n                                        column.Item().PaddingHorizontal(-25).PaddingVertical(10).LineHorizontal(1);\n                                        \n                                        foreach (var i in Enumerable.Range(1, 4))\n                                        {\n                                            column.Item()\n                                                .PaddingTop(10)\n                                                .AlignCenter()\n                                                .Text(Placeholders.Label())\n                                                .FontSize(16)\n                                                .Light();\n                                        }\n                                    });\n                            }\n                        });\n                });\n            })\n            .GenerateImages(x => \"zindex-positive.webp\", new ImageGenerationSettings() { ImageFormat = ImageFormat.Webp, ImageCompressionQuality = ImageCompressionQuality.VeryHigh, RasterDpi = 144 });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/ColumnTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\npublic class ColumnTests\n{\n    [Test]\n    public void Typical()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 140)\n            .ForContent(content =>\n            {\n                content.Shrink().Column(column =>\n                {\n                    column.Spacing(10);\n                    \n                    column.Item().Mock(\"a\").ContinuousBlock(50, 30);\n                    column.Item().Mock(\"b\").ContinuousBlock(40, 20);\n                    column.Item().Mock(\"c\").ContinuousBlock(70, 40);\n                    column.Item().Mock(\"d\").ContinuousBlock(60, 60);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(70, 140)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(70, 30);\n                        page.Mock(\"b\").Position(0, 40).Size(70, 20);\n                        page.Mock(\"c\").Position(0, 70).Size(70, 40);\n                        page.Mock(\"d\").Position(0, 120).Size(70, 20);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(60, 40)\n                    .Content(page =>\n                    {\n                        page.Mock(\"d\").Position(0, 0).Size(60, 40);\n                    });\n            });\n    }\n\n    [Test]\n    public void SingleItem()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Column(column =>\n                {\n                    column.Spacing(10);\n                    column.Item().Mock(\"a\").ContinuousBlock(50, 30);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(50, 30)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(50, 30);\n                    });\n            });\n    }\n\n    [Test]\n    public void ZeroHeightItemDoesNotConsumeSpacing()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Column(column =>\n                {\n                    column.Spacing(10);\n                    \n                    column.Item().Mock(\"a\").ContinuousBlock(50, 30);\n                    column.Item().Mock(\"b\").ContinuousBlock(50, 0);\n                    column.Item().Mock(\"c\").ContinuousBlock(70, 20);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(70, 60)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(70, 30);\n                        page.Mock(\"b\").Position(0, 30).Size(70, 0);\n                        page.Mock(\"c\").Position(0, 40).Size(70, 20);\n                    });\n            });\n    }\n\n    [Test]\n    public void NoSpacing()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Column(column =>\n                {\n                    column.Spacing(0);\n                    \n                    column.Item().Mock(\"a\").ContinuousBlock(50, 30);\n                    column.Item().Mock(\"b\").ContinuousBlock(40, 20);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(50, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(50, 30);\n                        page.Mock(\"b\").Position(0, 30).Size(50, 20);\n                    });\n            });\n    }\n\n    [Test]\n    public void PartialRenderItem()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 80)\n            .ForContent(content =>\n            {\n                content.Shrink().Column(column =>\n                {\n                    column.Spacing(5);\n                    \n                    column.Item().Mock(\"a\").ContinuousBlock(50, 40);\n                    column.Item().Mock(\"b\").ContinuousBlock(60, 50);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(60, 80)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(60, 40);\n                        page.Mock(\"b\").Position(0, 45).Size(60, 35);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(60, 15)\n                    .Content(page =>\n                    {\n                        page.Mock(\"b\").Position(0, 0).Size(60, 15);\n                    });\n            });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/LineTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\npublic class LineTests\n{\n    [Test]\n    public void VerticalLineRequiresSpaceEqualToItsThickness()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(5, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().LineVertical(10);\n            })\n            .ExpectLayoutException(\"The line thickness is greater than the available horizontal space.\");\n    }\n    \n    [Test]\n    public void HorizontalLineRequiresSpaceEqualToItsThickness()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 5)\n            .ForContent(content =>\n            {\n                content.Shrink().LineHorizontal(10);\n            })\n            .ExpectLayoutException(\"The line thickness is greater than the available vertical space.\");\n    }\n    \n    #region Stateful\n    \n    [Test]\n    public void CheckRenderingState()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(240, 100)\n            .ForContent(content =>\n            {\n                content.ShrinkVertical().Mock(\"a\").LineHorizontal(2);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(0, 2)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(240, 2).State(true);\n                    });\n            });\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/MultiColumnTests.cs",
    "content": "using QuestPDF.Elements;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.LayoutTests;\n\npublic class MultiColumnTests\n{\n    [Test]\n    public void DynamicComponent()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(400, 200)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .MultiColumn(column =>\n                    {\n                        column.Content()\n                            .Mock(\"dynamic\")\n                            .Dynamic(new CounterComponent());\n                    });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(400, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"dynamic\")\n                            .Position(0, 0)\n                            .Size(200, 50)\n                            .State(new DynamicHost.DynamicState()\n                            {\n                                IsRendered = false,\n                                RenderCount = 1,\n                                ChildState = 2\n                            });\n                        \n                        page.Mock(\"dynamic\")\n                            .Position(200, 0)\n                            .Size(200, 50)\n                            .State(new DynamicHost.DynamicState()\n                            {\n                                IsRendered = false,\n                                RenderCount = 2,\n                                ChildState = 3\n                            });\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(400, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"dynamic\")\n                            .Position(0, 0)\n                            .Size(200, 50)\n                            .State(new DynamicHost.DynamicState()\n                            {\n                                IsRendered = false,\n                                RenderCount = 3,\n                                ChildState = 4\n                            });\n                        \n                        page.Mock(\"dynamic\")\n                            .Position(200, 0)\n                            .Size(200, 50)\n                            .State(new DynamicHost.DynamicState()\n                            {\n                                IsRendered = false,\n                                RenderCount = 4,\n                                ChildState = 5\n                            });\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(400, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"dynamic\")\n                            .Position(0, 0)\n                            .Size(200, 50)\n                            .State(new DynamicHost.DynamicState()\n                            {\n                                IsRendered = true,\n                                RenderCount = 5,\n                                ChildState = 6\n                            });\n                    });\n            });\n    }\n    \n    public class CounterComponent : IDynamicComponent<int>\n    {\n        public int State { get; set; } = 1;\n        \n        public DynamicComponentComposeResult Compose(DynamicContext context)\n        {\n            var content = context.CreateElement(element =>\n            {\n                element\n                    .Width(100)\n                    .Height(50)\n                    .Background(Colors.Grey.Lighten2)\n                    .AlignCenter()\n                    .AlignMiddle()\n                    .Text($\"Item {State}\")\n                    .SemiBold();\n            });\n\n            State++;\n\n            return new DynamicComponentComposeResult\n            {\n                Content = content,\n                HasMoreContent = State <= 5\n            };\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/PaddingTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\n[TestFixture]\npublic class PaddingTests\n{\n    [Test]\n    public void PaddingModifiesPositioningAndMinimumSize()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .PaddingLeft(5)\n                    .PaddingTop(10)\n                    .PaddingRight(15)\n                    .PaddingBottom(20)\n                    .Mock(\"a\")\n                    .SolidBlock(20, 30);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(40, 60)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(5, 10).Size(20, 30);\n                    });\n            });\n    }\n    \n    [Test]\n    public void NegativePaddingIsAllowed()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .Padding(-10)\n                    .Mock(\"a\")\n                    .SolidBlock(50, 70);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(30, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(-10, -10).Size(50, 70);\n                    });\n            });\n    }\n    \n    [Test]\n    public void PaddingSupportsPaging()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .Padding(15)\n                    .Mock(\"a\")\n                    .ContinuousBlock(50, 90);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(80, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(15, 15).Size(50, 70);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(80, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(15, 15).Size(50, 20);\n                    });\n            });\n    }\n    \n    [Test]\n    public void MultipleItemsWithAppliedPadding()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 150)\n            .ForContent(content =>\n            {\n                content.Shrink().Column(column =>\n                {\n                    column.Item().PaddingVertical(5).Mock(\"a\").SolidBlock(15, 25);\n                    column.Item().PaddingHorizontal(10).Mock(\"b\").SolidBlock(20, 30);\n                    column.Item().Padding(15).Mock(\"c\").SolidBlock(25, 35);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(55, 130)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 5).Size(55, 25);\n                        page.Mock(\"b\").Position(10, 35).Size(35, 30);\n                        page.Mock(\"c\").Position(15, 80).Size(25, 35);\n                    });\n            });\n    }\n    \n    [Test]\n    public void PaddingProducesAvailableSpaceOfNegativeSize()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 150)\n            .ForContent(content =>\n            {\n                content.Shrink().Padding(60).SolidBlock(20, 25);\n            })\n            .ExpectLayoutException(\"The available space is negative.\");\n    }\n    \n    [Test]\n    public void PaddingWithEmptyChild()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 150)\n            .ForContent(content =>\n            {\n                content.Shrink().Padding(30);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(60, 60);\n            });\n    }\n    \n    [Test]\n    public void PaddingOnEmptyElementProducesAvailableSpaceOfNegativeSize()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 150)\n            .ForContent(content =>\n            {\n                content.Shrink().Padding(60);\n            })\n            .ExpectLayoutException(\"The available space is negative.\");\n    }\n    \n    [Test]\n    public void PaddingOnEmptyElementProducesAvailableSpaceOfNegativeSize2()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 150)\n            .ForContent(content =>\n            {\n                content.Shrink().Padding(60).Column(column => { });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(0, 0);\n            });\n    }\n    \n    [Test]\n    public void NegativePaddingProducesMeasurementOfNegativeSize()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 150)\n            .ForContent(content =>\n            {\n                content.Shrink().Padding(-15).Mock(\"a\").SolidBlock(20, 40);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(0, 10)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(-15, -15).Size(30, 40);\n                    });\n            });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/QuestPDF.LayoutTests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <ImplicitUsings>enable</ImplicitUsings>\n        <Nullable>enable</Nullable>\n        <SatelliteResourceLanguages>en</SatelliteResourceLanguages>\n\n        <IsPackable>false</IsPackable>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.13.0\" />\n        <PackageReference Include=\"NUnit\" Version=\"4.4.0\" />\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"4.11.2\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"6.1.0\" />\n        <PackageReference Include=\"SkiaSharp\" Version=\"3.119.1\" />\n        <PackageReference Include=\"SkiaSharp.NativeAssets.Linux.NoDependencies\" Version=\"3.119.1\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\QuestPDF\\QuestPDF.csproj\" />\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/RotateTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\npublic class RotateTests\n{\n    [Test]\n    public void SimpleRotation()\n    {\n        const float angle = 60;\n        const float armLength = 100;\n        \n        var expectedX = armLength * MathF.Cos(float.DegreesToRadians(angle));\n        var expectedY = armLength * MathF.Sin(float.DegreesToRadians(angle));\n        \n        Assert.That(expectedX, Is.EqualTo(50).Within(0.1f));\n        Assert.That(expectedY, Is.EqualTo(86.6).Within(0.1f));\n        \n        LayoutTest\n            .HavingSpaceOfSize(500, 500)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .Rotate(angle)\n                    .TranslateX(armLength)\n                    .Mock(\"a\")\n                    .SolidBlock(100, 100);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(expectedX, expectedY).Size(100, 100);\n                    });\n            });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/RowTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\n[TestFixture]\npublic class RowTests\n{\n    #region General Item Positioning\n    \n    [Test]\n    public void SingleConstantItem()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(40).Mock(\"a\").Height(30);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(40, 30)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(40, 30);\n                    });\n            });\n    }\n    \n    [Test]\n    public void MultipleConstantItems()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(20).Mock(\"a\").Height(30);\n                    row.ConstantItem(30).Mock(\"b\").Height(40);\n                    row.ConstantItem(40).Mock(\"c\").Height(20);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(90, 40)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(20, 40);\n                        page.Mock(\"b\").Position(20, 0).Size(30, 40);\n                        page.Mock(\"c\").Position(50, 0).Size(40, 40);\n                    });\n            });\n    }\n    \n    [Test]\n    public void SingleRelativeItem()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.RelativeItem().Mock(\"a\").Height(30);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 30)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 30);\n                    });\n            });\n    }\n    \n    [Test]\n    public void TwoRelativeItems()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.RelativeItem(2).Mock(\"a\").Height(40);\n                    row.RelativeItem(3).Mock(\"b\").Height(50);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(40, 50);\n                        page.Mock(\"b\").Position(40, 0).Size(60, 50);\n                    });\n            });\n    }\n    \n    [Test]\n    public void SingleAutoItem()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.AutoItem().Mock(\"a\").Size(60, 40);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(60, 40)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(60, 40);\n                    });\n            });\n    }\n    \n    [Test]\n    public void RelativeItemFillsRemainingSpace()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(20).Mock(\"a\").Height(30);\n                    row.ConstantItem(30).Mock(\"b\").Height(50);\n                    row.RelativeItem().Mock(\"c\").Height(40);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(20, 50);\n                        page.Mock(\"b\").Position(20, 0).Size(30, 50);\n                        page.Mock(\"c\").Position(50, 0).Size(50, 50);\n                    });\n            });\n    }\n    \n    [Test]\n    public void RelativeItemsSplitRemainingSpaceAccordingToProportions()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(30).Mock(\"a\").Height(60);\n                    row.RelativeItem(4).Mock(\"b\").Height(40);\n                    row.RelativeItem(3).Mock(\"c\").Height(30);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 60)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(30, 60);\n                        page.Mock(\"b\").Position(30, 0).Size(40, 60);\n                        page.Mock(\"c\").Position(70, 0).Size(30, 60);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ComplexItems()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(200, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(30).Mock(\"a\").Height(60);\n                    row.RelativeItem(1).Mock(\"b\").Height(40);\n                    row.RelativeItem(2).Mock(\"c\").Height(30);\n                    row.ConstantItem(20).Mock(\"d\").Height(30);\n                    row.RelativeItem(3).Mock(\"e\").Height(20);\n                    row.RelativeItem(2).Mock(\"f\").Height(70);\n                    row.AutoItem().Mock(\"g\").Size(40, 50);\n                    row.AutoItem().Mock(\"h\").Size(30, 40);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(200, 70)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(30, 70);\n                        page.Mock(\"b\").Position(30, 0).Size(10, 70);\n                        page.Mock(\"c\").Position(40, 0).Size(20, 70);\n                        page.Mock(\"d\").Position(60, 0).Size(20, 70);\n                        page.Mock(\"e\").Position(80, 0).Size(30, 70);\n                        page.Mock(\"f\").Position(110, 0).Size(20, 70);\n                        page.Mock(\"g\").Position(130, 0).Size(40, 70);\n                        page.Mock(\"h\").Position(170, 0).Size(30, 70);\n                    });\n            });\n    }\n    \n    #endregion\n    \n    #region Drawing On Multiple Pages\n    \n    [Test]\n    public void OneItemSpansTwoPages()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(80, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.RelativeItem().Mock(\"a\").SolidBlock(height: 40);\n                    row.RelativeItem().Mock(\"b\").SolidBlock(height: 80);\n                    row.RelativeItem(2).Mock(\"c\").ContinuousBlock(20, 140);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(80, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(20, 100);\n                        page.Mock(\"b\").Position(20, 0).Size(20, 100);\n                        page.Mock(\"c\").Position(40, 0).Size(40, 100);\n                    });\n            \n                document\n                    .Page()\n                    .RequiredAreaSize(80, 40)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(20, 40);\n                        page.Mock(\"b\").Position(20, 0).Size(20, 40);\n                        page.Mock(\"c\").Position(40, 0).Size(40, 40);\n                    });\n            });  \n    }\n    \n    #endregion\n\n    #region Spacing\n\n    [Test]\n    public void NoSpacing()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(10).Mock(\"a\").SolidBlock(height: 40);\n                    row.ConstantItem(20).Mock(\"b\").SolidBlock(height: 50);\n                    row.ConstantItem(30).Mock(\"c\").SolidBlock(height: 30);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(60, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(10, 50);\n                        page.Mock(\"b\").Position(10, 0).Size(20, 50);\n                        page.Mock(\"c\").Position(30, 0).Size(30, 50);\n                    });\n            });\n    }\n    \n    [Test]\n    public void NormalSpacing()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.Spacing(10);\n                    \n                    row.ConstantItem(10).Mock(\"a\").SolidBlock(height: 40);\n                    row.ConstantItem(20).Mock(\"b\").SolidBlock(height: 50);\n                    row.ConstantItem(30).Mock(\"c\").SolidBlock(height: 30);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(80, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(10, 50);\n                        page.Mock(\"b\").Position(20, 0).Size(20, 50);\n                        page.Mock(\"c\").Position(50, 0).Size(30, 50);\n                    });\n            });\n    }\n    \n    [Test]\n    public void BiggerSpacing()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.Spacing(15);\n                    \n                    row.ConstantItem(10).Mock(\"a\").SolidBlock(height: 40);\n                    row.ConstantItem(20).Mock(\"b\").SolidBlock(height: 50);\n                    row.ConstantItem(30).Mock(\"c\").SolidBlock(height: 30);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(90, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(10, 50);\n                        page.Mock(\"b\").Position(25, 0).Size(20, 50);\n                        page.Mock(\"c\").Position(60, 0).Size(30, 50);\n                    });\n            });\n    }\n    \n    [Test]\n    public void SpacingDoesNotFitInAvailableSpace()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.Spacing(20);\n\n                    row.ConstantItem(30).Height(50);\n                    row.ConstantItem(30).Height(50);\n                    row.ConstantItem(30).Height(50);\n                });\n            })\n            .ExpectLayoutException(\"The content requires more horizontal space than available.\");\n    }\n    \n    [Test]\n    public void SpacingIsLargerThanAvailableSpace()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.Spacing(200);\n                    \n                    row.ConstantItem(10).SolidBlock(height: 40); // <-\n                });\n            })\n            .ExpectLayoutException(\"The content requires more horizontal space than available.\");\n    }\n    \n    [Test]\n    public void NotEnoughSpaceForRelativeItemsAfterApplyingSpacing()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.Spacing(20);\n                    \n                    row.ConstantItem(40);\n                    row.ConstantItem(40);\n                    row.RelativeItem();\n                });\n            })\n            .ExpectLayoutException(\"One of the items has a negative size, indicating insufficient horizontal space. Usually, constant items require more space than is available, potentially causing other content to overflow.\");\n    }\n\n    #endregion\n    \n    #region Paging\n    \n    [Test]\n    public void OneItemRequiresTwoPages()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.RelativeItem(2).Mock(\"a\").Height(30);\n                    row.RelativeItem(3).Mock(\"b\").ContinuousBlock(height: 140);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(40, 100);\n                        page.Mock(\"b\").Position(40, 0).Size(60, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(100, 40)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(40, 40);\n                        page.Mock(\"b\").Position(40, 0).Size(60, 40);\n                    });\n            });\n    } \n    \n    [Test]\n    public void ItemsRequireMultiplePages()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.RelativeItem(2).Mock(\"a\").ContinuousBlock(height: 230);\n                    row.RelativeItem(3).Mock(\"b\").ContinuousBlock(height: 140);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(40, 100);\n                        page.Mock(\"b\").Position(40, 0).Size(60, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(100, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(40, 100);\n                        page.Mock(\"b\").Position(40, 0).Size(60, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(100, 30)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(40, 30);\n                        page.Mock(\"b\").Position(40, 0).Size(60, 30);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ItemHeightExceedsAvailableHeight()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(40).Height(50);\n                    row.ConstantItem(40).Height(200); // <-\n                });\n            })\n            .ExpectLayoutException(\"The available vertical space is less than the minimum height.\");\n    }\n    \n    #endregion\n    \n    #region Right-To-Left Direction\n    \n    [Test]\n    public void RightToLeftDirection()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.ContentFromRightToLeft().Shrink().Row(row =>\n                {\n                    row.ConstantItem(20).Mock(\"a\").Height(30);\n                    row.ConstantItem(30).Mock(\"b\").Height(40);\n                    row.ConstantItem(40).Mock(\"c\").Height(20);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(90, 40)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(80, 0).Size(20, 40);\n                        page.Mock(\"b\").Position(50, 0).Size(30, 40);\n                        page.Mock(\"c\").Position(10, 0).Size(40, 40);\n                    });\n            });\n    } \n    \n    #endregion\n    \n    #region Layout Exceptions\n    \n    [Test]\n    public void ConstantItemOfTooLargeSize()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(200);  // <-\n                });\n            })\n            .ExpectLayoutException(\"The content requires more horizontal space than available.\");\n    }\n    \n    [Test]\n    public void ConstantItemHasChildOfTooLargeSize()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(30).Width(20);\n                    row.ConstantItem(40).Width(200); // <-\n                });\n            })\n            .ExpectLayoutException(\"The available horizontal space is less than the minimum width.\");\n    }\n    \n    [Test]\n    public void SumOfConstantItemsExceedsAvailableWidth()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(40);\n                    row.ConstantItem(40);\n                    row.ConstantItem(40);\n                });\n            })\n            .ExpectLayoutException(\"The content requires more horizontal space than available.\");\n    }\n    \n    [Test]\n    public void RelativeItemHasChildOfTooLargeSize()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.RelativeItem(2).Width(30);\n                    row.RelativeItem(3).Width(200); // <-\n                });\n            })\n            .ExpectLayoutException(\"The available horizontal space is less than the minimum width.\");\n    }\n    \n    [Test]\n    public void AutoItemHasChildOfTooLargeSize()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(30);\n                    row.AutoItem().Width(80);\n                });\n            })\n            .ExpectLayoutException(\"The content requires more horizontal space than available.\");\n    }\n    \n    [Test]\n    public void SumOfAutoItemsExceedsAvailableWidth()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.AutoItem().Width(30);\n                    row.AutoItem().Width(40);\n                    row.AutoItem().Width(50);\n                });\n            })\n            .ExpectLayoutException(\"The content requires more horizontal space than available.\");\n    }\n    \n    [Test]\n    public void SumOfVariousItemsExceedsAvailableWidth()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.ConstantItem(60);\n                    row.AutoItem().Width(50);\n                });\n            })\n            .ExpectLayoutException(\"The content requires more horizontal space than available.\");\n    }\n    \n    #endregion\n    \n    #region Corner Cases\n    \n    [Test]\n    public void NoItems()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    // <-\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(0, 0)\n                    .Content(page => { });\n            });\n    }\n    \n    [Test]\n    public void RerenderingOfFullyDrawnRow()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Row(row =>\n                {\n                    row.RelativeItem().Mock(\"a\").Row(innerRow =>\n                    {\n                        innerRow.RelativeItem().Mock(\"b\").SolidBlock(20, 50);\n                        innerRow.RelativeItem().Mock(\"c\").SolidBlock(15, 40);\n                    });\n                    \n                    row.RelativeItem().Mock(\"d\").ContinuousBlock(40, 140);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(50, 100);\n                        page.Mock(\"b\").Position(0, 0).Size(25, 100);\n                        page.Mock(\"c\").Position(25, 0).Size(25, 100);\n                        page.Mock(\"d\").Position(50, 0).Size(50, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(100, 40)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(50, 40);\n                        page.Mock(\"d\").Position(50, 0).Size(50, 40);\n                    });\n            });\n    }\n    \n    #endregion\n    \n    #region Stateful\n    \n    [Test]\n    public void CheckRenderingState()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(240, 100)\n            .ForContent(content =>\n            {\n                content.Shrink().Mock(\"a\").Row(innerRow =>\n                {\n                    innerRow.RelativeItem().ContinuousBlock(50, 80);\n                    innerRow.RelativeItem().ContinuousBlock(50, 250);\n                    innerRow.RelativeItem().ContinuousBlock(50, 170);\n                    innerRow.RelativeItem().ContinuousBlock(50, 320);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(240, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(240, 100).State(new[] { true, false, false, false });\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(240, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(240, 100).State(new[] { true, false, true, false });\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(240, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(240, 100).State(new[] { true, true, true, false });\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(240, 20)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(240, 20).State(new[] { true, true, true, true });\n                    });\n            });\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/ScaleTests.cs",
    "content": "using QuestPDF.Helpers;\n\nnamespace QuestPDF.LayoutTests;\n\npublic class ScaleTests\n{\n    private void DrawTestSubject(IContainer container)\n    {\n        container\n            .Inlined(inlined =>\n            {\n                inlined.Item().Mock(\"a\").SolidBlock(100, 100);\n                inlined.Item().Mock(\"b\").SolidBlock(100, 100);\n                inlined.Item().Mock(\"c\").SolidBlock(100, 100);\n                inlined.Item().Mock(\"d\").SolidBlock(100, 100);\n                inlined.Item().Mock(\"e\").SolidBlock(100, 100);\n                inlined.Item().Mock(\"f\").SolidBlock(100, 100);\n            });\n    }\n    \n    [Test]\n    public void DefaultScale()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(800, 500)\n            .ForContent(content =>\n            {\n                content.Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(600, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(100, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(200, 0).Size(100, 100);\n                        page.Mock(\"d\").Position(300, 0).Size(100, 100);\n                        page.Mock(\"e\").Position(400, 0).Size(100, 100);\n                        page.Mock(\"f\").Position(500, 0).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void PositiveScale05()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(800, 500)\n            .ForContent(content =>\n            {\n                content.Scale(0.5f).Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(300, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(50, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(100, 0).Size(100, 100);\n                        page.Mock(\"d\").Position(150, 0).Size(100, 100);\n                        page.Mock(\"e\").Position(200, 0).Size(100, 100);\n                        page.Mock(\"f\").Position(250, 0).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void PositiveScale15()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(800, 500)\n            .ForContent(content =>\n            {\n                content.Scale(1.5f).Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(750, 300)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(150, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(300, 0).Size(100, 100);\n                        page.Mock(\"d\").Position(450, 0).Size(100, 100);\n                        page.Mock(\"e\").Position(600, 0).Size(100, 100);\n                        page.Mock(\"f\").Position(0, 150).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void PositiveScale25()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(800, 500)\n            .ForContent(content =>\n            {\n                content.Scale(2.5f).Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(750, 500)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(250, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(500, 0).Size(100, 100);\n                        page.Mock(\"d\").Position(0, 250).Size(100, 100);\n                        page.Mock(\"e\").Position(250, 250).Size(100, 100);\n                        page.Mock(\"f\").Position(500, 250).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void PositiveScaleTwoPages()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(800, 250)\n            .ForContent(content =>\n            {\n                content.Scale(2).Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(800, 200)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(200, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(400, 0).Size(100, 100);\n                        page.Mock(\"d\").Position(600, 0).Size(100, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(400, 200)\n                    .Content(page =>\n                    {\n                        page.Mock(\"e\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"f\").Position(200, 0).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ScaleVertical()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(450, 800)\n            .ForContent(content =>\n            {\n                content.ScaleVertical(2f).Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(400, 400)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(100, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(200, 0).Size(100, 100);\n                        page.Mock(\"d\").Position(300, 0).Size(100, 100);\n                        page.Mock(\"e\").Position(0, 200).Size(100, 100);\n                        page.Mock(\"f\").Position(100, 200).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ScaleVerticalNegative()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(400, 500)\n            .ForContent(content =>\n            {\n                content.ScaleVertical(-1.5f).Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(400, 300)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 500).Size(100, 100);\n                        page.Mock(\"b\").Position(100, 500).Size(100, 100);\n                        page.Mock(\"c\").Position(200, 500).Size(100, 100);\n                        page.Mock(\"d\").Position(300, 500).Size(100, 100);\n                        page.Mock(\"e\").Position(0, 350).Size(100, 100);\n                        page.Mock(\"f\").Position(100, 350).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ScaleHorizontal()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(450, 800)\n            .ForContent(content =>\n            {\n                content.ScaleHorizontal(2f).Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(400, 300)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(200, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(0, 100).Size(100, 100);\n                        page.Mock(\"d\").Position(200, 100).Size(100, 100);\n                        page.Mock(\"e\").Position(0, 200).Size(100, 100);\n                        page.Mock(\"f\").Position(200, 200).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ScaleHorizontalNegative()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(700, 400)\n            .ForContent(content =>\n            {\n                content.ScaleHorizontal(-1.5f).Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(600, 200)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(700, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(550, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(400, 0).Size(100, 100);\n                        page.Mock(\"d\").Position(250, 0).Size(100, 100);\n                        page.Mock(\"e\").Position(700, 100).Size(100, 100);\n                        page.Mock(\"f\").Position(550, 100).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void WrapHorizontal()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Scale(3).Width(50).Height(10);\n            })\n            .ExpectLayoutException(\"The available horizontal space is less than the minimum width.\");\n    }\n    \n    [Test]\n    public void WrapVertical()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Scale(3).Width(10).Height(50);\n            })\n            .ExpectLayoutException(\"The available vertical space is less than the minimum height.\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/Setup.cs",
    "content": "﻿namespace QuestPDF.LayoutTests\n{\n    [SetUpFixture]\n    public class Setup\n    {\n        [OneTimeSetUp]\n        public static void Configure()\n        {\n            QuestPDF.Settings.License = LicenseType.Community;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/ShowIfTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\npublic class ShowIfTests\n{\n    [Test]\n    public void Scenario()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Decoration(decoration =>\n                {\n                    decoration.Before().ShowIf(c => c.PageNumber % 2 == 0).Mock(\"before\").Size(80, 20);\n                    decoration.Content().Mock(\"content\").ContinuousBlock(70, 460);\n                    decoration.After().ShowIf(c => c.PageNumber % 3 == 0).Mock(\"after\").Size(90, 30);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(70, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"content\").Position(0, 0).Size(70, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(80, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"before\").Position(0, 0).Size(80, 20);\n                        page.Mock(\"content\").Position(0, 20).Size(80, 80);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(90, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"content\").Position(0, 0).Size(90, 70);\n                        page.Mock(\"after\").Position(0, 70).Size(90, 30);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(80, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"before\").Position(0, 0).Size(80, 20);\n                        page.Mock(\"content\").Position(0, 20).Size(80, 80);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(70, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"content\").Position(0, 0).Size(70, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(90, 80)\n                    .Content(page =>\n                    {\n                        page.Mock(\"before\").Position(0, 0).Size(90, 20);\n                        page.Mock(\"content\").Position(0, 20).Size(90, 30);\n                        page.Mock(\"after\").Position(0, 50).Size(90, 30);\n                    });\n            });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/ShrinkTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\npublic class ShrinkTests\n{\n    [Test]\n    public void Both()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 120)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .Mock(\"a\").ContinuousBlock(60, 200);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(60, 120)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(60, 120);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(60, 80)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(60, 80);\n                    });\n            });\n    }\n    \n    [Test]\n    public void Vertical()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 120)\n            .ForContent(content =>\n            {\n                content\n                    .ShrinkVertical()\n                    .Mock(\"a\").ContinuousBlock(60, 200);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(60, 120)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 120);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(60, 80)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 80);\n                    });\n            });\n    }\n    \n    [Test]\n    public void Horizontal()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 120)\n            .ForContent(content =>\n            {\n                content\n                    .ShrinkHorizontal()\n                    .Mock(\"a\").ContinuousBlock(60, 200);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(60, 120)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(60, 120);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(60, 80)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(60, 120);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ContentFromRightToLeft()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 120)\n            .ForContent(content =>\n            {\n                content\n                    .ContentFromRightToLeft()\n                    .Shrink()\n                    .Mock(\"a\").ContinuousBlock(60, 200);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(60, 120)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(40, 0).Size(60, 120);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(60, 80)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(40, 0).Size(60, 80);\n                    });\n            });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/SimpleRotateTests.cs",
    "content": "using QuestPDF.Helpers;\n\nnamespace QuestPDF.LayoutTests;\n\npublic class SimpleRotateTests\n{\n    private void DrawTestSubject(IContainer container)\n    {\n        container\n            .Column(column =>\n            {\n                column.Item().Row(row =>\n                {\n                    row.AutoItem().Mock(\"a\").SolidBlock(100, 100);\n                    row.AutoItem().Mock(\"b\").SolidBlock(100, 100);\n                    row.AutoItem().Mock(\"c\").SolidBlock(100, 100);\n                });\n                \n                column.Item().Row(row =>\n                {\n                    row.AutoItem().Mock(\"d\").SolidBlock(100, 100);\n                    row.AutoItem().Mock(\"e\").SolidBlock(100, 100);\n                    row.AutoItem().Mock(\"f\").SolidBlock(100, 100);\n                });\n            });\n    }\n    \n    #region Single Page\n    \n    [Test]\n    public void NoRotation()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(500, 500)\n            .ForContent(content =>\n            {\n                content.Shrink().Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(300, 200)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(100, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(200, 0).Size(100, 100);\n                        page.Mock(\"d\").Position(0, 100).Size(100, 100);\n                        page.Mock(\"e\").Position(100, 100).Size(100, 100);\n                        page.Mock(\"f\").Position(200, 100).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void OneRotation()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(500, 500)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .RotateRight() // <-\n                    .Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(200, 300)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(200, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(200, 100).Size(100, 100);\n                        page.Mock(\"c\").Position(200, 200).Size(100, 100);\n                        page.Mock(\"d\").Position(100, 0).Size(100, 100);\n                        page.Mock(\"e\").Position(100, 100).Size(100, 100);\n                        page.Mock(\"f\").Position(100, 200).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void TwoRotations()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(500, 500)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .RotateRight() // <-\n                    .RotateRight()\n                    .Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(300, 200)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(300, 200).Size(100, 100);\n                        page.Mock(\"b\").Position(200, 200).Size(100, 100);\n                        page.Mock(\"c\").Position(100, 200).Size(100, 100);\n                        page.Mock(\"d\").Position(300, 100).Size(100, 100);\n                        page.Mock(\"e\").Position(200, 100).Size(100, 100);\n                        page.Mock(\"f\").Position(100, 100).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ThreeRotation()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(500, 500)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .RotateRight() // <-\n                    .RotateRight()\n                    .RotateRight()\n                    .Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(200, 300)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 300).Size(100, 100);\n                        page.Mock(\"b\").Position(0, 200).Size(100, 100);\n                        page.Mock(\"c\").Position(0, 100).Size(100, 100);\n                        page.Mock(\"d\").Position(100, 300).Size(100, 100);\n                        page.Mock(\"e\").Position(100, 200).Size(100, 100);\n                        page.Mock(\"f\").Position(100, 100).Size(100, 100);\n                    });\n            });\n    }\n    \n    #endregion\n    \n    #region Paging\n    \n    [Test]\n    public void NoRotationWithPaging()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(500, 150)\n            .ForContent(content =>\n            {\n                content.Shrink().Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(300, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(100, 0).Size(100, 100);\n                        page.Mock(\"c\").Position(200, 0).Size(100, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(300, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"d\").Position(0, 0).Size(100, 100);\n                        page.Mock(\"e\").Position(100, 0).Size(100, 100);\n                        page.Mock(\"f\").Position(200, 0).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void OneRotationWithPaging()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(150, 500)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .RotateRight() // <-\n                    .Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 300)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(100, 0).Size(100, 100);\n                        page.Mock(\"b\").Position(100, 100).Size(100, 100);\n                        page.Mock(\"c\").Position(100, 200).Size(100, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(100, 300)\n                    .Content(page =>\n                    {\n                        page.Mock(\"d\").Position(100, 0).Size(100, 100);\n                        page.Mock(\"e\").Position(100, 100).Size(100, 100);\n                        page.Mock(\"f\").Position(100, 200).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void TwoRotationsWithPaging()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(500, 150)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .RotateRight() // <-\n                    .RotateRight()\n                    .Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(300, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(300, 100).Size(100, 100);\n                        page.Mock(\"b\").Position(200, 100).Size(100, 100);\n                        page.Mock(\"c\").Position(100, 100).Size(100, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(300, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"d\").Position(300, 100).Size(100, 100);\n                        page.Mock(\"e\").Position(200, 100).Size(100, 100);\n                        page.Mock(\"f\").Position(100, 100).Size(100, 100);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ThreeRotationWithPaging()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(150, 500)\n            .ForContent(content =>\n            {\n                content\n                    .Shrink()\n                    .RotateRight() // <-\n                    .RotateRight()\n                    .RotateRight()\n                    .Element(DrawTestSubject);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(100, 300)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 300).Size(100, 100);\n                        page.Mock(\"b\").Position(0, 200).Size(100, 100);\n                        page.Mock(\"c\").Position(0, 100).Size(100, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(100, 300)\n                    .Content(page =>\n                    {\n                        page.Mock(\"d\").Position(0, 300).Size(100, 100);\n                        page.Mock(\"e\").Position(0, 200).Size(100, 100);\n                        page.Mock(\"f\").Position(0, 100).Size(100, 100);\n                    });\n            });\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/StopPagingTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\npublic class StopPagingTests\n{\n    [Test]\n    public void ChildReturnsWrap()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink()\n                    .Mock(\"a\")\n                    .StopPaging() // <- \n                    .Mock(\"b\")\n                    .SolidBlock(200, 200);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(0, 0)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(0, 0);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ChildReturnsPartialRender()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink()\n                    .Mock(\"a\")\n                    .StopPaging() // <-\n                    .Mock(\"b\")\n                    .ContinuousBlock(50, 150);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(50, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(50, 100);\n                        page.Mock(\"b\").Position(0, 0).Size(50, 100);\n                    });\n                \n                // remaining item space is ignored\n            });\n    }\n    \n    [Test]\n    public void ChildReturnsFullRender()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink()\n                    .Mock(\"a\")\n                    .StopPaging() // <-\n                    .Mock(\"b\")\n                    .SolidBlock(50, 50);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(50, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(50, 50);\n                        page.Mock(\"b\").Position(0, 0).Size(50, 50);\n                    });\n            });\n    }\n    \n    [Test]\n    public void ChildReturnsEmpty()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 100)\n            .ForContent(content =>\n            {\n                content.Shrink()\n                    .Mock(\"a\")\n                    .StopPaging() // <-\n                    .Mock(\"b\");\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(0, 0)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(0, 0);\n                        page.Mock(\"b\").Position(0, 0).Size(0, 0);\n                    });\n            });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/TableTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\npublic class TableTests\n{\n    [Test]\n    public void RowSpan_CornerCase1()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(200, 400)\n            .ForContent(content =>\n            {\n                content\n                    .Table(table =>\n                    {\n                        table.ColumnsDefinition(columns =>\n                        {\n                            columns.RelativeColumn();\n                        });\n                        \n                        table.Cell()\n                            .RowSpan(2)\n                            .Mock(\"a\")\n                            .SolidBlock(100, 100);\n                        \n                        table.Cell()\n                            .Mock(\"b\")\n                            .SolidBlock(100, 350);\n                    });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(200, 100)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(200, 100);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(200, 350)\n                    .Content(page =>\n                    {\n                        page.Mock(\"b\").Position(0, 0).Size(200, 350);\n                    });\n            });\n    }\n    \n    [Test]\n    public void RowSpan_CornerCase2()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(200, 400)\n            .ForContent(content =>\n            {\n                content\n                    .Table(table =>\n                    {\n                        table.ColumnsDefinition(columns =>\n                        {\n                            columns.RelativeColumn();\n                            columns.RelativeColumn();\n                        });\n                        \n                        table.Cell()\n                            .Column(1)\n                            .Row(1)\n                            .RowSpan(3)\n                            .Mock(\"a\")\n                            .SolidBlock(100, 100);\n                        \n                        table.Cell()\n                            .Column(2)\n                            .Row(2)\n                            .Mock(\"b\")\n                            .ContinuousBlock(100, 600);\n                    });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(200, 400)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 400);\n                        page.Mock(\"b\").Position(100, 0).Size(100, 400);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(200, 200)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 0).Size(100, 200);\n                        page.Mock(\"b\").Position(100, 0).Size(100, 200);\n                    });\n            });\n    }\n    \n    [Test]\n    public void RowSpan_CornerCase3()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(200, 400)\n            .ForContent(content =>\n            {\n                content\n                    .Table(table =>\n                    {\n                        table.ColumnsDefinition(columns =>\n                        {\n                            columns.RelativeColumn();\n                        });\n\n                        table.Cell()\n                            .Column(1)\n                            .Row(1)\n                            .RowSpan(3)\n                            .Column(column =>\n                            {\n                                foreach (var i in Enumerable.Range(1, 5))\n                                {\n                                    column.Item().Width(200).Height(200).Mock($\"{i}\");\n                                }\n                            });\n                    });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(200, 400)\n                    .Content(page =>\n                    {\n                        page.Mock(\"1\").Position(0, 0).Size(200, 200);\n                        page.Mock(\"2\").Position(0, 200).Size(200, 200);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(200, 400)\n                    .Content(page =>\n                    {\n                        page.Mock(\"3\").Position(0, 0).Size(200, 200);\n                        page.Mock(\"4\").Position(0, 200).Size(200, 200);\n                    });\n                \n                document\n                    .Page()\n                    .RequiredAreaSize(200, 200)\n                    .Content(page =>\n                    {\n                        page.Mock(\"5\").Position(0, 0).Size(200, 200);\n                    });\n            });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/TestEngine/ContinuousBlock.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.LayoutTests.TestEngine;\n\ninternal class ContinuousBlock : Element, IStateful\n{\n    public float TotalWidth { get; set; }\n    public float TotalHeight { get; set; }\n\n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        if (TotalWidth > availableSpace.Width + Size.Epsilon)\n            return SpacePlan.Wrap(\"The content requires more horizontal space than available.\");\n\n        if (availableSpace.Height < Size.Epsilon)\n            return SpacePlan.Wrap(\"The content requires more vertical space than available.\");\n\n        var remainingHeight = TotalHeight - HeightOffset;\n\n        if (remainingHeight < Size.Epsilon)\n            return SpacePlan.FullRender(Size.Zero);\n        \n        if (remainingHeight > availableSpace.Height)\n            return SpacePlan.PartialRender(TotalWidth, availableSpace.Height);\n        \n        return SpacePlan.FullRender(TotalWidth, remainingHeight);\n    }\n\n    internal override void Draw(Size availableSpace)\n    {\n        var height = Math.Min(TotalHeight - HeightOffset, availableSpace.Height);\n        var size = new Size(TotalWidth, height);\n        \n        HeightOffset += height;\n\n        using var paint = new SkPaint();\n        paint.SetSolidColor(Colors.Grey.Medium);\n        Canvas.DrawRectangle(Position.Zero, size, paint);\n\n        if (HeightOffset > TotalHeight - Size.Epsilon)\n            HeightOffset = 0;\n    }\n    \n    #region IStateful\n        \n    private float HeightOffset { get; set; }\n\n    public void ResetState(bool hardReset = false) => HeightOffset = 0;\n    public object GetState() => HeightOffset;\n    public void SetState(object state) => HeightOffset = (float) state;\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/TestEngine/DrawingRecorder.cs",
    "content": "using System.Collections.ObjectModel;\n\nnamespace QuestPDF.LayoutTests.TestEngine;\n\ninternal class ElementDrawingEvent\n{\n    public string ObserverId { get; set; }\n    public int PageNumber { get; set; }\n    public Position Position { get; set; }\n    public Size Size { get; set; }\n    public object? StateAfterDrawing { get; set; }\n}\n\ninternal class DrawingRecorder\n{\n    private List<ElementDrawingEvent> DrawingEvents { get; } = [];\n    \n    public void Record(ElementDrawingEvent elementDrawingEvent)\n    {\n        DrawingEvents.Add(elementDrawingEvent);\n    }\n    \n    public IReadOnlyCollection<ElementDrawingEvent> GetDrawingEvents()\n    {\n        return new ReadOnlyCollection<ElementDrawingEvent>(DrawingEvents);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/TestEngine/ElementObserver.cs",
    "content": "using System.Diagnostics;\nusing QuestPDF.Drawing.DrawingCanvases;\nusing QuestPDF.Drawing.Proxy;\nusing QuestPDF.Elements;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.LayoutTests.TestEngine;\n\n\n\ninternal class ElementObserver : ContainerElement\n{\n    public string? ObserverId { get; set; }\n    public DrawingRecorder? DrawingRecorder { get; set; }\n    \n    internal override void Draw(Size availableSpace)\n    {\n        Debug.Assert(ObserverId != null);\n        Debug.Assert(DrawingRecorder != null);\n        \n        var matrix = Canvas.GetCurrentMatrix();\n\n        var drawingEvent = new ElementDrawingEvent\n        {\n            ObserverId = ObserverId,\n            PageNumber = PageContext.CurrentPage,\n            Position = new Position(matrix.TranslateX, matrix.TranslateY),\n            Size = ObserverId == \"$document\" ? Child.Measure(availableSpace) : availableSpace\n        };\n        \n        if (!Canvas.Is<DiscardDrawingCanvas>())\n            DrawingRecorder?.Record(drawingEvent);\n        \n        var matrixBeforeDraw = Canvas.GetCurrentMatrix().ToMatrix4x4();\n        base.Draw(availableSpace);\n        var matrixAfterDraw = Canvas.GetCurrentMatrix().ToMatrix4x4();\n        \n        if (matrixAfterDraw != matrixBeforeDraw)\n            throw new InvalidOperationException(\"Canvas state was not restored after drawing operation.\");\n\n        drawingEvent.StateAfterDrawing = (GetRealChild() as IStateful)?.GetState();\n    }\n\n    private Element GetRealChild()\n    {\n        var result = Child;\n\n        while (true)\n        {\n            if (result is ElementProxy proxy)\n            {\n                result = proxy.Child;\n                continue;\n            }\n\n            if (result is DebugPointer debugPointer)\n            {\n                result = debugPointer.Child;\n                continue;\n            }\n            \n            break;\n        }\n        \n        return result;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/TestEngine/ElementObserverSetter.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.LayoutTests.TestEngine;\n\ninternal class ElementObserverSetter : ContainerElement\n{\n    public required DrawingRecorder Recorder { get; init; }\n    \n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        SetRecorderOnChildren();\n        return base.Measure(availableSpace);\n    }\n    \n    internal override void Draw(Size availableSpace)\n    {\n        SetRecorderOnChildren();\n        base.Draw(availableSpace);\n    }\n    \n    private void SetRecorderOnChildren()\n    {\n        this.VisitChildren(x =>\n        {\n            if (x is ElementObserver observer)\n                observer.DrawingRecorder = Recorder;\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/TestEngine/FluentExtensions.cs",
    "content": "using QuestPDF.Helpers;\n\nnamespace QuestPDF.LayoutTests.TestEngine;\n\ninternal class ExpectedDocumentLayoutDescriptor(DrawingRecorder DrawingRecorder)\n{\n    private int CurrentPage { get; set; } = 1;\n    \n    public ExpectedPageLayoutDescriptor Page()\n    {\n        return new ExpectedPageLayoutDescriptor(DrawingRecorder, CurrentPage++);\n    }\n}\n\ninternal class ExpectedPageLayoutDescriptor(DrawingRecorder DrawingRecorder, int CurrentPageNumber)\n{\n    public ExpectedPageLayoutDescriptor RequiredAreaSize(float width, float height)\n    {\n        DrawingRecorder.Record(new ElementDrawingEvent\n        {\n            ObserverId = \"$document\",\n            PageNumber = CurrentPageNumber,\n            Size = new Size(width, height)\n        });\n        \n        return this;\n    }\n    \n    public void Content(Action<ExpectedPageContentDescriptor> content)\n    {\n        var pageContent = new ExpectedPageContentDescriptor(DrawingRecorder, CurrentPageNumber);\n        content(pageContent);\n    }\n}\n\ninternal class ExpectedPageContentDescriptor(DrawingRecorder drawingRecorder, int CurrentPageNumber)\n{\n    public ExpectedMockPositionDescriptor Mock(string mockId)\n    {\n        var elementDrawingEvent = new ElementDrawingEvent\n        {\n            ObserverId = mockId,\n            PageNumber = CurrentPageNumber,\n        };\n        \n        drawingRecorder.Record(elementDrawingEvent);\n        return new ExpectedMockPositionDescriptor(elementDrawingEvent);\n    }\n}\n\ninternal class ExpectedMockPositionDescriptor(ElementDrawingEvent drawingEvent)\n{\n    public ExpectedMockPositionDescriptor Position(float x, float y)\n    {\n        drawingEvent.Position = new Position(x, y);\n        return this;\n    }\n    \n    public ExpectedMockPositionDescriptor Size(float width, float height)\n    {\n        drawingEvent.Size = new Size(width, height);\n        return this;\n    }\n    \n    public ExpectedMockPositionDescriptor State(object state)\n    {\n        drawingEvent.StateAfterDrawing = state;\n        return this;\n    }\n}\n\ninternal static class FluentExtensions\n{\n    public const string DefaultMockId = \"$mock\";\n    \n    public static IContainer Mock(this IContainer element, string id)\n    {\n        return element.Element(new ElementObserver\n        {\n            ObserverId = id\n        });\n    } \n\n    public static IContainer ElementObserverSetter(this IContainer element, DrawingRecorder recorder)\n    {\n        return element.Element(new ElementObserverSetter\n        {\n            Recorder = recorder\n        });\n    } \n    \n    public static IContainer Size(this IContainer element, float width, float height)\n    {\n        return element.Width(width).Height(height);\n    }     \n    \n    public static void ContinuousBlock(this IContainer element, float width = 1f, float height = 1f)\n    {\n        element.Element(new ContinuousBlock\n        {\n            TotalWidth = width, \n            TotalHeight = height\n        });\n    } \n    \n    public static void SolidBlock(this IContainer element, float width = 1f, float height = 1f)\n    {\n        element.Element(new SolidBlock\n        {\n            TotalWidth = width, \n            TotalHeight = height\n        });\n    } \n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/TestEngine/LayoutTest.cs",
    "content": "using System.Runtime.CompilerServices;\nusing System.Text;\nusing NUnit.Framework.Constraints;\nusing QuestPDF.Drawing.DocumentCanvases;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.LayoutTests.TestEngine;\n\ninternal class LayoutTest\n{\n    private string TestIdentifier { get; set; }\n    private Size AvailableSpace { get; set; }\n    private DrawingRecorder ActualDrawingRecorder { get; } = new();\n    private DrawingRecorder ExpectedDrawingRecorder { get; } = new();\n    private IContainer? Content { get; set; }\n  \n    private static readonly NUnitEqualityComparer Comparer = new();\n\n    public static LayoutTest HavingSpaceOfSize(float width, float height, [CallerMemberName] string testIdentifier = \"test\")\n    {\n        var layoutTest = new LayoutTest\n        {\n            TestIdentifier = testIdentifier,\n            AvailableSpace = new Size(width, height)\n        };\n\n        return layoutTest;\n    }\n\n    public LayoutTest ForContent(Action<IContainer> handler)\n    {\n        if (Content != null)\n            throw new InvalidOperationException(\"Content has already been defined.\");\n        \n        Content = new Container();\n        \n        Content\n            .Width(AvailableSpace.Width)\n            .Height(AvailableSpace.Height)\n            .ElementObserverSetter(ActualDrawingRecorder)\n            .Mock(\"$document\")\n            .Element(handler);\n        \n        return this;\n    }\n\n    public void ExpectDrawResult(Action<ExpectedDocumentLayoutDescriptor> handler)\n    {\n        if (!ActualDrawingRecorder.GetDrawingEvents().Any())\n            PerformTest();\n        \n        var builder = new ExpectedDocumentLayoutDescriptor(ExpectedDrawingRecorder);\n        handler(builder);\n\n        var actualDrawingEvents = ActualDrawingRecorder.GetDrawingEvents();\n        var expectedDrawingEvents = ExpectedDrawingRecorder.GetDrawingEvents();\n\n        if (CheckIfIdentical(actualDrawingEvents, expectedDrawingEvents))\n        {\n            Assert.Pass();\n        }\n        else\n        {\n            DrawLog(actualDrawingEvents, expectedDrawingEvents);\n            Assert.Fail($\"The drawing operations do not match the expected result. See the log above for details. Test identifier: '{TestIdentifier}'.\");\n        }\n\n        static bool CheckIfIdentical(IReadOnlyCollection<ElementDrawingEvent> actual, IReadOnlyCollection<ElementDrawingEvent> expected)\n        {\n            if (actual.Count != expected.Count)\n                return false;\n\n            return actual.Zip(expected, Compare).All(x => x);\n        }\n\n        static bool Compare(ElementDrawingEvent? actual, ElementDrawingEvent? expected)\n        {\n            if (actual == null && expected == null)\n                return true;\n            \n            if (actual == null || expected == null)\n                return false;\n            \n            var tolerance = Tolerance.Default;\n            \n            return actual.ObserverId == expected.ObserverId &&\n                   actual.PageNumber == expected.PageNumber &&\n                   Position.Equal(actual.Position, expected.Position) &&\n                   Size.Equal(actual.Size, expected.Size) &&\n                   (expected.StateAfterDrawing == null || Comparer.AreEqual(actual.StateAfterDrawing, expected.StateAfterDrawing, ref tolerance));\n        }\n\n        static void DrawLog(IReadOnlyCollection<ElementDrawingEvent> actualEvents, IReadOnlyCollection<ElementDrawingEvent> expectedEvents)\n        {\n            var identicalLines = actualEvents.Zip(expectedEvents, Compare).TakeWhile(x => x).Count();\n\n            if (identicalLines > 0)\n            {\n                TestContext.Out.WriteLine(\"IDENTICAL\");\n                TestContext.Out.WriteLine(DrawHeader());\n                \n                foreach (var actualEvent in actualEvents.Take(identicalLines))\n                    TestContext.Out.WriteLine($\"🟩\\t{GetEventAsText(actualEvent)}\");\n            }\n\n            if (expectedEvents.Count > identicalLines)\n            {\n                TestContext.Out.WriteLine();\n                TestContext.Out.WriteLine(\"EXPECTED\");\n                TestContext.Out.WriteLine(DrawHeader());\n                \n                foreach (var expectedEvent in expectedEvents.Skip(identicalLines))\n                    TestContext.Out.WriteLine($\"🟧\\t{GetEventAsText(expectedEvent)}\");   \n            }\n\n            if (actualEvents.Count > identicalLines)\n            {\n                TestContext.Out.WriteLine();\n                TestContext.Out.WriteLine(\"ACTUAL\");\n                TestContext.Out.WriteLine(DrawHeader());\n                \n                foreach (var actualEvent in actualEvents.Skip(identicalLines))\n                    TestContext.Out.WriteLine($\"🟥\\t{GetEventAsText(actualEvent)}\");    \n            }\n        }\n\n        static string DrawHeader()\n        {\n            var mock = \"Mock\".PadRight(12);\n            var page = \"Page\".PadRight(6);\n            var x = \"X\".PadRight(8);\n            var y = \"Y\".PadRight(8);\n            var width = \"W\".PadRight(10);\n            var height = \"H\";\n            \n            return $\"\\t{mock} {page} {x} {y} {width} {height}\";      \n        }\n        \n        static string GetEventAsText(ElementDrawingEvent drawingEvent)\n        {\n            var observerId = drawingEvent.ObserverId.PadRight(12);\n            var pageNumber = $\"{drawingEvent.PageNumber}\".PadRight(6);\n            \n            var positionX = $\"{drawingEvent.Position.X}\".PadRight(8);\n            var positionY = $\"{drawingEvent.Position.Y}\".PadRight(8);\n            \n            var sizeWidth = $\"{drawingEvent.Size.Width}\".PadRight(10);\n            var sizeHeight = $\"{drawingEvent.Size.Height}\";\n            \n            return $\"{observerId} {pageNumber} {positionX} {positionY} {sizeWidth} {sizeHeight}\";       \n        }\n    }\n\n    public void ExpectLayoutException(string reason)\n    {\n        try\n        {\n            QuestPDF.Settings.EnableDebugging = true;\n            PerformTest();\n        }\n        catch (DocumentLayoutException e)\n        {\n            Assert.That(e.Message.Contains(reason));\n            Assert.Pass($\"The expected exception was thrown: {e.Message}\");\n        }\n        catch\n        {\n            Assert.Fail(\"Un expected exception was thrown.\");\n        }\n    }\n\n    private void PerformTest()\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(Size.Infinity, Size.Infinity));\n                    page.Content().Element(Content);\n                });\n            })\n            .Generate(new DiscardDocumentCanvas());\n    }\n\n    public LayoutTest VisualizeOutput()\n    {\n        if (Content == null)\n            throw new InvalidOperationException(\"Content has not been defined.\");\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(Size.Infinity, Size.Infinity));\n                    page.Content().Element(Content);\n                });\n            })\n            .GeneratePdfAndShow();\n        \n        return this;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/TestEngine/SolidBlock.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Helpers;\nusing QuestPDF.Skia;\n\nnamespace QuestPDF.LayoutTests.TestEngine;\n\ninternal class SolidBlock : Element, IStateful\n{\n    public float TotalWidth { get; set; } \n    public float TotalHeight { get; set; }\n\n    internal override SpacePlan Measure(Size availableSpace)\n    {\n        if (IsRendered)\n            return SpacePlan.Empty();\n        \n        if (TotalWidth > availableSpace.Width + Size.Epsilon)\n            return SpacePlan.Wrap(\"The content requires more horizontal space than available.\");\n\n        if (TotalHeight > availableSpace.Height + Size.Epsilon)\n            return SpacePlan.Wrap(\"The content requires more vertical space than available.\");\n\n        return SpacePlan.FullRender(TotalWidth, TotalHeight);\n    }\n\n    internal override void Draw(Size availableSpace)\n    {\n        using var paint = new SkPaint();\n        paint.SetSolidColor(Placeholders.BackgroundColor());\n        Canvas.DrawRectangle(Position.Zero, availableSpace, paint);\n        \n        IsRendered = true;\n    }\n    \n    #region IStateful\n        \n    private bool IsRendered { get; set; }\n\n    public void ResetState(bool hardReset = false) => IsRendered = false;\n    public object GetState() => IsRendered;\n    public void SetState(object state) => IsRendered = (bool) state;\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/TranslateTests.cs",
    "content": "namespace QuestPDF.LayoutTests;\n\npublic class TranslateTests\n{\n    [Test]\n    public void HorizontalTranslation()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 120)\n            .ForContent(content =>\n            {\n                content.Shrink().TranslateX(15).Mock(\"a\").SolidBlock(40, 50);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(40, 50)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(15, 0).Size(40, 50);\n                    });\n            });\n    }\n    \n    [Test]\n    public void VerticalTranslation()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 120)\n            .ForContent(content =>\n            {\n                content.Shrink().TranslateY(25).Mock(\"a\").SolidBlock(30, 40);\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(30, 40)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(0, 25).Size(30, 40);\n                    });\n            });\n    }\n    \n    [Test]\n    public void MultipleItemsWithTranslation()\n    {\n        LayoutTest\n            .HavingSpaceOfSize(100, 120)\n            .ForContent(content =>\n            {\n                content.Shrink().Column(column =>\n                {\n                    column.Item().TranslateX(5).TranslateY(10).Mock(\"a\").SolidBlock(40, 20);\n                    column.Item().TranslateX(-10).TranslateY(20).Mock(\"b\").SolidBlock(30, 25);\n                    column.Item().TranslateX(30).TranslateY(-15).Mock(\"c\").SolidBlock(50, 15);\n                });\n            })\n            .ExpectDrawResult(document =>\n            {\n                document\n                    .Page()\n                    .RequiredAreaSize(50, 60)\n                    .Content(page =>\n                    {\n                        page.Mock(\"a\").Position(5, 10).Size(50, 20);\n                        page.Mock(\"b\").Position(-10, 40).Size(50, 25);\n                        page.Mock(\"c\").Position(30, 30).Size(50, 15);\n                    });\n            });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.LayoutTests/Usings.cs",
    "content": "global using NUnit.Framework;\nglobal using QuestPDF.Fluent;\nglobal using QuestPDF.Infrastructure;\nglobal using QuestPDF.LayoutTests.TestEngine;"
  },
  {
    "path": "Source/QuestPDF.ReportSample/DataSource.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.ReportSample\n{\n    public static class DataSource\n    {\n        public static ReportModel GetReport()\n        {\n            return new ReportModel\n            {\n                Title = \"Sample Report Document\",\n                HeaderFields = HeaderFields(),\n                \n                LogoData = Helpers.GetImage(\"Logo.png\"),\n                Sections = Enumerable.Range(0, 40).Select(x => GenerateSection()).ToList(),\n                Photos = Enumerable.Range(0, 25).Select(x => GetReportPhotos()).ToList()\n            };\n\n            List<ReportHeaderField> HeaderFields()\n            {\n                return new List<ReportHeaderField>\n                {\n                    new ReportHeaderField()\n                    {\n                        Label = \"Scope\",\n                        Value = \"Internal activities\"\n                    },\n                    new ReportHeaderField()\n                    {\n                        Label = \"Author\",\n                        Value = \"Marcin Ziąbek\"\n                    },\n                    new ReportHeaderField()\n                    {\n                        Label = \"Date\",\n                        Value = DateTime.Now.ToString(\"g\")\n                    },\n                    new ReportHeaderField()\n                    {\n                        Label = \"Status\",\n                        Value = \"Completed, found 2 issues\"\n                    }\n                };\n            }\n            \n            ReportSection GenerateSection()\n            {\n                var sectionLength = Helpers.Random.NextDouble() > 0.75\n                    ? Helpers.Random.Next(20, 40)\n                    : Helpers.Random.Next(5, 10);\n                \n                return new ReportSection\n                {\n                    Title = Placeholders.Label(),\n                    Parts = Enumerable.Range(0, sectionLength).Select(x => GetRandomElement()).ToList()\n                };\n            }\n\n            ReportSectionElement GetRandomElement()\n            {\n                var random = Helpers.Random.NextDouble();\n\n                if (random < 0.9f)\n                    return GetTextElement();\n                \n                if (random < 0.95f)\n                    return GetMapElement();\n                \n                return GetPhotosElement();\n            }\n            \n            ReportSectionText GetTextElement()\n            {\n                return new ReportSectionText\n                {\n                    Label = Placeholders.Label(),\n                    Text = Placeholders.Paragraph()\n                };\n            }\n            \n            ReportSectionMap GetMapElement()\n            {\n                return new ReportSectionMap\n                {\n                    Label = \"Location\",\n                    Location = Helpers.RandomLocation()\n                };\n            }\n            \n            ReportSectionPhotos GetPhotosElement()\n            {\n                return new ReportSectionPhotos\n                {    \n                    Label = \"Photos\",\n                    PhotoCount = Helpers.Random.Next(1, 15)\n                };\n            }\n\n            ReportPhoto GetReportPhotos()\n            {\n                return new ReportPhoto()\n                {\n                    Comments = Placeholders.Sentence(),\n                    Date = DateTime.Now - TimeSpan.FromDays(Helpers.Random.NextDouble() * 100),\n                    Location = Helpers.RandomLocation()\n                };\n            }\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Helpers.cs",
    "content": "using System;\nusing System.Collections.Concurrent;\nusing System.IO;\nusing System.Text;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\nusing SkiaSharp;\n\nnamespace QuestPDF.ReportSample\n{\n    public static class Helpers\n    {\n        public static Random Random { get; } = new Random();\n        \n        public static string GetTestItem(string path) => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, \"Resources\", path);\n\n        public static byte[] GetImage(string name)\n        {\n            var photoPath = GetTestItem(name);\n            return SKImage.FromEncodedData(photoPath).EncodedData.ToArray();\n        }\n\n        public static Location RandomLocation()\n        {\n            return new Location\n            {\n                Longitude = Helpers.Random.NextDouble() * 360f - 180f,\n                Latitude = Helpers.Random.NextDouble() * 180f - 90f\n            };\n        }\n\n        private static readonly ConcurrentDictionary<int, string> RomanNumeralCache = new ConcurrentDictionary<int, string>();\n\n        public static string FormatAsRomanNumeral(this int number)\n        {\n            if (number < 0 || number > 3999) \n                throw new ArgumentOutOfRangeException(nameof(number), \"Number should be in range from 1 to 3999\");\n            \n            return RomanNumeralCache.GetOrAdd(number, x =>\n            {\n                if (x >= 1000) return \"M\" + FormatAsRomanNumeral(x - 1000);\n                if (x >= 900) return \"CM\" + FormatAsRomanNumeral(x - 900); \n                if (x >= 500) return \"D\" + FormatAsRomanNumeral(x - 500);\n                if (x >= 400) return \"CD\" + FormatAsRomanNumeral(x - 400);\n                if (x >= 100) return \"C\" + FormatAsRomanNumeral(x - 100);            \n                if (x >= 90) return \"XC\" + FormatAsRomanNumeral(x - 90);\n                if (x >= 50) return \"L\" + FormatAsRomanNumeral(x - 50);\n                if (x >= 40) return \"XL\" + FormatAsRomanNumeral(x - 40);\n                if (x >= 10) return \"X\" + FormatAsRomanNumeral(x - 10);\n                if (x >= 9) return \"IX\" + FormatAsRomanNumeral(x - 9);\n                if (x >= 5) return \"V\" + FormatAsRomanNumeral(x - 5);\n                if (x >= 4) return \"IV\" + FormatAsRomanNumeral(x - 4);\n                if (x >= 1) return \"I\" + FormatAsRomanNumeral(x - 1);\n                \n                return string.Empty;  \n            });\n        }\n        \n        public static void SkiaSharpCanvas(this IContainer container, Action<SKCanvas, Size> drawOnCanvas)\n        {\n            container.Svg(size =>\n            {\n                using var stream = new MemoryStream();\n\n                using (var canvas = SKSvgCanvas.Create(new SKRect(0, 0, size.Width, size.Height), stream))\n                    drawOnCanvas(canvas, size);\n            \n                var svgData = stream.ToArray();\n                return Encoding.UTF8.GetString(svgData);\n            });\n        }\n        \n        public static void SkiaSharpRasterized(this IContainer container, Action<SKCanvas, Size> drawOnCanvas)\n        {\n            container.Image(payload =>\n            {\n                using var bitmap = new SKBitmap(payload.ImageSize.Width, payload.ImageSize.Height);\n\n                using (var canvas = new SKCanvas(bitmap))\n                {\n                    var scalingFactor = payload.Dpi / (float)DocumentSettings.DefaultRasterDpi;\n                    canvas.Scale(scalingFactor);\n                    drawOnCanvas(canvas, payload.AvailableSpace);\n                }\n                \n                return bitmap.Encode(SKEncodedImageFormat.Png, 100).ToArray();\n            });\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Layouts/DifferentHeadersTemplate.cs",
    "content": "﻿using QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ReportSample.Layouts\n{\n    public class DifferentHeadersTemplate : IDocument\n    {\n        public DocumentMetadata GetMetadata() => DocumentMetadata.Default;\n        public DocumentSettings GetSettings() => DocumentSettings.Default;\n\n        public void Compose(IDocumentContainer container)\n        {\n            container\n                .Page(page =>\n                {\n                    page.Margin(40);\n\n                    page.Size(PageSizes.A4);\n\n                    page.Header().Element(ComposeHeader);\n                    page.Content().Element(ComposeContent);\n                    page.Footer().Element(ComposeFooter);\n                });\n        }\n\n        private void ComposeHeader(IContainer container)\n        {\n            container.Background(Colors.Grey.Lighten3).Border(1).Column(column =>\n            {\n                column.Item().ShowOnce().Padding(5).AlignMiddle().Row(row =>\n                {\n                    row.RelativeItem(2).AlignMiddle().Text(\"PRIMARY HEADER\").FontColor(Colors.Grey.Darken3).FontSize(30).Bold();\n                    row.RelativeItem(1).AlignRight().MinimalBox().AlignMiddle().Background(Colors.Blue.Darken2).Padding(30);\n                });\n                column.Item().SkipOnce().Padding(5).Row(row =>\n                {\n                    row.RelativeItem(2).Text(\"SECONDARY HEADER\").FontColor(Colors.Grey.Darken3).FontSize(30).Bold();\n                    row.RelativeItem(1).AlignRight().MinimalBox().Background(Colors.Blue.Lighten4).Padding(15);\n                });\n            });\n        }\n\n        private void ComposeContent(IContainer container)\n        {\n            container.Column(column =>\n            {\n                column.Item().PaddingVertical(80).Text(\"First\");\n                column.Item().PageBreak();\n                column.Item().PaddingVertical(80).Text(\"Second\");\n                column.Item().PageBreak();\n                column.Item().PaddingVertical(80).Text(\"Third\");\n                column.Item().PageBreak();\n            });\n        }\n\n        private void ComposeFooter(IContainer container)\n        {\n            container.Background(Colors.Grey.Lighten3).Column(column =>\n            {\n                column.Item().ShowOnce().Background(Colors.Grey.Lighten3).Row(row =>\n                {\n                    row.RelativeItem().Text(x =>\n                    {\n                        x.CurrentPageNumber();\n                        x.Span(\" / \");\n                        x.TotalPages();\n                    });\n                    row.RelativeItem().AlignRight().Text(\"Footer for header\");\n                });\n\n                column.Item().SkipOnce().Background(Colors.Grey.Lighten3).Row(row =>\n                {\n                    row.RelativeItem().Text(x =>\n                    {\n                        x.CurrentPageNumber();\n                        x.Span(\" / \");\n                        x.TotalPages();\n                    });\n                    row.RelativeItem().AlignRight().Text(\"Footer for every page except header\");\n                });\n            });\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Layouts/Helpers.cs",
    "content": "using System;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ReportSample.Layouts\n{\n    public static class Helpers\n    {\n        static IContainer Cell(this IContainer container, bool background)\n        {\n            return container\n                .Border(0.5f)\n                .BorderColor(Colors.Grey.Lighten1)\n                .Background(background ? Colors.Grey.Lighten4 : Colors.White)\n                .Padding(5);\n        }\n        \n        public static IContainer ValueCell(this IContainer container)\n        {\n            return container.Cell(false);\n        }\n        \n        public static IContainer LabelCell(this IContainer container)\n        {\n            return container.Cell(true);\n        }\n        \n        public static string Format(this Location location)\n        {\n            if (location == null)\n                return string.Empty;\n            \n            var lon = location.Longitude;\n            var lat = location.Latitude;\n            \n            var typeLon = lon > 0 ? \"E\" : \"W\";\n            lon = Math.Abs(lon);\n            \n            var typeLat = lat > 0 ? \"N\" : \"S\";\n            lat = Math.Abs(lat);\n            \n            return $\"{lat:F5}° {typeLat}   {lon:F5}° {typeLon}\";\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Layouts/ImagePlaceholder.cs",
    "content": "﻿using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ReportSample.Layouts\n{\n    public class ImagePlaceholder : IComponent\n    {\n        public static bool Solid { get; set; } = false;\n        \n        public void Compose(IContainer container)\n        {\n            if (Solid)\n                container.Background(Placeholders.Color());\n            \n            else\n                container.Image(Placeholders.Image);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Layouts/PhotoTemplate.cs",
    "content": "using System;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ReportSample.Layouts\n{\n    public class PhotoTemplate : IComponent\n    {\n        public ReportPhoto Model { get; set; }\n\n        public PhotoTemplate(ReportPhoto model)\n        {\n            Model = model;\n        }\n        \n        public void Compose(IContainer container)\n        {\n            container\n                .ShowEntire()\n                .Column(column =>\n                {\n                    column.Spacing(5);\n                    column.Item().Element(PhotoWithMaps);\n                    column.Item().Element(PhotoDetails);\n                });\n        }\n        \n        void PhotoWithMaps(IContainer container)\n        {\n            container\n                .Row(row =>\n                {\n                    row.RelativeItem(2).AspectRatio(4 / 3f).Component<ImagePlaceholder>();\n\n                    row.RelativeItem().PaddingLeft(5).Column(column =>\n                    {\n                        column.Spacing(7f);\n                        \n                        column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();\n                        column.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>();\n                    });\n                });\n        }\n\n        void PhotoDetails(IContainer container)\n        {\n            container.Border(0.75f).BorderColor(Colors.Grey.Medium).Grid(grid =>\n            {\n                grid.Columns(6);\n\n                grid.Item().LabelCell().Text(\"Date\");\n                grid.Item(2).ValueCell().Text(Model.Date?.ToString(\"g\") ?? string.Empty);\n                grid.Item().LabelCell().Text(\"Location\");\n                grid.Item(2).ValueCell().Text(Model.Location.Format());\n                \n                grid.Item().LabelCell().Text(\"Comments\");\n                grid.Item(5).ValueCell().Text(Model.Comments);\n            });\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Layouts/SectionTemplate.cs",
    "content": "using System.Linq;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ReportSample.Layouts\n{\n    public class SectionTemplate : IComponent\n    {\n        public ReportSection Model { get; set; }\n\n        public SectionTemplate(ReportSection model)\n        {\n            Model = model;\n        }\n        \n        public void Compose(IContainer container)\n        {\n            container\n                .EnsureSpace()\n                .Decoration(decoration =>\n                {\n                    decoration\n                        .Before()\n                        .PaddingBottom(5)\n                        .Text(Model.Title)\n                        .Style(Typography.Headline);\n\n                    decoration.Content().Border(0.75f).BorderColor(Colors.Grey.Medium).Column(column =>\n                    {\n                        foreach (var part in Model.Parts)\n                        {\n                            column.Item().EnsureSpace(25).Row(row =>\n                            {\n                                row.ConstantItem(150).LabelCell().Text(part.Label);\n                                var frame = row.RelativeItem().ValueCell();\n                            \n                                if (part is ReportSectionText text)\n                                    frame.ShowEntire().Text(text.Text);\n                                \n                                if (part is ReportSectionMap map)\n                                    frame.Element(x => MapElement(x, map));\n                                \n                                if (part is ReportSectionPhotos photos)\n                                    frame.Element(x => PhotosElement(x, photos));\n                            });\n                        }\n                    });\n                });\n        }\r\n\r\n        static void MapElement(IContainer container, ReportSectionMap model)\n        {\n            if (model.Location == null)\n            {\n                container.Text(\"No location provided\");\n                return;\n            }\n\n            container.ShowEntire().Column(column =>\n            {\n                column.Spacing(5);\n                \n                column.Item().MaxWidth(250).AspectRatio(4 / 3f).Component<ImagePlaceholder>();\n                column.Item().Text(model.Location.Format());\n            });\n        }\r\n\r\n        static void PhotosElement(IContainer container, ReportSectionPhotos model)\n        {\n            if (model.PhotoCount == 0)\n            {\n                container.Text(\"No photos\").Style(Typography.Normal);\n                return;\n            }\n\n            container.DebugArea(\"Photos\").Grid(grid =>\n            {\n                grid.Spacing(5);\n                grid.Columns(3);\n                \n                Enumerable\n                    .Range(0, model.PhotoCount)\n                    .ToList()\n                    .ForEach(x => grid.Item().AspectRatio(4 / 3f).Component<ImagePlaceholder>());\n            });\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Layouts/StandardReport.cs",
    "content": "using QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ReportSample.Layouts\n{\n    public class StandardReport : IDocument\n    {\n        private ReportModel Model { get; }\n\n        public StandardReport(ReportModel model)\n        {\n            Model = model;\n        }\n        \n        public DocumentMetadata GetMetadata()\n        {\n            return new DocumentMetadata()\n            {\n                Title = Model.Title\n            };\n        }\n        \n        public DocumentSettings GetSettings() => DocumentSettings.Default;\n\n        public void Compose(IDocumentContainer container)\n        {\n            container\n                .Page(page =>\n                {\n                    page.DefaultTextStyle(Typography.Normal);\n                    \n                    page.MarginVertical(40);\n                    page.MarginHorizontal(50);\n                    \n                    page.Size(PageSizes.A4);\n                        \n                    page.Header().Element(ComposeHeader);\n                    page.Content().Element(ComposeContent);\n                    \n                    page.Footer().AlignCenter().Text(text =>\n                    {\n                        text.CurrentPageNumber().Format(x => x?.FormatAsRomanNumeral() ?? \"-----\");\n                        text.Span(\" / \");\n                        text.TotalPages().Format(x => x?.FormatAsRomanNumeral() ?? \"-----\");\n                    });\n                });\n        }\n\n        private void ComposeHeader(IContainer container)\n        {\n            container.Column(column =>\n            {\n                column.Item().Row(row =>\n                {\n                    row.Spacing(50);\n                    \n                    row.RelativeItem().PaddingTop(-10).Text(Model.Title).Style(Typography.Title);\n                    row.ConstantItem(90).Hyperlink(\"https://www.questpdf.com\").MaxHeight(30).Component<ImagePlaceholder>();\n                });\n\n                column.Item().ShowOnce().PaddingVertical(15).Border(1f).BorderColor(Colors.Grey.Lighten1).ExtendHorizontal();\n                \n                column.Item().ShowOnce().Grid(grid =>\n                {\n                    grid.Columns(2);\n                    grid.Spacing(5);\n                        \n                    foreach (var field in Model.HeaderFields)\n                    {\n                        grid.Item().Text(text =>\n                        {\n                            text.Span($\"{field.Label}: \").SemiBold();\n                            text.Span(field.Value);\n                        });\n                    }\n                });\n            });\n        }\n\n        void ComposeContent(IContainer container)\n        {\n            container.PaddingVertical(20).Column(column =>\n            {\n                column.Spacing(20);\n                \n                column.Item().Component(new TableOfContentsTemplate(Model.Sections));\n                \n                column.Item().PageBreak();\n                \n                foreach (var section in Model.Sections)\n                    column.Item().Section(section.Title).Component(new SectionTemplate(section));\n                \n                column.Item().PageBreak();\n                column.Item().Section(\"Photos\");\n                \n                foreach (var photo in Model.Photos)\n                    column.Item().Component(new PhotoTemplate(photo));\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Drawing;\nusing System.IO;\nusing System.Text;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing SkiaSharp;\n\nnamespace QuestPDF.ReportSample.Layouts\n{\n    public class TableOfContentsTemplate : IComponent\n    {\n        private List<ReportSection> Sections { get; }\n\n        public TableOfContentsTemplate(List<ReportSection> sections)\n        {\n            Sections = sections;\n        }\n        \n        public void Compose(IContainer container)\n        {\n            container\n                .Decoration(decoration =>\n                {\n                    decoration\n                        .Before()\n                        .PaddingBottom(5)\n                        .Text(\"Table of contents\")\n                        .Style(Typography.Headline);\n\n                    decoration.Content().Column(column =>\n                    {\n                        column.Spacing(5);\n                        \n                        for (var i = 0; i < Sections.Count; i++)\n                            column.Item().Element(c => DrawLink(c, i+1, Sections[i].Title));\n\n                        column.Item().Element(c => DrawLink(c, Sections.Count+1, \"Photos\"));\n                    });\n                });\n        }\n\n        private static void DrawLink(IContainer container, int number, string locationName)\n        {\n            container\n                .SectionLink(locationName)\n                .Row(row =>\n                {\n                    row.ConstantItem(20).Text($\"{number}.\");\n                    row.AutoItem().Text(locationName);\n                    \n                    row.RelativeItem()\n                        .PaddingHorizontal(2)\n                        .AlignBottom()\n                        .Height(3)\n                        .SkiaSharpRasterized((canvas, size) =>\n                        {\n                            using var paint = new SKPaint\n                            {\n                                StrokeWidth = 1,\n                                PathEffect = SKPathEffect.CreateDash(new float[] { 1, 3 }, 0),\n                            };\n                        \n                            canvas.Translate(0, 1);\n                            canvas.DrawLine(0, 0, size.Width, 0, paint);\n                        });\n                    \n                    row.AutoItem().Text(text =>\n                    {\n                        text.BeginPageNumberOfSection(locationName);\n                        text.Span(\" - \");\n                        text.EndPageNumberOfSection(locationName);\n\n                        var lengthStyle = TextStyle.Default.FontColor(Colors.Grey.Medium);\n                        \n                        text.TotalPagesWithinSection(locationName).Style(lengthStyle).Format(x =>\n                        {\n                            var formatted = x == 1 ? \"1 page long\" : $\"{x} pages long\";\n                            return $\" ({formatted})\";\n                        });\n                    });\n                });\n        }\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Models.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ReportSample\n{\n    public class ReportModel\n    {\n        public string Title { get; set; }\n        public byte[] LogoData { get; set; }\n        public List<ReportHeaderField> HeaderFields { get; set; }\n\n        public List<ReportSection> Sections { get; set; }\n        public List<ReportPhoto> Photos { get; set; }\n    }\n\n    public class ReportHeaderField\n    {\n        public string Label { get; set; }\n        public string Value { get; set; }\n    }\n\n    public class Location\n    {\n        public double Longitude { get; set; }\n        public double Latitude { get; set; }\n    }\n    \n    public class ReportSection\n    {\n        public string Title { get; set; }\n        public List<ReportSectionElement> Parts { get; set; }\n    }\n\n    public abstract class ReportSectionElement\n    {\n        public string Label { get; set; }\n    }\n\n    public class ReportSectionText : ReportSectionElement\n    {\n        public string Text { get; set; }\n    }\n    \n    public class ReportSectionMap : ReportSectionElement\n    {\n        public Location Location { get; set; }\n    }\n\n    public class ReportSectionPhotos : ReportSectionElement\n    {\n        public int PhotoCount { get; set; }\n    }\n\n    public class ReportPhoto\n    {\n        public Location Location { get; set; }\n        \n        public DateTime? Date { get; set; }\n        public string Comments { get; set; }\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF.ReportSample/QuestPDF.ReportSample.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <SatelliteResourceLanguages>en</SatelliteResourceLanguages>\n        <IsPackable>false</IsPackable>\n        <RootNamespace>QuestPDF.ReportSample</RootNamespace>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"BenchmarkDotNet\" Version=\"0.15.8\" />\n        <PackageReference Include=\"nunit\" Version=\"4.4.0\" />\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"6.1.0\" />\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.13.0\" />\n        <PackageReference Include=\"SkiaSharp\" Version=\"3.119.1\" />\n        <PackageReference Include=\"SkiaSharp.NativeAssets.Linux.NoDependencies\" Version=\"3.119.1\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <Content Include=\"Resources\\**\\**\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n        </Content>\n    </ItemGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\QuestPDF\\QuestPDF.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <EmbeddedResource Include=\"Resources\\Logo.png\" />\n    </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Tests.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Threading.Tasks;\nusing NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.ReportSample.Layouts;\n\nnamespace QuestPDF.ReportSample\n{\n    public class ReportGeneration\n    {\n        private StandardReport Report { get; set; }\n        \n        [SetUp]\n        public void SetUp()\n        {\n            QuestPDF.Settings.License = LicenseType.Community;\n            \n            var model = DataSource.GetReport();\n            Report = new StandardReport(model);\n            \n            //ImagePlaceholder.Solid = true;\n        }\n        \n        [Test]\n        [Ignore(\"This test is for manual testing only.\")]\n        public void GeneratePdfAndShow()\n        {\n            Report.GeneratePdfAndShow();\n        }\n        \n        [Test] \n        [Ignore(\"This test is for manual testing only.\")]\n        public void GenerateXpsAndShow()\n        {\n            Report.GenerateXpsAndShow();\n        }\n        \n        [Test]\n        public void GeneratePdfForManualVerificationTesting()\n        {\n            Report.GeneratePdf(\"report.pdf\");\n        }\n        \n        [Test]\n        [Description(\"This test is important, as it checks if all IDisposables are properly disposed, and there are no memory leaks.\")]\n        public async Task CheckFinalizersStability()\n        {\n            Settings.EnableCaching = true;\n\n            Report.GeneratePdf();\n            Report.GenerateImages(new ImageGenerationSettings { RasterDpi = 72 });\n            Report.GenerateSvg();\n\n            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\n                Report.GenerateXps();\n\n            await Task.Delay(1000);\n            GC.Collect();\n            GC.WaitForPendingFinalizers();\n            await Task.Delay(1000);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ReportSample/Typography.cs",
    "content": "﻿using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ReportSample\n{\n    public static class Typography\n    {\n        public static TextStyle Title => TextStyle.Default.FontFamily(Fonts.Lato).FontColor(Colors.Blue.Darken3).FontSize(26).Black();\n        public static TextStyle Headline => TextStyle.Default.FontFamily(Fonts.Lato).FontColor(Colors.Blue.Medium).FontSize(16).SemiBold();\n        public static TextStyle Normal => TextStyle.Default.FontFamily(Fonts.Lato).FontColor(Colors.Black).FontSize(10).LineHeight(1.2f);\n    }\n}\n"
  },
  {
    "path": "Source/QuestPDF.UnitTests/AlignmentTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class AlignmentTests\n    {\n        [Test]\n        public void Measure() => SimpleContainerTests.Measure<Alignment>();\n        \n        [Test]\n        public void Draw_HorizontalCenter_VerticalCenter()\n        {\n            TestPlan\n                .For(x => new Alignment\n                {\n                    Horizontal = HorizontalAlignment.Center,\n                    Vertical = VerticalAlignment.Middle,\n                    \n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(1000, 500))\n                .ExpectChildMeasure(expectedInput: new Size(1000, 500), returns: SpacePlan.PartialRender(new Size(400, 200)))\n                .ExpectCanvasTranslate(new Position(300, 150))\n                .ExpectChildDraw(new Size(400, 200))\n                .ExpectCanvasTranslate(new Position(-300, -150))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_HorizontalLeft_VerticalCenter()\n        {\n            TestPlan\n                .For(x => new Alignment\n                {\n                    Horizontal = HorizontalAlignment.Left,\n                    Vertical = VerticalAlignment.Middle,\n                    \n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))\n                .ExpectCanvasTranslate(new Position(0, 125))\n                .ExpectChildDraw(new Size(100, 50))\n                .ExpectCanvasTranslate(new Position(0, -125))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_HorizontalCenter_VerticalBottom()\n        {\n            TestPlan\n                .For(x => new Alignment\n                {\n                    Horizontal = HorizontalAlignment.Center,\n                    Vertical = VerticalAlignment.Bottom,\n                    \n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))\n                .ExpectCanvasTranslate(new Position(150, 250))\n                .ExpectChildDraw(new Size(100, 50))\n                .ExpectCanvasTranslate(new Position(-150, -250))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_HorizontalRight_VerticalTop()\n        {\n            TestPlan\n                .For(x => new Alignment\n                {\n                    Horizontal = HorizontalAlignment.Right,\n                    Vertical = VerticalAlignment.Top,\n                    \n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))\n                .ExpectCanvasTranslate(new Position(300, 0))\n                .ExpectChildDraw(new Size(100, 50))\n                .ExpectCanvasTranslate(new Position(-300, 0))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_HorizontalCenter_VerticalNone()\n        {\n            TestPlan\n                .For(x => new Alignment\n                {\n                    Horizontal = HorizontalAlignment.Center,\n                    Vertical = null,\n                    \n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))\n                .ExpectCanvasTranslate(new Position(150, 0))\n                .ExpectChildDraw(new Size(100, 300))\n                .ExpectCanvasTranslate(new Position(-150, 0))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_HorizontalNone_VerticalMiddle()\n        {\n            TestPlan\n                .For(x => new Alignment\n                {\n                    Horizontal = null,\n                    Vertical = VerticalAlignment.Middle,\n                    \n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: SpacePlan.FullRender(new Size(100, 50)))\n                .ExpectCanvasTranslate(new Position(0, 125))\n                .ExpectChildDraw(new Size(400, 50))\n                .ExpectCanvasTranslate(new Position(0, -125))\n                .CheckDrawResult();\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/AspectRatioTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class AspectRatioTests\n    {\n        [Test]\n        public void Measure_FitWidth_EnoughSpace_FullRender()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitArea,\n                    Ratio = 2f\n                })\n                .MeasureElement(new Size(400, 201))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))\n                .CheckMeasureResult(SpacePlan.FullRender(400, 200));\n        }\n        \n        [Test]\n        public void Measure_FitWidth_EnoughSpace_PartialRender()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitArea,\n                    Ratio = 2f\n                })\n                .MeasureElement(new Size(400, 201))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.PartialRender(100, 50))\n                .CheckMeasureResult(SpacePlan.PartialRender(400, 200));\n        }\n        \n        [Test]\n        public void Measure_FitWidth_EnoughSpace_Wrap()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitArea,\n                    Ratio = 2f\n                })\n                .MeasureElement(new Size(400, 201))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Forwarded from child\"));\n        }\n        \n        [Test]\n        public void Measure_FitWidth_EnoughSpace()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitWidth,\n                    Ratio = 2f\n                })\n                .MeasureElement(new Size(400, 201))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))\n                .CheckMeasureResult(SpacePlan.FullRender(400, 200));\n        }\n\n        [Test]\n        public void Measure_FitWidth_NotEnoughSpace()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitWidth,\n                    Ratio = 2f\n                })\n                .MeasureElement(new Size(400, 199))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .CheckMeasureResult(SpacePlan.Wrap(\"To preserve the target aspect ratio, the content requires more vertical space than available.\"));\n        }\n        \n        [Test]\n        public void Measure_FitHeight_EnoughSpace()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitHeight,\n                    Ratio = 2f\n                })\n                .MeasureElement(new Size(401, 200))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))\n                .CheckMeasureResult(SpacePlan.FullRender(400, 200));\n        }\n        \n        [Test]\n        public void Measure_FitHeight_NotEnoughSpace()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitHeight,\n                    Ratio = 2f\n                })\n                .MeasureElement(new Size(399, 200))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .CheckMeasureResult(SpacePlan.Wrap(\"To preserve the target aspect ratio, the content requires more horizontal space than available.\"));\n        }\n        \n        [Test]\n        public void Measure_FitArea_ToWidth()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitArea,\n                    Ratio = 2f\n                })\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))\n                .CheckMeasureResult(SpacePlan.FullRender(400, 200));\n        }\n        \n        [Test]\n        public void Measure_FitArea_ToHeight()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitArea,\n                    Ratio = 2f\n                })\n                .MeasureElement(new Size(500, 200))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 50))\n                .CheckMeasureResult(SpacePlan.FullRender(400, 200));\n        }\n        \n        [Test]\n        public void DrawChild_PerWidth()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitArea,\n                    Ratio = 2f\n                })\n                .DrawElement(new Size(500, 200))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(new Size(400, 200))\n                .ExpectCanvasTranslate(0, 0)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void DrawChild_PerHeight()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitArea,\n                    Ratio = 2f\n                })\n                .DrawElement(new Size(400, 300))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(new Size(400, 200))\n                .ExpectCanvasTranslate(0, 0)\n                .CheckDrawResult();\n        } \n        \n        [Test]\n        public void DrawChild_PerWidth_RightToLeft()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitArea,\n                    Ratio = 2f,\n                    ContentDirection = ContentDirection.RightToLeft\n                })\n                .DrawElement(new Size(500, 200))\n                .ExpectCanvasTranslate(100, 0)\n                .ExpectChildDraw(new Size(400, 200))\n                .ExpectCanvasTranslate(-100, 0)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void DrawChild_PerHeight_RightToLeft()\n        {\n            TestPlan\n                .For(x => new AspectRatio\n                {\n                    Child = x.CreateChild(),\n                    Option = AspectRatioOption.FitArea,\n                    Ratio = 2f,\n                    ContentDirection = ContentDirection.RightToLeft\n                })\n                .DrawElement(new Size(400, 300))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(new Size(400, 200))\n                .ExpectCanvasTranslate(0, 0)\n                .CheckDrawResult();\n        } \n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/ColumnTests.cs",
    "content": "﻿using System.Linq;\nusing NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class ColumnTests\n    {\n        private Column CreateColumnWithTwoItems(TestPlan testPlan)\n        {\n            return new Column\n            {\n                Items =\n                {\n                    testPlan.CreateChild(\"first\"),\n                    testPlan.CreateChild(\"second\")\n                }\n            };\n        }\n        \n        private Column CreateColumnWithTwoItemsWhereFirstIsFullyRendered(TestPlan testPlan)\n        {\n            var column = CreateColumnWithTwoItems(testPlan);\n            column.CurrentRenderingIndex = 1;\n            return column;\n        }\n        \n        #region Measure\n\n        [Test]\n        public void Measure_ReturnsWrap_WhenFirstChildWraps()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"The available space is not sufficient for even partially rendering a single item.\"));\n        }\n        \n        [Test]\n        public void Measure_ReturnsPartialRender_WhenFirstChildReturnsPartialRender()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.PartialRender(300, 200))\n                .CheckMeasureResult(SpacePlan.PartialRender(300, 200));\n        }\n        \n        [Test]\n        public void Measure_ReturnsPartialRender_WhenSecondChildWraps()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.FullRender(200, 100))\n                .ExpectChildMeasure(\"second\", new Size(400, 200), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.PartialRender(200, 100));\n        }\n        \n        [Test]\n        public void Measure_ReturnsPartialRender_WhenSecondChildReturnsPartialRender()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.FullRender(200, 100))\n                .ExpectChildMeasure(\"second\", new Size(400, 200), SpacePlan.PartialRender(300, 150))\n                .CheckMeasureResult(SpacePlan.PartialRender(300, 250));\n        }\n        \n        [Test]\n        public void Measure_ReturnsFullRender_WhenSecondChildReturnsFullRender()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.FullRender(200, 100))\n                .ExpectChildMeasure(\"second\", new Size(400, 200), SpacePlan.FullRender(100, 50))\n                .CheckMeasureResult(SpacePlan.FullRender(200, 150));\n        }\n\n        #endregion\n        \n        #region Draw\n        \n        [Test]\n        public void Draw_WhenFirstChildWraps()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.Wrap(\"Mock\"))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenFirstChildPartiallyRenders()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.PartialRender(200, 100))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(\"first\", new Size(400, 100))\n                .ExpectCanvasTranslate(0, 0)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenFirstChildFullyRenders_AndSecondChildWraps()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.FullRender(200, 100))\n                .ExpectChildMeasure(\"second\", new Size(400, 200), SpacePlan.Wrap(\"Mock\"))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(\"first\", new Size(400, 100))\n                .ExpectCanvasTranslate(0, 0)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenFirstChildFullyRenders_AndSecondChildPartiallyRenders()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.FullRender(200, 100))\n                .ExpectChildMeasure(\"second\", new Size(400, 200), SpacePlan.PartialRender(250, 150))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(\"first\", new Size(400, 100))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectCanvasTranslate(0, 100)\n                .ExpectChildDraw(\"second\", new Size(400, 150))\n                .ExpectCanvasTranslate(0, -100)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenFirstChildFullyRenders_AndSecondChildFullyRenders()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItems)\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(\"first\", new Size(400, 300), SpacePlan.FullRender(200, 100))\n                .ExpectChildMeasure(\"second\", new Size(400, 200), SpacePlan.FullRender(250, 150))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(\"first\", new Size(400, 100))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectCanvasTranslate(0, 100)\n                .ExpectChildDraw(\"second\", new Size(400, 150))\n                .ExpectCanvasTranslate(0, -100)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_UsesEmpty_WhenFirstChildIsRendered()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered)\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(\"second\", new Size(400, 300), SpacePlan.PartialRender(200, 300))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(\"second\", new Size(400, 300))\n                .ExpectCanvasTranslate(0, 0)\n                .CheckState<Column>(x => x.CurrentRenderingIndex > 0)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_DoesNotToggleFirstRenderedFlag_WhenSecondFullyRenders()\n        {\n            TestPlan\n                .For(CreateColumnWithTwoItemsWhereFirstIsFullyRendered)\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(\"second\", new Size(400, 300), SpacePlan.FullRender(200, 300))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(\"second\", new Size(400, 300))\n                .ExpectCanvasTranslate(0, 0)\n                .CheckDrawResult()\n                .CheckState<Column>(x => x.CurrentRenderingIndex == 2);\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/ConstrainedTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class ConstrainedTests\n    {\n        #region Height\n        \n        [Test]\n        public void Measure_MinHeight_ExpectWrap()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MinHeight = 100\n                })\n                .MeasureElement(new Size(400, 50))\n                .CheckMeasureResult(SpacePlan.Wrap(\"The available vertical space is less than the minimum height.\"));\n        }\n        \n        [Test]\n        public void Measure_MinHeight_ExtendHeight()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MinHeight = 100,\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 200))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(400, 50))\n                .CheckMeasureResult(SpacePlan.FullRender(400, 100));\n        }\n        \n        [Test]\n        public void Measure_MinHeight_PassHeight()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MinHeight = 100,\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 200))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(400, 150))\n                .CheckMeasureResult(SpacePlan.FullRender(400, 150));\n        }\n        \n        [Test]\n        public void Measure_MaxHeight_Empty()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MaxHeight = 100\n                })\n                .MeasureElement(new Size(400, 150))\n                .CheckMeasureResult(SpacePlan.FullRender(0, 0));\n        }\n        \n        [Test]\n        public void Measure_MaxHeight_PartialRender()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MaxHeight = 100,\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 200))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 100), SpacePlan.PartialRender(400, 75))\n                .CheckMeasureResult(SpacePlan.PartialRender(400, 75));\n        }\n        \n        [Test]\n        public void Measure_MaxHeight_ExpectWrap()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MaxHeight = 100,\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 200))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(400, 100), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Forwarded from child\"));\n        }\n        \n        #endregion\n        \n        #region Width\n        \n        [Test]\n        public void Measure_MinWidth_ExpectWrap()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MinWidth = 100\n                })\n                .MeasureElement(new Size(50, 400))\n                .CheckMeasureResult(SpacePlan.Wrap(\"The available horizontal space is less than the minimum width.\"));\n        }\n        \n        [Test]\n        public void Measure_MinWidth_ExtendHeight()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MinWidth = 100,\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(200, 400))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(200, 400), SpacePlan.FullRender(50, 400))\n                .CheckMeasureResult(SpacePlan.FullRender(100, 400));\n        }\n        \n        [Test]\n        public void Measure_MinWidth_PassHeight()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MinWidth = 100,\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(200, 400))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(200, 400), SpacePlan.FullRender(150, 400))\n                .CheckMeasureResult(SpacePlan.FullRender(150, 400));\n        }\n        \n        [Test]\n        public void Measure_MaxWidth_Empty()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MaxWidth = 100\n                })\n                .MeasureElement(new Size(150, 400))\n                .CheckMeasureResult(SpacePlan.FullRender(0, 0));\n        }\n        \n        [Test]\n        public void Measure_MaxWidth_PartialRender()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MaxWidth = 100,\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(200, 400))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(100, 400), SpacePlan.PartialRender(75, 400))\n                .CheckMeasureResult(SpacePlan.PartialRender(75, 400));\n        }\n        \n        [Test]\n        public void Measure_MaxWidth_ExpectWrap()\n        {\n            TestPlan\n                .For(x => new Constrained\n                {\n                    MaxWidth = 100,\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(200, 400))\n                .ExpectChildMeasure(Size.Zero, SpacePlan.PartialRender(Size.Zero))\n                .ExpectChildMeasure(new Size(100, 400), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Forwarded from child\"));\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/DecorationTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class DecorationTests\n    {\n        private Decoration CreateDecoration(TestPlan testPlan)\n        {\n            return new Decoration\n            {\n                Before = testPlan.CreateChild(\"before\"),\n                Content = testPlan.CreateChild(\"content\"),\n                After = testPlan.CreateChild(\"after\"),\n            };\n        }\n        \n        #region Measure\n\n        [Test]\n        public void Measure_ReturnsWrap_WhenBeforeReturnsWrap()\n        {\n            TestPlan\n                .For(CreateDecoration)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"before\", new Size(400, 300), SpacePlan.Wrap(\"Mock\"))\n                .ExpectChildMeasure(\"after\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"content\", new Size(400, 250), SpacePlan.FullRender(100, 100))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Decoration slot (before or after) does not fit fully on the page.\"));\n        }\n        \n        [Test]\n        public void Measure_ReturnsWrap_WhenContentReturnsWrap()\n        {\n            TestPlan\n                .For(CreateDecoration)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"before\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"after\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"content\", new Size(400, 200), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"The primary content does not fit on the page.\"));\n        }\n        \n        [Test]\n        public void Measure_ReturnsWrap_WhenAfterReturnsWrap()\n        {\n            TestPlan\n                .For(CreateDecoration)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"before\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"after\", new Size(400, 300), SpacePlan.Wrap(\"Mock\"))\n                .ExpectChildMeasure(\"content\", new Size(400, 250), SpacePlan.FullRender(100, 100))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Decoration slot (before or after) does not fit fully on the page.\"));\n        }\n        \n        [Test]\n        public void Measure_ReturnsWrap_WhenBeforeReturnsPartialRender()\n        {\n            TestPlan\n                .For(CreateDecoration)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"before\", new Size(400, 300), SpacePlan.PartialRender(100, 50))\n                .ExpectChildMeasure(\"after\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"content\", new Size(400, 250), SpacePlan.FullRender(100, 100))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Decoration slot (before or after) does not fit fully on the page.\"));\n        }\n        \n        [Test]\n        public void Measure_ReturnsWrap_WhenAfterReturnsPartialRender()\n        {\n            TestPlan\n                .For(CreateDecoration)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"before\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"after\", new Size(400, 300), SpacePlan.PartialRender(100, 50))\n                .ExpectChildMeasure(\"content\", new Size(400, 250), SpacePlan.FullRender(100, 100))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Decoration slot (before or after) does not fit fully on the page.\"));\n        }\n        \n        [Test]\n        public void Measure_ReturnsWrap_WhenContentReturnsPartialRender()\n        {\n            TestPlan\n                .For(CreateDecoration)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"before\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"after\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"content\", new Size(400, 200), SpacePlan.PartialRender(150, 100))\n                .CheckMeasureResult(SpacePlan.PartialRender(150, 200));\n        }\n        \n        [Test]\n        public void Measure_ReturnsWrap_WhenContentReturnsFullRender()\n        {\n            TestPlan\n                .For(CreateDecoration)\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(\"before\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"after\", new Size(400, 300), SpacePlan.FullRender(100, 50))\n                .ExpectChildMeasure(\"content\", new Size(400, 200), SpacePlan.FullRender(150, 100))\n                .CheckMeasureResult(SpacePlan.FullRender(150, 200));\n        }\n\n        #endregion\n        \n        #region Draw\n        \n        [Test]\n        public void Draw_Append()\n        {\n            TestPlan\n                .For(CreateDecoration)\n                .DrawElement(new Size(400, 300))\n                .ExpectChildMeasure(\"before\", new Size(400, 300), SpacePlan.FullRender(200, 40))\n                .ExpectChildMeasure(\"after\", new Size(400, 300), SpacePlan.FullRender(200, 60))\n                .ExpectChildMeasure(\"content\", new Size(400, 200), SpacePlan.FullRender(300, 100))\n                \n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(\"before\", new Size(300, 40))\n                .ExpectCanvasTranslate(0, 0)\n                \n                .ExpectCanvasTranslate(0, 40)\n                .ExpectChildDraw(\"content\", new Size(300, 100))\n                .ExpectCanvasTranslate(0, -40)\n                \n                .ExpectCanvasTranslate(0, 140)\n                .ExpectChildDraw(\"after\", new Size(300, 60))\n                .ExpectCanvasTranslate(0, -140)\n\n                .CheckDrawResult();\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/DocumentCompressionTests.cs",
    "content": "using System;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing NUnit.Framework;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests;\n\npublic class DocumentCompressionTests\n{\n    [Test]\n    public void Test()\n    {\n        var document = Document.Create(document =>\n        {\n            document.Page(page =>\n            {\n                page.Size(PageSizes.A4);\n                \n                page.Content()\n                    .Table(table =>\n                    {\n                        table.ColumnsDefinition(columns =>\n                        {\n                            columns.RelativeColumn();\n                            columns.RelativeColumn();\n                            columns.RelativeColumn();\n                            columns.RelativeColumn();\n                            columns.ConstantColumn(100);\n                        });\n\n                        foreach (var y in Enumerable.Range(1, 100))\n                        {\n                            foreach (var x in Enumerable.Range(1, 4))\n                            {\n                                table\n                                    .Cell()\n                                    .Padding(5)\n                                    .Border(1)\n                                    .Background(Placeholders.BackgroundColor())\n                                    .Padding(5)\n                                    .Text($\"f({y}, {x}) = '{Placeholders.Sentence()}'\");\n                            }\n                        \n                            table\n                                .Cell()\n                                .Padding(5)\n                                .AspectRatio(2f)\n                                .Image(Placeholders.Image);\n                        }\n                    });\n            });\n        });\n\n        // warmup cache\n        document.GeneratePdf();\n\n        var withoutCompression = MeasureDocumentSizeAndGenerationTime(false);\n        var withCompression = MeasureDocumentSizeAndGenerationTime(true);\n        \n        var sizeRatio = withoutCompression.documentSize / (float)withCompression.documentSize;\n        Assert.That(sizeRatio, Is.GreaterThan(3));\n\n        var generationTimeRatio = withCompression.generationTime / (float)withoutCompression.generationTime;\n        Assert.That(generationTimeRatio, Is.LessThan(2));\n        \n        (int documentSize, float generationTime) MeasureDocumentSizeAndGenerationTime(bool compress)\n        {\n            var stopwatch = new Stopwatch();\n            \n            stopwatch.Restart();\n            \n            var documentSize = document\n                .WithSettings(new DocumentSettings { CompressDocument = compress })\n                .GeneratePdf()\n                .Length;\n            \n            stopwatch.Stop();\n            \n            return (documentSize, stopwatch.ElapsedMilliseconds);\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/DocumentOperationTests.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing NUnit.Framework;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests;\n\n/// <summary>\n/// This test suite focus on executing various QPDF operations.\n/// In most cases, it does not check the result but rather if any exception is thrown.\n/// </summary>\npublic class DocumentOperationTests\n{\n    [Test]\n    public void TakePages()\n    {\n        GenerateSampleDocument(\"take-input.pdf\", Colors.Red.Medium, 10);\n        \n        DocumentOperation\n            .LoadFile(\"take-input.pdf\")\n            .TakePages(\"2-5\")\n            .Save(\"operation-take.pdf\");\n    }\n    \n    [Test]\n    public void MergeTest()\n    {\n        GenerateSampleDocument(\"merge-first.pdf\", Colors.Red.Medium, 3);\n        GenerateSampleDocument(\"merge-second.pdf\", Colors.Green.Medium, 5);\n        GenerateSampleDocument(\"merge-third.pdf\", Colors.Blue.Medium, 7);\n        \n        DocumentOperation\n            .LoadFile(\"merge-first.pdf\")\n            .MergeFile(\"merge-second.pdf\")\n            .MergeFile(\"merge-third.pdf\")\n            .Save(\"operation-merged.pdf\");\n    }\n    \n    [Test]\n    public void OverlayTest()\n    {\n        GenerateSampleDocument(\"overlay-main.pdf\", Colors.Red.Medium, 10);\n        GenerateSampleDocument(\"overlay-watermark.pdf\", Colors.Green.Medium, 5);\n        \n        DocumentOperation\n            .LoadFile(\"overlay-main.pdf\")\n            .OverlayFile(new DocumentOperation.LayerConfiguration\n            {\n                FilePath = \"overlay-watermark.pdf\"\n            })\n            .Save(\"operation-overlay.pdf\");\n    }\n    \n    [Test]\n    public void UnderlayTest()\n    {\n        GenerateSampleDocument(\"underlay-main.pdf\", Colors.Red.Medium, 10);\n        GenerateSampleDocument(\"underlay-watermark.pdf\", Colors.Green.Medium, 5);\n        \n        DocumentOperation\n            .LoadFile(\"underlay-main.pdf\")\n            .UnderlayFile(new DocumentOperation.LayerConfiguration\n            {\n                FilePath = \"underlay-watermark.pdf\",\n            })\n            .Save(\"operation-underlay.pdf\");\n    }\n\n    [Test]\n    public void AttachmentTest()\n    {\n        GenerateSampleDocument(\"attachment-main.pdf\", Colors.Red.Medium, 10);\n        GenerateSampleDocument(\"attachment-file.pdf\", Colors.Green.Medium, 5);\n        \n        DocumentOperation\n            .LoadFile(\"attachment-main.pdf\")\n            .AddAttachment(new DocumentOperation.DocumentAttachment\n            {\n                FilePath = \"attachment-file.pdf\"\n            })\n            .Save(\"operation-attachment.pdf\");\n    }\n    \n    [Test]\n    public void Encrypt40Test()\n    {\n        GenerateSampleDocument(\"encrypt40-input.pdf\", Colors.Red.Medium, 10);\n        \n        DocumentOperation\n            .LoadFile(\"encrypt40-input.pdf\")\n            .Encrypt(new DocumentOperation.Encryption40Bit()\n            {\n                UserPassword = \"user_password\",\n                OwnerPassword = \"owner_password\"\n            })\n            .Save(\"operation-encrypt40.pdf\");\n    }\n    \n    [Test]\n    public void Encrypt128Test()\n    {\n        GenerateSampleDocument(\"encrypt128-input.pdf\", Colors.Red.Medium, 10);\n        \n        DocumentOperation\n            .LoadFile(\"encrypt128-input.pdf\")\n            .Encrypt(new DocumentOperation.Encryption128Bit()\n            {\n                UserPassword = \"user_password\",\n                OwnerPassword = \"owner_password\"\n            })\n            .Save(\"operation-encrypt128.pdf\");\n    }\n    \n    [Test]\n    public void Encrypt256Test()\n    {\n        GenerateSampleDocument(\"encrypt256-input.pdf\", Colors.Red.Medium, 10);\n        \n        DocumentOperation\n            .LoadFile(\"encrypt256-input.pdf\")\n            .Encrypt(new DocumentOperation.Encryption256Bit()\n            {\n                UserPassword = \"user_password\",\n                OwnerPassword = \"owner_password\"\n            })\n            .Save(\"operation-encrypt256.pdf\");\n    }\n    \n    [Test]\n    public void LinearizeTest()\n    {\n        GenerateSampleDocument(\"linearize-input.pdf\", Colors.Red.Medium, 10);\n        \n        DocumentOperation\n            .LoadFile(\"linearize-input.pdf\")\n            .Linearize()\n            .Save(\"operation-linearize.pdf\");\n    }\n    \n    [Test]\n    public void DecryptTest()\n    {\n        GenerateSampleDocument(\"decrypt-input-not-encrypted.pdf\", Colors.Red.Medium, 10);\n        \n        DocumentOperation\n            .LoadFile(\"decrypt-input-not-encrypted.pdf\")\n            .Encrypt(new DocumentOperation.Encryption256Bit()\n            {\n                UserPassword = \"user_password\",\n                OwnerPassword = \"owner_password\"\n            })\n            .Save(\"decrypt-input-encrypted.pdf\");\n        \n        DocumentOperation\n            .LoadFile(\"decrypt-input-encrypted.pdf\", \"owner_password\")\n            .Decrypt()\n            .Save(\"operation-decrypt.pdf\");\n    }\n    \n    [Test]\n    public void RemoveRestrictionsTest()\n    {\n        GenerateSampleDocument(\"remove-restrictions-input-not-encrypted.pdf\", Colors.Red.Medium, 10);\n        \n        DocumentOperation\n            .LoadFile(\"remove-restrictions-input-not-encrypted.pdf\")\n            .Encrypt(new DocumentOperation.Encryption256Bit()\n            {\n                UserPassword = string.Empty,\n                OwnerPassword = \"owner_password\",\n                AllowPrinting = false,\n                AllowContentExtraction = false\n            })\n            .Save(\"remove-restrictions-input-encrypted.pdf\");\n        \n        DocumentOperation\n            .LoadFile(\"remove-restrictions-input-encrypted.pdf\", \"owner_password\")\n            .RemoveRestrictions()\n            .Save(\"operation-remove-restrictions.pdf\");\n    }\n    \n    [Test]\n    public void LoadEncryptedWithIncorrectPasswordTest()\n    {\n        GenerateSampleDocument(\"load-encrypted-input-not-encrypted.pdf\", Colors.Red.Medium, 10);\n        \n        DocumentOperation\n            .LoadFile(\"load-encrypted-input-not-encrypted.pdf\")\n            .Encrypt(new DocumentOperation.Encryption256Bit()\n            {\n                UserPassword = \"user_password\",\n                OwnerPassword = \"owner_password\"\n            })\n            .Save(\"load-encrypted-input-encrypted.pdf\");\n        \n        Assert.Catch(() =>\n        {\n            DocumentOperation\n                .LoadFile(\"load-encrypted-input-encrypted.pdf\", \"wrong_password\")\n                .Save(\"operation-load-encrypted.pdf\");\n        });\n    }\n    \n    [Test]\n    public void ExtendMetadataTest()\n    {\n        GenerateSampleDocument(\"extend-metadata-input.pdf\", Colors.Red.Medium, 10);\n        \n        // requires PDF/A-3b\n        DocumentOperation\n            .LoadFile(\"extend-metadata-input.pdf\")\n            .ExtendMetadata(\"<rdf:Description xmlns:dc=\\\"http://purl.org/dc/elements/1.1/\\\" rdf:about=\\\"\\\"></rdf:Description>\")\n            .Save(\"operation-extend-metadata.pdf\");\n    }\n    \n    private void GenerateSampleDocument(string filePath, Color color, int length)\n    {\n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Size(PageSizes.A4);\n                    page.PageColor(Colors.Transparent);\n                    \n                    page.Content().Column(column =>\n                    {\n                        foreach (var i in Enumerable.Range(1, length))\n                        {\n                            if (i != 1)\n                                column.Item().PageBreak();\n                            \n                            var width = Random.Shared.Next(100, 200);\n                            var height = Random.Shared.Next(100, 200);\n                            \n                            var horizontalTranslation = Random.Shared.Next(0, (int)PageSizes.A4.Width - width);\n                            var verticalTranslation = Random.Shared.Next(0, (int)PageSizes.A4.Height - height);\n                            \n                            column.Item()\n                                .TranslateX(horizontalTranslation)\n                                .TranslateY(verticalTranslation)\n                                .Width(width)\n                                .Height(height)\n                                .Background(color.WithAlpha(64))\n                                .AlignCenter()\n                                .AlignMiddle()\n                                .Text($\"{filePath}\\npage {i}\")\n                                .FontColor(color)\n                                .Bold()\n                                .FontSize(16);\n                        }\n                    });\n                });\n            })\n            .WithSettings(new DocumentSettings { PdfA = true })\n            .GeneratePdf(filePath);\n    }\n} "
  },
  {
    "path": "Source/QuestPDF.UnitTests/DynamicImageTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\nusing SkiaSharp;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class DynamicImageTests\n    {\n        [Test]\n        public void Measure_TakesAvailableSpaceRegardlessOfSize()\n        {\n            TestPlan\n                .For(x => new DynamicImage\n                {\n                    TargetDpi = DocumentSettings.DefaultRasterDpi,\n                    CompressionQuality = ImageCompressionQuality.High,\n                    Source = payload => GenerateImage(payload.ImageSize)\n                })\n                .MeasureElement(new Size(300, 200))\n                .CheckMeasureResult(SpacePlan.FullRender(300, 200));\n        }\n        \n        [Test]\n        public void Draw_HandlesNull()\n        {\n            TestPlan\n                .For(x => new DynamicImage\n                {\n                    TargetDpi = DocumentSettings.DefaultRasterDpi,\n                    CompressionQuality = ImageCompressionQuality.High,\n                    Source = size => null\n                })\n                .DrawElement(new Size(300, 200))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_PreservesSize()\n        {\n            TestPlan\n                .For(x => new DynamicImage\n                {\n                    TargetDpi = DocumentSettings.DefaultRasterDpi,\n                    CompressionQuality = ImageCompressionQuality.High,\n                    Source = payload => GenerateImage(payload.ImageSize)\n                })\n                .DrawElement(new Size(300, 200))\n                .ExpectCanvasDrawImage(Position.Zero, new Size(300, 200))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_PassesCorrectSizeToSource()\n        {\n            ImageSize passedSize = default;\n\n            TestPlan\n                .For(x => new DynamicImage\n                {\n                    TargetDpi = DocumentSettings.DefaultRasterDpi * 3,\n                    CompressionQuality = ImageCompressionQuality.High,\n                    Source = payload =>\n                    {\n                        passedSize = payload.ImageSize;\n                        return GenerateImage(payload.ImageSize);\n                    }\n                })\n                .DrawElement(new Size(400, 300))\n                .ExpectCanvasDrawImage(Position.Zero, new Size(400, 300))\n                .CheckDrawResult();\n            \n            Assert.That(passedSize.Width, Is.EqualTo(1200));\n            Assert.That(passedSize.Height, Is.EqualTo(900));\n        }\n        \n        byte[] GenerateImage(ImageSize size)\n        {\n            var image = GenerateImage(size.Width, size.Height);\n            return image.Encode(SKEncodedImageFormat.Png, 100).ToArray();\n        }\n\n        static SKImage GenerateImage(int width, int height)\n        {\n            var imageInfo = new SKImageInfo(width, height);\n            using var surface = SKSurface.Create(imageInfo);\n            return surface.Snapshot();\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/EnsureSpaceTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class EnsureSpaceTests\n    {\n        [Test]\n        public void Measure_ReturnsPartialRenderWithZeroSize_WhenChildReturnsWrap()\n        {\n            TestPlan\n                .For(x => new EnsureSpace\n                {\n                    Child = x.CreateChild(),\n                    MinHeight = 200\n                })\n                .MeasureElement(new Size(400, 100))\n                .ExpectChildMeasure(new Size(400, 100), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.PartialRender(Size.Zero));\n        }\n        \n        [Test]\n        public void Measure_ReturnsPartialRenderWithZeroSize_WhenChildReturnsPartialRender_AndNotEnoughSpace()\n        {\n            TestPlan\n                .For(x => new EnsureSpace\n                {\n                    Child = x.CreateChild(),\n                    MinHeight = 200\n                })\n                .MeasureElement(new Size(400, 100))\n                .ExpectChildMeasure(new Size(400, 100), SpacePlan.PartialRender(300, 50))\n                .CheckMeasureResult(SpacePlan.PartialRender(Size.Zero));\n        }\n        \n        [Test]\n        public void Measure_ReturnsPartialRender_WhenChildReturnsPartialRender_AndEnoughSpace()\n        {\n            TestPlan\n                .For(x => new EnsureSpace\n                {\n                    Child = x.CreateChild(),\n                    MinHeight = 200\n                })\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(new Size(400, 300), SpacePlan.PartialRender(300, 250))\n                .CheckMeasureResult(SpacePlan.PartialRender(300, 250));\n        }\n        \n        [Test]\n        public void Measure_ReturnsFullRender_WhenChildReturnsFullRender_AndNotEnoughSpace()\n        {\n            TestPlan\n                .For(x => new EnsureSpace\n                {\n                    Child = x.CreateChild(),\n                    MinHeight = 200\n                })\n                .MeasureElement(new Size(400, 100))\n                .ExpectChildMeasure(new Size(400, 100), SpacePlan.FullRender(300, 50))\n                .CheckMeasureResult(SpacePlan.FullRender(300, 50));\n        }\n        \n        [Test]\n        public void Measure_ReturnsFullRender_WhenChildReturnsFullRender_AndEnoughSpace()\n        {\n            TestPlan\n                .For(x => new EnsureSpace\n                {\n                    Child = x.CreateChild(),\n                    MinHeight = 200\n                })\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(new Size(400, 300), SpacePlan.FullRender(300, 250))\n                .CheckMeasureResult(SpacePlan.FullRender(300, 250));\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/ExtendTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class ExtendTests\n    {\n        [Test]\n        public void Measure_ReturnsWrap_WhenChildReturnsWrap()\n        {\n            TestPlan\n                .For(x => new Extend\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 200))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Forwarded from child\"));\n        }\n        \n        [Test]\n        public void Measure_ReturnsPartialRender_WhenChildReturnsPartialRender()\n        {\n            TestPlan\n                .For(x => new Extend\n                {\n                    Child = x.CreateChild(),\n                    ExtendHorizontal = true,\n                    ExtendVertical = true\n                })\n                .MeasureElement(new Size(400, 200))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.PartialRender(300, 100))\n                .CheckMeasureResult(SpacePlan.PartialRender(400, 200));\n        }\n        \n        [Test]\n        public void Measure_ReturnsFullRender_WhenChildReturnsFullRender()\n        {\n            TestPlan\n                .For(x => new Extend\n                {\n                    Child = x.CreateChild(),\n                    ExtendHorizontal = true,\n                    ExtendVertical = true\n                })\n                .MeasureElement(new Size(400, 200))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(300, 100))\n                .CheckMeasureResult(SpacePlan.FullRender(400, 200));\n        }\n        \n        [Test]\n        public void Measure_ExtendHorizontal()\n        {\n            TestPlan\n                .For(x => new Extend\n                {\n                    Child = x.CreateChild(),\n                    ExtendHorizontal = true,\n                    ExtendVertical = false\n                })\n                .MeasureElement(new Size(400, 200))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 100))\n                .CheckMeasureResult(SpacePlan.FullRender(400, 100));\n        }\n        \n        [Test]\n        public void Measure_ExtendVertical()\n        {\n            TestPlan\n                .For(x => new Extend\n                {\n                    Child = x.CreateChild(),\n                    ExtendHorizontal = false,\n                    ExtendVertical = true\n                })\n                .MeasureElement(new Size(400, 200))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(100, 100))\n                .CheckMeasureResult(SpacePlan.FullRender(100, 200));\n        }\n\n        [Test]\n        public void Draw() => SimpleContainerTests.Draw<Extend>();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/ExternalLinkTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Elements;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class ExternalLinkTests\n    {\n        [Test]\n        public void Measure() => SimpleContainerTests.Measure<Hyperlink>();\n        \n        // TODO: consider tests for the Draw method\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/FontManagerTests.cs",
    "content": "﻿using System;\nusing System.IO;\nusing NUnit.Framework;\nusing QuestPDF.Drawing;\n\nnamespace QuestPDF.UnitTests\n{\n    public class FontManagerTests\n    {\n        [Test]\n        public void LoadFontFromFile()\n        {\n            using var stream = File.OpenRead(\"Resources/FontContent.ttf\"); \n            FontManager.RegisterFont(stream);\n        }\n        \n        [Test]\n        public void LoadFontFromEmbeddedResource()\n        {\n            FontManager.RegisterFontFromEmbeddedResource(\"QuestPDF.UnitTests.Resources.FontEmbeddedResource.ttf\");\n        }\n        \n        [Test]\n        public void LoadFontFromEmbeddedResource_ShouldThrowException_WhenResourceIsNotAvailable()\n        {\n            Assert.Throws<ArgumentException>(() =>\n            {\n                FontManager.RegisterFontFromEmbeddedResource(\"QuestPDF.UnitTests.WrongPath.ttf\");\n            });\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/ImageGenerationTests.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Linq;\nusing NUnit.Framework;\nusing NUnit.Framework.Legacy;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing SkiaSharp;\n\nnamespace QuestPDF.UnitTests\n{\n    public class GenerateImageTests\n    {\n        [Test]\n        [TestCaseSource(nameof(GeneratedImageResolutionCorrespondsToTargetDpi_TestCases))]\n        public void GeneratedImageResolutionCorrespondsToTargetDpi(GeneratedImageResolutionCorrespondsToTargetDpi_TestCaseItem testCase)\n        {\n            // act\n            var images = Document\n                .Create(document => document.Page(page =>\n                {\n                    page.Size(testCase.PageSize);\n                    page.Content().Text(\"Test\");\n                }))\n                .GenerateImages(new ImageGenerationSettings { RasterDpi = testCase.TargetDpi })\n                .ToList();\n            \n            // assert\n            Assert.That(images, Has.Exactly(1).Items);\n\n            var imageData = images.First();\n            Assert.That(imageData, Is.Not.Null);\n            \n            using var image = SKImage.FromEncodedData(imageData);\n            Assert.That(image, Is.Not.Null);\n            \n            Assert.That(image.Width, Is.EqualTo(testCase.ExpectedImageSize.Width));\n            Assert.That(image.Height, Is.EqualTo(testCase.ExpectedImageSize.Height));\n        }\n\n        public record GeneratedImageResolutionCorrespondsToTargetDpi_TestCaseItem(PageSize PageSize, int TargetDpi, ImageSize ExpectedImageSize);\n        \n        public static GeneratedImageResolutionCorrespondsToTargetDpi_TestCaseItem[] GeneratedImageResolutionCorrespondsToTargetDpi_TestCases =\n        {\n            new(new PageSize(150, 250), 72, new ImageSize(150, 250)),\n            new(new PageSize(200, 300), 144, new ImageSize(400, 600)),\n            new(new PageSize(250, 350), 360, new ImageSize(1250, 1750)),\n        };\n\n\n\n        [Test]\n        public void GeneratedImageSizeCorrespondsToImageQuality()\n        {\n            // arrange\n            var document = Document.Create(document => document.Page(page =>\n            {\n                page.Content().Image(\"Resources/photo.jpg\");\n            }));\n            \n            // act\n            var imageSizeWithLowQuality = CheckImageSize(ImageCompressionQuality.Low);\n            var imageSizeWithMediumQuality = CheckImageSize(ImageCompressionQuality.Medium);\n            var imageSizeWithHighQuality = CheckImageSize(ImageCompressionQuality.High);\n            \n            // assert\n            Assert.That(imageSizeWithLowQuality, Is.LessThan(imageSizeWithMediumQuality));\n            Assert.That(imageSizeWithMediumQuality, Is.LessThan(imageSizeWithHighQuality));\n\n            int CheckImageSize(ImageCompressionQuality quality)\n            {\n                var images = document\n                    .GenerateImages(new ImageGenerationSettings() { ImageFormat = ImageFormat.Jpeg, ImageCompressionQuality = quality })\n                    .ToList();\n                \n                Assert.That(images, Has.Exactly(1).Items);\n\n                var image = images.First();\n                Assert.That(image, Is.Not.Null);\n\n                return image.Length;\n            }\n        }\n        \n        \n        [TestCase(ImageFormat.Png)]\n        [TestCase(ImageFormat.Jpeg)]\n        [TestCase(ImageFormat.Webp)]\n        public void ImageFormatIsRespected(ImageFormat imageFormat)\n        {\n            var images = Document\n                .Create(document =>\n                {\n                    document.Page(page =>\n                    {\n                        page.Content().Padding(25).AspectRatio(2).Background(Colors.Red.Medium);\n                    });\n                })\n                .GenerateImages(new ImageGenerationSettings() { ImageFormat = imageFormat })\n                .ToList();\n            \n            Assert.That(images, Has.Exactly(1).Items);\n\n            var imageData = images.First();\n            Assert.That(imageData, Is.Not.Null);\n\n            using var imageStream = new MemoryStream(imageData);\n            using var imageCodec = SKCodec.Create(imageStream);\n\n            Assert.That(imageCodec, Is.Not.Null);\n            Assert.That(imageCodec.EncodedFormat.ToString(), Is.EqualTo(imageFormat.ToString()));\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/ImageTests.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Linq;\nusing System.Net.Mime;\nusing System.Threading;\nusing NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Drawing.Exceptions;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\nusing SkiaSharp;\nusing ImageElement = QuestPDF.Elements.Image;\nusing DocumentImage = QuestPDF.Infrastructure.Image;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class ImageTests\n    {\n        [Test]\n        public void Measure_TakesMinimalSpaceRegardlessOfSize()\n        {\n            TestPlan\n                .For(x => new ImageElement\n                {\n                    DocumentImage = GenerateDocumentImage(400, 300)\n                })\n                .MeasureElement(new Size(300, 200))\n                .CheckMeasureResult(SpacePlan.FullRender(0, 0));\n        }\n        \n        [Test]\n        public void Draw_TakesAvailableSpaceRegardlessOfSize()\n        {\n            TestPlan\n                .For(x => new ImageElement\n                {\n                    CompressionQuality = ImageCompressionQuality.High,\n                    TargetDpi = DocumentSettings.DefaultRasterDpi,\n                    DocumentImage = GenerateDocumentImage(400, 300)\n                })\n                .DrawElement(new Size(300, 200))\n                .ExpectCanvasDrawImage(new Position(0, 0), new Size(300, 200))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Fluent_RecognizesImageProportions()\n        {\n            var image = GenerateDocumentImage(60, 20);\n            \n            TestPlan\n                .For(x =>\n                {\n                    var container = new Container();\n                    container.Image(image);\n                    return container;\n                })\n                .MeasureElement(new Size(300, 200))\n                .CheckMeasureResult(SpacePlan.FullRender(300, 100));\n        }\n        \n        [Test]\n        public void ImageObject_ThrowsEncodingException_WhenImageDataIsIncorrect()\n        {\n            Func<Infrastructure.Image> action = () => Infrastructure.Image.FromBinaryData(new byte[] { 1, 2, 3 });\n            Assert.That(action, Throws.Exception.TypeOf<DocumentComposeException>().With.Message.EqualTo(\"Cannot decode the provided image.\"));\n        }\n        \n        [Test]\n        public void ImageObject_ThrowsEncodingException_WhenStreamIsIncorrect()\n        {\n            Func<Infrastructure.Image> action = () =>\n            {\n                using var stream = new MemoryStream(new byte[] { 1, 2, 3 });\n                return Infrastructure.Image.FromStream(stream);\n            };\n\n            Assert.That(action, Throws.Exception.TypeOf<DocumentComposeException>().With.Message.EqualTo(\"Cannot decode the provided image.\"));\n        }\n        \n        [Test]\n        public void ImageObject_ThrowsFileNotFoundException_FileIsNotFound()\n        {\n            var action = () => Infrastructure.Image.FromFile(\"non-existing-file.jpg\");\n            Assert.That(action, Throws.Exception.TypeOf<DocumentComposeException>().With.Message.EqualTo(\"Cannot load an image under the provided relative path, file not found: non-existing-file.jpg\"));\n        }\n\n        [Test]\n        public void UsingSharedImageShouldNotDrasticallyIncreaseDocumentSize()\n        {\n            var photo = File.ReadAllBytes(\"Resources/photo.jpg\");\n\n            var documentWithSingleImageSize = GetDocumentSize(container =>\n            {\n                container.Image(photo);\n            });\n\n            var documentWithMultipleImagesSize = GetDocumentSize(container =>\n            {\n                container.Column(column =>\n                {\n                    foreach (var i in Enumerable.Range(0, 10))\n                        column.Item().Image(photo);\n                });\n            });\n\n            using var sharedImage = DocumentImage.FromBinaryData(photo);\n            \n            var documentWithSingleImageUsedMultipleTimesSize = GetDocumentSize(container =>\n            {\n                container.Column(column =>\n                {\n                    foreach (var i in Enumerable.Range(0, 10))\n                        column.Item().Image(sharedImage);\n                });\n            });\n\n            var documentWithMultipleImagesSizeRatio = (documentWithMultipleImagesSize / (float)documentWithSingleImageSize);\n            Assert.That(documentWithMultipleImagesSizeRatio, Is.InRange(9.9f, 10));\n            \n            var documentWithSingleImageUsedMultipleTimesSizeRatio = (documentWithSingleImageUsedMultipleTimesSize / (float)documentWithSingleImageSize);\n            Assert.That(documentWithSingleImageUsedMultipleTimesSizeRatio, Is.InRange(1f, 1.05f));\n        }\n        \n        [Test]\n        public void ImageCompressionHasImpactOnDocumentSize()\n        {\n            var photo = File.ReadAllBytes(\"Resources/photo.jpg\");\n\n            var veryLowCompressionSize = GetDocumentSize(container => container.Image(photo).WithCompressionQuality(ImageCompressionQuality.VeryLow));\n            var bestCompressionSize = GetDocumentSize(container => container.Image(photo).WithCompressionQuality(ImageCompressionQuality.Best));\n\n            var compressionSizeRatio = (bestCompressionSize / (float)veryLowCompressionSize);\n            Assert.That(compressionSizeRatio, Is.GreaterThan(10));\n        }\n        \n        [Test]\n        public void TargetDpiHasImpactOnDocumentSize()\n        {\n            var photo = File.ReadAllBytes(\"Resources/photo.jpg\");\n            \n            var lowDpiSize = GetDocumentSize(container => container.Image(photo).WithRasterDpi(12));\n            var highDpiSize = GetDocumentSize(container => container.Image(photo).WithRasterDpi(144));\n\n            var dpiSizeRatio = (highDpiSize / (float)lowDpiSize);\n            Assert.That(dpiSizeRatio, Is.GreaterThan(35));\n        }\n        \n        private static int GetDocumentSize(Action<IContainer> container)\n        {\n            return Document\n                .Create(document =>\n                {\n                    document.Page(page =>\n                    {\n                        page.Content().Element(container);\n                    });\n                })\n                .GeneratePdf()\n                .Length;\n        }\n\n        static DocumentImage GenerateDocumentImage(int width, int height)\n        {\n            var image = Placeholders.Image(width, height);\n            var result = DocumentImage.FromBinaryData(image);\n            result.IsShared = false;\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/InternalLinkTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Elements;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class InternalLinkTests\n    {\n        [Test]\n        public void Measure() => SimpleContainerTests.Measure<SectionLink>();\n        \n        // TODO: consider tests for the Draw method\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/InternalLocationTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Elements;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class InternalLocationTests\n    {\n        [Test]\n        public void Measure() => SimpleContainerTests.Measure<SectionLink>();\n        \n        // TODO: consider tests for the Draw method\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/LayersTests.cs",
    "content": "﻿using System.Collections.Generic;\nusing NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class LayersTests\n    {\n        private const string BackgroundLayer = \"background\";\n        private const string MainLayer = \"main\";\n        private const string ForegroundLayer = \"foreground\";\n        \n        private static Layers GetLayers(TestPlan x)\n        {\n            return new Layers\n            {\n                Children = new List<Layer>\n                {\n                    new Layer\n                    {\n                        Child = x.CreateChild(BackgroundLayer)\n                    },\n                    new Layer\n                    {\n                        Child = x.CreateChild(MainLayer),\n                        IsPrimary = true\n                    },\n                    new Layer\n                    {\n                        Child = x.CreateChild(ForegroundLayer)\n                    }\n                }\n            };\n        }\n        \n        #region measure\n        \n        [Test]\n        public void Measure_Wrap()\n        {\n            TestPlan\n                .For(GetLayers)\n                .MeasureElement(new Size(800, 600))\n                .ExpectChildMeasure(MainLayer, new Size(800, 600), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"The content of the primary layer does not fit (even partially) the available space.\"));\n        }\n\n        [Test]\n        public void Measure_PartialRender()\n        {\n            TestPlan\n                .For(GetLayers)\n                .MeasureElement(new Size(800, 600))\n                .ExpectChildMeasure(MainLayer, new Size(800, 600), SpacePlan.PartialRender(700, 500))\n                .CheckMeasureResult(SpacePlan.PartialRender(700, 500));\n        }\n        \n        [Test]\n        public void Measure_FullRender()\n        {\n            TestPlan\n                .For(GetLayers)\n                .MeasureElement(new Size(800, 600))\n                .ExpectChildMeasure(MainLayer, new Size(800, 600), SpacePlan.FullRender(500, 400))\n                .CheckMeasureResult(SpacePlan.FullRender(500, 400));\n        }\n        \n        #endregion\n        \n        #region draw\n        \n        [Test]\n        public void Draw_Simple()\n        {\n            TestPlan\n                .For(GetLayers)\n                .MeasureElement(new Size(800, 600))\n                \n                .ExpectChildMeasure(BackgroundLayer, new Size(800, 600), SpacePlan.FullRender(100, 200))\n                .ExpectChildMeasure(MainLayer, new Size(800, 600), SpacePlan.PartialRender(200, 300))\n                .ExpectChildMeasure(ForegroundLayer, new Size(800, 600), SpacePlan.FullRender(300, 400))\n                \n                \n                .ExpectChildDraw(BackgroundLayer, new Size(800, 600))\n                .ExpectChildDraw(MainLayer, new Size(800, 600))\n                .ExpectChildDraw(ForegroundLayer, new Size(800, 600))\n                \n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenSecondaryLayerReturnsWrap_SkipThatLayer_1()\n        {\n            TestPlan\n                .For(GetLayers)\n                .MeasureElement(new Size(800, 600))\n                \n                .ExpectChildMeasure(BackgroundLayer, new Size(800, 600), SpacePlan.PartialRender(100, 200))\n                .ExpectChildMeasure(MainLayer, new Size(800, 600), SpacePlan.PartialRender(200, 300))\n                .ExpectChildMeasure(ForegroundLayer, new Size(800, 600), SpacePlan.Wrap(\"Mock\"))\n                \n                .ExpectChildDraw(BackgroundLayer, new Size(800, 600))\n                .ExpectChildDraw(MainLayer, new Size(800, 600))\n                \n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenSecondaryLayerReturnsWrap_SkipThatLayer_2()\n        {\n            TestPlan\n                .For(GetLayers)\n                .MeasureElement(new Size(800, 600))\n                \n                .ExpectChildMeasure(BackgroundLayer, new Size(800, 600), SpacePlan.Wrap(\"Mock\"))\n                .ExpectChildMeasure(MainLayer, new Size(800, 600), SpacePlan.PartialRender(200, 300))\n                .ExpectChildMeasure(ForegroundLayer, new Size(800, 600), SpacePlan.PartialRender(300, 400))\n                \n                .ExpectChildDraw(MainLayer, new Size(800, 600))\n                .ExpectChildDraw(ForegroundLayer, new Size(800, 600))\n                \n                .CheckDrawResult();\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/LicenseSetup.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests\n{\n    [SetUpFixture]\n    public class LicenseSetup\n    {\n        [OneTimeSetUp]\n        public static void Setup()\n        {\n            QuestPDF.Settings.License = LicenseType.Community;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/LineTests.cs",
    "content": "using System;\nusing NUnit.Framework;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests;\n\npublic class LineTests\n{\n    #region Line Types\n    \n    [Test]\n    public void VerticalLineTypeIsSetCorrectly()\n    {\n        var container = EmptyContainer.Create();\n        container.LineVertical(2);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.Type, Is.EqualTo(LineType.Vertical));\n        Assert.That(line?.Thickness, Is.EqualTo(2));\n    }\n    \n    [Test]\n    public void HorizontalLineTypeIsSetCorrectly()\n    {\n        var container = EmptyContainer.Create();\n        container.LineHorizontal(3);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.Type, Is.EqualTo(LineType.Horizontal));\n        Assert.That(line?.Thickness, Is.EqualTo(3));\n    }\n    \n    #endregion\n    \n    #region Line Thickness\n    \n    [Test]\n    public void VerticalLineThicknessSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        container.LineVertical(2, Unit.Inch);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.Thickness, Is.EqualTo(144));\n    }\n    \n    [TestCase(-5f)]\n    [TestCase(-float.Epsilon)]\n    public void LineThicknessCannotBeNegative(float thickness)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer\n                .Create()\n                .LineVertical(thickness);\n        });\n        \n        Assert.That(exception.Message, Is.EqualTo(\"The Line thickness cannot be negative. (Parameter 'thickness')\"));\n    }\n    \n    [Test]\n    public void LineThicknessCanBeEqualToZero()\n    {\n        // thickness 0 corresponds to a hairline\n        \n        var container = EmptyContainer.Create();\n        container.LineHorizontal(0);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.Thickness, Is.Zero);\n    }\n    \n    [Test]\n    public void HorizontalLineThicknessSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        container.LineHorizontal(3, Unit.Inch);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.Thickness, Is.EqualTo(216));\n    }\n    \n    #endregion\n    \n    [Test]\n    public void LineColorIsSetCorrectly()\n    {\n        var container = EmptyContainer.Create();\n        container.LineHorizontal(1).LineColor(Colors.Red.Medium);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.Color, Is.EqualTo(Colors.Red.Medium));\n    }\n    \n    #region Line Dash Pattern\n    \n    [Test]\n    public void LineDashPatternCannotBeNull()\n    {\n        var exception = Assert.Throws<ArgumentNullException>(() =>\n        {\n            EmptyContainer\n                .Create()\n                .LineVertical(1)\n                .LineDashPattern(null);\n        });\n        \n        Assert.That(exception.Message, Is.EqualTo(\"The dash pattern cannot be null. (Parameter 'dashPattern')\"));\n    }\n    \n    [Test]\n    public void LineDashPatternCannotBeEmpty()\n    {\n        var exception = Assert.Throws<ArgumentException>(() =>\n        {\n            EmptyContainer\n                .Create()\n                .LineVertical(1)\n                .LineDashPattern([]);\n        });\n        \n        Assert.That(exception.Message, Is.EqualTo(\"The dash pattern cannot be empty. (Parameter 'dashPattern')\"));\n    }\n    \n    [Test]\n    public void LineDashPatternMustHaveEvenNumberOfElements()\n    {\n        var exception = Assert.Throws<ArgumentException>(() =>\n        {\n            EmptyContainer\n                .Create()\n                .LineVertical(1)\n                .LineDashPattern([ 1, 2, 3 ]);\n        });\n        \n        Assert.That(exception.Message, Is.EqualTo(\"The dash pattern must contain an even number of elements. (Parameter 'dashPattern')\"));\n    }\n    \n    [Test]\n    public void LineDashPatternIsSetCorrectly()\n    {\n        var container = EmptyContainer.Create();\n\n        container\n            .LineVertical(1)\n            .LineDashPattern([1, 2, 3, 4]);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.DashPattern, Is.EquivalentTo([ 1, 2, 3, 4 ]));\n    }\n    \n    [Test]\n    public void LineDashPatternSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n\n        container\n            .LineVertical(1)\n            .LineDashPattern([1, 2, 3, 4], Unit.Inch);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.DashPattern, Is.EquivalentTo([ 72, 144, 216, 288 ]));\n    }\n    \n    #endregion\n    \n    #region Gradient Colors\n    \n    [Test]\n    public void LineGradientColorsCannotBeBull()\n    {\n        var exception = Assert.Throws<ArgumentNullException>(() =>\n        {\n            EmptyContainer\n                .Create()\n                .LineVertical(1)\n                .LineGradient(null);\n        });\n        \n        Assert.That(exception.Message, Is.EqualTo(\"The gradient colors cannot be null. (Parameter 'colors')\"));\n    }\n    \n    [Test]\n    public void LineGradientColorsCannotBeEmpty()\n    {\n        var exception = Assert.Throws<ArgumentException>(() =>\n        {\n            EmptyContainer\n                .Create()\n                .LineVertical(1)\n                .LineGradient([]);\n        });\n        \n        Assert.That(exception.Message, Is.EqualTo(\"The gradient colors cannot be empty. (Parameter 'colors')\"));\n    }\n    \n    [Test]\n    public void LineGradientColorsAreSetCorrectly()\n    {\n        var container = EmptyContainer.Create();\n            \n        container\n            .LineVertical(1)\n            .LineGradient([Colors.Red.Medium, Colors.Green.Medium, Colors.Blue.Medium]);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.GradientColors, Is.EquivalentTo([ Colors.Red.Medium, Colors.Green.Medium, Colors.Blue.Medium ]));\n    }\n    \n    #endregion\n    \n    #region Companion Hint\n    \n    [Test]\n    public void VerticalLineCompanionHint()\n    {\n        var container = EmptyContainer.Create();\n        container.LineVertical(123.45f);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.GetCompanionHint(), Is.EqualTo(\"Vertical 123.5\"));\n    }\n    \n    [Test]\n    public void HorizontalLineCompanionHint()\n    {\n        var container = EmptyContainer.Create();\n        container.LineHorizontal(234.56f);\n        \n        var line = container.Child as Line;\n        Assert.That(line?.GetCompanionHint(), Is.EqualTo(\"Horizontal 234.6\"));\n    }\n    \n    #endregion\n    \n    [Test]\n    [Repeat(10)]\n    public void LineSupportsStatefulOperations()\n    {\n        var container = EmptyContainer.Create();\n\n        container.LineHorizontal(1);\n        \n        var line = container.Child as Line;\n        \n        Assert.That(line.GetState(), Is.False);\n        line.SetState(true);\n        Assert.That(line.GetState(), Is.True);\n        \n        line.ResetState();\n        Assert.That(line.GetState(), Is.False);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/PaddingTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class PaddingTests\n    {\n        [TestCase(0, 0, 0, 0, \"\")]\n        [TestCase(10, 0, 0, 0, \"L=10\")]\n        [TestCase(0, 15, 0, 0, \"T=15\")]\n        [TestCase(0, 0, 20, 0, \"R=20\")]\n        [TestCase(0, 0, 0, 25, \"B=25\")]\n        [TestCase(50, 0, 50, 0, \"H=50\")]\n        [TestCase(0, 60, 0, 60, \"V=60\")]\n        [TestCase(10, -20, 10, -30, \"L=10   T=-20   R=10   B=-30\")]\n        [TestCase(-5, -10, 15, -10, \"L=-5   T=-10   R=15   B=-10\")]\n        [TestCase(1.234f, -2.345f, 3.456f, -4.567f, \"L=1.2   T=-2.3   R=3.5   B=-4.6\")]\n        [TestCase(5, 5, 5, 5, \"A=5\")]\n        public void CompanionHint(float left, float top, float right, float bottom, string expected)\n        {\n            var container = EmptyContainer.Create();\n            \n            container\n                .PaddingLeft(left)\n                .PaddingTop(top)\n                .PaddingRight(right)\n                .PaddingBottom(bottom);\n            \n            var translationElement = container.Child as Padding;\n            var companionHint = translationElement?.GetCompanionHint();\n            \n            Assert.That(companionHint, Is.EqualTo(expected));\n        }\n        \n        #region Cumulative Property\n        \n        [Test]\n        public void PaddingLeftIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.PaddingLeft(-20).PaddingLeft(25).PaddingLeft(30);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Left, Is.EqualTo(35));\n        }\n        \n        [Test]\n        public void PaddingTopIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.PaddingTop(20).PaddingTop(-25).PaddingTop(30);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Top, Is.EqualTo(25));\n        }\n        \n        [Test]\n        public void PaddingRightIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.PaddingRight(20).PaddingRight(25).PaddingRight(-30);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Right, Is.EqualTo(15));\n        }\n        \n        [Test]\n        public void PaddingBottomIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.PaddingBottom(-20).PaddingBottom(-25).PaddingBottom(30);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Bottom, Is.EqualTo(-15));\n        }\n        \n        #endregion\n        \n        #region Simple Asignment\n        \n        [Test]\n        public void PaddingVerticalShorthandWorksCorrectly()\n        {\n            var container = EmptyContainer.Create();\n\n            container.PaddingVertical(123);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Left, Is.Zero);\n            Assert.That(rowContainer?.Top, Is.EqualTo(123));\n            Assert.That(rowContainer?.Right, Is.Zero);\n            Assert.That(rowContainer?.Bottom, Is.EqualTo(123));\n        }\n        \n        [Test]\n        public void PaddingHorizontalShorthandWorksCorrectly()\n        {\n            var container = EmptyContainer.Create();\n\n            container.PaddingHorizontal(234);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Left, Is.EqualTo(234));\n            Assert.That(rowContainer?.Top, Is.Zero);\n            Assert.That(rowContainer?.Right, Is.EqualTo(234));\n            Assert.That(rowContainer?.Bottom, Is.Zero);\n        }\n        \n        [Test]\n        public void PaddingAllShorthandWorksCorrectly()\n        {\n            var container = EmptyContainer.Create();\n\n            container.Padding(456);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Left, Is.EqualTo(456));\n            Assert.That(rowContainer?.Top, Is.EqualTo(456));\n            Assert.That(rowContainer?.Right, Is.EqualTo(456));\n            Assert.That(rowContainer?.Bottom, Is.EqualTo(456));\n        }\n        \n        #endregion\n        \n        #region Unit Conversion\n        \n        [Test]\n        public void PaddingLeftAppliesUnitConversion()\n        {\n            var container = EmptyContainer.Create();\n\n            container.PaddingLeft(2, Unit.Inch);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Left, Is.EqualTo(144));\n        }\n        \n        [Test]\n        public void PaddingTopAppliesUnitConversion()\n        {\n            var container = EmptyContainer.Create();\n\n            container.PaddingTop(3, Unit.Inch);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Top, Is.EqualTo(216));\n        }\n        \n        [Test]\n        public void PaddingRightAppliesUnitConversion()\n        {\n            var container = EmptyContainer.Create();\n\n            container.PaddingRight(4, Unit.Inch);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Right, Is.EqualTo(288));\n        }\n        \n        [Test]\n        public void PaddingBottomAppliesUnitConversion()\n        {\n            var container = EmptyContainer.Create();\n\n            container.PaddingBottom(5, Unit.Inch);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Bottom, Is.EqualTo(360));\n        }\n        \n        [Test]\n        public void PaddingVerticalAppliesUnitConversion()\n        {\n            var container = EmptyContainer.Create();\n\n            container.PaddingVertical(6, Unit.Inch);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Top, Is.EqualTo(432));\n            Assert.That(rowContainer?.Bottom, Is.EqualTo(432));\n        }\n        \n        [Test]\n        public void PaddingHorizontalAppliesUnitConversion()\n        {\n            var container = EmptyContainer.Create();\n\n            container.PaddingHorizontal(7, Unit.Inch);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Left, Is.EqualTo(504));\n            Assert.That(rowContainer?.Right, Is.EqualTo(504));\n        }\n        \n        [Test]\n        public void PaddingAllAppliesUnitConversion()\n        {\n            var container = EmptyContainer.Create();\n\n            container.Padding(8, Unit.Inch);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Left, Is.EqualTo(576));\n            Assert.That(rowContainer?.Top, Is.EqualTo(576));\n            Assert.That(rowContainer?.Right, Is.EqualTo(576));\n            Assert.That(rowContainer?.Bottom, Is.EqualTo(576));\n        }\n        \n        #endregion\n        \n        [Test]\n        public void PaddingAppliesCorrectValues()\n        {\n            var container = EmptyContainer.Create();\n\n            container\n                .PaddingLeft(20)\n                .PaddingTop(25)\n                .PaddingRight(30)\n                .PaddingBottom(35)\n                .PaddingVertical(-5)\n                .PaddingHorizontal(-15)\n                .Padding(10);\n        \n            var rowContainer = container.Child as Padding;\n            Assert.That(rowContainer?.Left, Is.EqualTo(15));\n            Assert.That(rowContainer?.Top, Is.EqualTo(30));\n            Assert.That(rowContainer?.Right, Is.EqualTo(25));\n            Assert.That(rowContainer?.Bottom, Is.EqualTo(40));\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/PageBreakTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class PageBreakTests\n    {\n        [Test]\n        public void Measure()\n        {\n            TestPlan\n                .For(x => new PageBreak())\n                \n                .MeasureElement(new Size(400, 300))\n                .CheckMeasureResult(SpacePlan.PartialRender(Size.Zero))\n                \n                .DrawElement(new Size(400, 300))\n                .CheckDrawResult()\n                \n                .MeasureElement(new Size(500, 400))\n                .CheckMeasureResult(SpacePlan.Empty());\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/QuestPDF.UnitTests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <SatelliteResourceLanguages>en</SatelliteResourceLanguages>\n        <IsPackable>false</IsPackable>\n        <IsTestProject>true</IsTestProject>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"nunit\" Version=\"4.4.0\" />\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"4.11.2\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"6.1.0\" />\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.13.0\" />\n        <PackageReference Include=\"SkiaSharp\" Version=\"3.119.1\" />\n        <PackageReference Include=\"SkiaSharp.NativeAssets.Linux.NoDependencies\" Version=\"3.119.1\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\QuestPDF\\QuestPDF.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <Content Include=\"Resources\\FontContent.ttf\">\n        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      </Content>\n      <EmbeddedResource Include=\"Resources\\FontEmbeddedResource.ttf\">\n        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      </EmbeddedResource>\n    </ItemGroup>\n\n    <ItemGroup>\n      <None Update=\"Resources\\photo.jpg\">\n        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      </None>\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF.UnitTests/RotateTests.cs",
    "content": "using NUnit.Framework;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests;\n\npublic class RotateTests\n{\n    [Test]\n    public void RotateIsCumulative()\n    {\n        var container = EmptyContainer.Create();\n        \n        container\n            .Rotate(45)\n            .Rotate(-15)\n            .Rotate(20);\n        \n        var rotation = container.Child as Rotate;\n        Assert.That(rotation?.Angle, Is.EqualTo(50));\n    }\n    \n    [TestCase(0, ExpectedResult = \"No rotation\")]\n    [TestCase(45, ExpectedResult = \"45 deg clockwise\")]\n    [TestCase(-75, ExpectedResult = \"75 deg counter-clockwise\")]\n    [TestCase(12.345f, ExpectedResult = \"12.3 deg clockwise\")]\n    public string RotateCompanionHint(float angle)\n    {\n        var container = EmptyContainer.Create();\n        container.Rotate(angle);\n        \n        var rotation = container.Child as Rotate;\n        return rotation?.GetCompanionHint();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/RowTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing NUnit.Framework;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests;\n\n[TestFixture]\npublic class RowTests\n{\n    #region Spacing\n    \n    [TestCase(float.MinValue)]\n    [TestCase(-5)]\n    [TestCase(-float.Epsilon)]\n    public void NegativeSpacingThrowsException(float spacingValue)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer\n                .Create()\n                .Row(row =>\n                {\n                    row.Spacing(spacingValue);\n                });\n        });\n        \n        Assert.That(exception.Message, Is.EqualTo(\"The row spacing cannot be negative. (Parameter 'spacing')\"));\n    }\n    \n    [TestCase(0)]\n    [TestCase(float.Epsilon)]\n    [TestCase(10)]\n    public void ValidSpacingIsCorrectlyApplied(float spacingValue)\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Row(row =>\n        {\n            row.Spacing(spacingValue);\n        });\n        \n        var rowContainer = container.Child as Row;\n        Assert.That(rowContainer?.Spacing, Is.EqualTo(spacingValue));\n    }\n    \n    [Test]\n    public void SpacingSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Row(row =>\n        {\n            row.Spacing(5, Unit.Inch);\n        });\n        \n        var rowContainer = container.Child as Row;\n        Assert.That(rowContainer?.Spacing, Is.EqualTo(360));\n    }\n    \n    #endregion\n    \n    #region Relative Item\n    \n    [TestCase(-10)]\n    [TestCase(-float.Epsilon)]\n    [TestCase(0)]\n    public void RelativeItemCannotHaveSizeSmallerOrEqualToZero(float size)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer\n                .Create()\n                .Row(row =>\n                {\n                    row.RelativeItem(size);\n                });\n        });\n\n        Assert.That(exception?.Message, Is.EqualTo(\"The relative item size must be greater than zero. (Parameter 'size')\"));\n    }\n    \n    [TestCase(float.Epsilon)]\n    [TestCase(1)]\n    [TestCase(5)]\n    public void RelativeItemMustHaveSizeLargerThanZero(float size)\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Row(row =>\n        {\n            row.RelativeItem(size);\n        });\n        \n        var rowContainer = container.Child as Row;\n        Assert.That(rowContainer?.Items.Count, Is.EqualTo(1));\n        \n        var firstItem = rowContainer?.Items.Single();\n        Assert.That(firstItem.Type, Is.EqualTo(RowItemType.Relative));\n        Assert.That(firstItem.Size, Is.EqualTo(size));\n    }\n    \n    #endregion\n    \n    #region Constant Item\n    \n    [TestCase(-10)]\n    [TestCase(-float.Epsilon)]\n    public void ConstantItemCannotHaveSizeSmallerThanZero(float size)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer\n                .Create()\n                .Row(row =>\n                {\n                    row.ConstantItem(size);\n                });\n        });\n\n        Assert.That(exception?.Message, Is.EqualTo(\"The constant item size cannot be negative. (Parameter 'size')\"));\n    }\n    \n    [TestCase(0)]\n    [TestCase(100)]\n    public void ConstantItemMustHaveSizeLargerOrEqualToZero(float size)\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Row(row =>\n        {\n            row.ConstantItem(size);\n        });\n        \n        var rowContainer = container.Child as Row;\n        Assert.That(rowContainer?.Items.Count, Is.EqualTo(1));\n        \n        var firstItem = rowContainer?.Items.Single();\n        Assert.That(firstItem.Type, Is.EqualTo(RowItemType.Constant));\n        Assert.That(firstItem.Size, Is.EqualTo(size));\n    }\n    \n    [Test]\n    public void ConstantItemSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Row(row =>\n        {\n            row.ConstantItem(2, Unit.Inch);\n        });\n        \n        var rowContainer = container.Child as Row;\n        Assert.That(rowContainer?.Items.Count, Is.EqualTo(1));\n        \n        var firstItem = rowContainer?.Items.Single();\n        Assert.That(firstItem.Type, Is.EqualTo(RowItemType.Constant));\n        Assert.That(firstItem.Size, Is.EqualTo(144));\n    }\n    \n    #endregion\n    \n    [Test]\n    public void CompanionHints()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Row(row =>\n        {\n            row.RelativeItem(3);\n            row.ConstantItem(2, Unit.Inch);\n            row.AutoItem();\n        });\n        \n        var rowContainer = container.Child as Row;\n        Assert.That(rowContainer?.Items.Count, Is.EqualTo(3));\n        \n        var items = rowContainer?.Items;\n        \n        Assert.That(items[0].GetCompanionHint(), Is.EqualTo(\"Relative 3\"));\n        Assert.That(items[1].GetCompanionHint(), Is.EqualTo(\"Constant 144\"));\n        Assert.That(items[2].GetCompanionHint(), Is.EqualTo(\"Auto\"));\n    }\n    \n    [Test]\n    [Repeat(10)]\n    public void RowSupportsStatefulOperations()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Row(row =>\n        {\n            foreach (var i in Enumerable.Range(0, 10))\n                row.RelativeItem();\n        });\n        \n        var rowContainer = container.Child as Row;\n        Assert.That(rowContainer?.Items.Count, Is.EqualTo(10));\n        \n        rowContainer.ResetState();\n        Assert.That(rowContainer.GetState(), Is.EquivalentTo(new bool[10]));\n        \n        var newState = Enumerable\n            .Range(0, 10)\n            .Select(x => Random.Shared.Next() % 2 == 0)\n            .ToArray();\n        \n        rowContainer.SetState(newState);\n        Assert.That(rowContainer.GetState(), Is.EquivalentTo(newState));\n        \n        rowContainer.ResetState();\n        Assert.That(rowContainer.GetState(), Is.EquivalentTo(new bool[10]));\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/ScaleTests.cs",
    "content": "﻿using System;\nusing NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class ScaleTests\n    {\n        [TestCase(2, 2, ExpectedResult = \"A=2\")]\n        [TestCase(-3, -3, ExpectedResult = \"A=-3\")]\n        [TestCase(4, 1, ExpectedResult = \"H=4\")]\n        [TestCase(1, -2, ExpectedResult = \"V=-2\")]\n        [TestCase(4, 5, ExpectedResult = \"H=4   V=5\")]\n        [TestCase(1.2345f, -2.3456f, ExpectedResult = \"H=1.2   V=-2.3\")]\n        public string CompanionHint(float horizontal, float vertical)\n        {\n            var container = EmptyContainer.Create();\n\n            container.ScaleHorizontal(horizontal).ScaleVertical(vertical);\n            \n            var translationElement = container.Child as Scale;\n            return translationElement?.GetCompanionHint();\n        }     \n        \n        #region Cumulative Property\n        \n        [Test]\n        public void HorizontalScaleIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.ScaleHorizontal(3).ScaleHorizontal(0.5f).ScaleHorizontal(-4);\n        \n            var rowContainer = container.Child as Scale;\n            Assert.That(rowContainer?.ScaleX, Is.EqualTo(-6));\n            Assert.That(rowContainer?.ScaleY, Is.EqualTo(1));\n        }\n        \n        [Test]\n        public void VerticalScaleIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.ScaleVertical(2).ScaleVertical(-0.25f).ScaleVertical(-3f);\n        \n            var rowContainer = container.Child as Scale;\n            Assert.That(rowContainer?.ScaleX, Is.EqualTo(1));\n            Assert.That(rowContainer?.ScaleY, Is.EqualTo(1.5f));\n        }\n        \n        [Test]\n        public void ScaleIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.ScaleHorizontal(-5f).ScaleVertical(3).Scale(-0.25f);\n        \n            var rowContainer = container.Child as Scale;\n            Assert.That(rowContainer?.ScaleX, Is.EqualTo(1.25f));\n            Assert.That(rowContainer?.ScaleY, Is.EqualTo(-0.75f));\n        }\n        \n        #endregion\n        \n        #region Flip\n        \n        [Test]\n        public void FlipHorizontalAppliesCorrectScale()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.FlipHorizontal();\n        \n            var rowContainer = container.Child as Scale;\n            Assert.That(rowContainer?.ScaleX, Is.EqualTo(-1));\n            Assert.That(rowContainer?.ScaleY, Is.EqualTo(1));\n        }\n        \n        [Test]\n        public void FlipVerticalAppliesCorrectScale()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.FlipVertical();\n        \n            var rowContainer = container.Child as Scale;\n            Assert.That(rowContainer?.ScaleX, Is.EqualTo(1));\n            Assert.That(rowContainer?.ScaleY, Is.EqualTo(-1));\n        }\n        \n        [Test]\n        public void FlipOverAppliesCorrectScale()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.FlipOver();\n        \n            var rowContainer = container.Child as Scale;\n            Assert.That(rowContainer?.ScaleX, Is.EqualTo(-1));\n            Assert.That(rowContainer?.ScaleY, Is.EqualTo(-1));\n        }\n        \n        #endregion\n\n        #region Zero Scale Validation\n\n        [Test]\n        public void ScaleCannotBeZero()\n        {\n            var exception = Assert.Throws<ArgumentException>(() =>\n            {\n                EmptyContainer.Create().Scale(0);\n            });\n            \n            Assert.That(exception.Message, Is.EqualTo(\"Vertical scale factor cannot be zero. (Parameter 'factor')\"));\n        }\n        \n        [Test]\n        public void VerticalScaleCannotBeZero()\n        {\n            var exception = Assert.Throws<ArgumentException>(() =>\n            {\n                EmptyContainer.Create().ScaleVertical(0);\n            });\n            \n            Assert.That(exception.Message, Is.EqualTo(\"Vertical scale factor cannot be zero. (Parameter 'factor')\"));\n        }\n        \n        [Test]\n        public void HorizontalScaleCannotBeZero()\n        {\n            var exception = Assert.Throws<ArgumentException>(() =>\n            {\n                EmptyContainer.Create().ScaleHorizontal(0);\n            });\n            \n            Assert.That(exception.Message, Is.EqualTo(\"Vertical scale factor cannot be zero. (Parameter 'factor')\"));\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/ShowEntireTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class ShowEntireTests\n    {\n        [Test]\n        public void Measure_ReturnsWrap_WhenElementReturnsWrap()\n        {\n            TestPlan\n                .For(x => new ShowEntire\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(new Size(400, 300), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Child element does not fit (even partially) on the page.\"));\n        }\n        \n        [Test]\n        public void Measure_ReturnsWrap_WhenElementReturnsPartialRender()\n        {\n            TestPlan\n                .For(x => new ShowEntire\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(new Size(400, 300), SpacePlan.PartialRender(300, 200))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Child element fits only partially on the page.\"));\n        }\n        \n        [Test]\n        public void Measure_ReturnsFullRender_WhenElementReturnsFullRender()\n        {\n            TestPlan\n                .For(x => new ShowEntire\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(new Size(400, 300), SpacePlan.FullRender(300, 200))\n                .CheckMeasureResult(SpacePlan.FullRender(300, 200));\n        }\n        \n        [Test]\n        public void Draw() => SimpleContainerTests.Draw<ShowEntire>();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/ShowOnceTest.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class ShowOnceTest\n    {\n        [Test]\n        public void Draw()\n        {\n            TestPlan\n                .For(x => new ShowOnce()\n                {\n                    Child = x.CreateChild()\n                })\n                \n                // Measure the element and return result\n                .MeasureElement(new Size(300, 200))\n                .ExpectChildMeasure(\"child\", new Size(300, 200), SpacePlan.PartialRender(new Size(200, 200)))\n                .CheckMeasureResult(SpacePlan.PartialRender(new Size(200, 200)))\n                \n                // Draw element partially\n                .DrawElement(new Size(200, 200))\n                .ExpectChildMeasure(new Size(200, 200), SpacePlan.PartialRender(new Size(200, 200)))\n                .ExpectChildDraw(new Size(200, 200))\n                .CheckDrawResult()\n                \n                // Element was not fully drawn\n                // It should be measured again for rendering on next page\n                .MeasureElement(new Size(800, 200))\n                .ExpectChildMeasure(new Size(800, 200), SpacePlan.FullRender(new Size(400, 200)))\n                .CheckMeasureResult(SpacePlan.FullRender(new Size(400, 200)))\n\n                // Draw element on next page\n                // Element was fully drawn at this point\n                .DrawElement(new Size(400, 200))\n                .ExpectChildMeasure(new Size(400, 200), SpacePlan.FullRender(new Size(400, 200)))\n                .ExpectChildDraw(new Size(400, 200))\n                .CheckDrawResult()\n                \n                // In the next attempt of measuring element, it should behave like empty parent.\n                .MeasureElement(new Size(600, 200))\n                .CheckMeasureResult(SpacePlan.Empty())\n                \n                // In the next attempt of measuring element, it should not draw its child\n                .DrawElement(new Size(600, 200))\n                .CheckDrawResult();\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/SimpleRotateTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class SimpleRotateTests\n    {\n        #region Cumulative rotation\n        \n        [Test]\n        public void RotateRightIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n            container\n                .RotateRight()\n                .RotateRight()\n                .RotateRight()\n                .RotateRight()\n                .RotateRight();\n        \n            var rotation = container.Child as SimpleRotate;\n            Assert.That(rotation?.TurnCount, Is.EqualTo(5));\n        }\n        \n        [Test]\n        public void RotateLeftIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n            container\n                .RotateLeft()\n                .RotateLeft()\n                .RotateLeft()\n                .RotateLeft()\n                .RotateLeft()\n                .RotateLeft();\n        \n            var rotation = container.Child as SimpleRotate;\n            Assert.That(rotation?.TurnCount, Is.EqualTo(-6));\n        }\n        \n        [Test]\n        public void RotateRightAndLeftCanBeCombined()\n        {\n            var container = EmptyContainer.Create();\n            container\n                .RotateRight()\n                .RotateRight()\n                .RotateRight()\n                .RotateRight()\n                .RotateLeft()\n                .RotateLeft()\n                .RotateLeft();\n        \n            var rotation = container.Child as SimpleRotate;\n            Assert.That(rotation?.TurnCount, Is.EqualTo(1));\n        }\n        \n        #endregion\n        \n        #region Companion Hint\n        \n        [Test]\n        public void NoRotationCompanionHint()\n        {\n            var container = EmptyContainer.Create();\n            container.RotateRight().RotateLeft();\n        \n            var rotation = container.Child as SimpleRotate;\n            Assert.That(rotation?.GetCompanionHint(), Is.EqualTo(\"No rotation\"));\n        }\n        \n        [Test]\n        public void RotateRightCompanionHint()\n        {\n            var container = EmptyContainer.Create();\n            container.RotateRight();\n        \n            var rotation = container.Child as SimpleRotate;\n            Assert.That(rotation?.GetCompanionHint(), Is.EqualTo(\"90 deg clockwise\"));\n        }\n        \n        [Test]\n        public void DoubleRotateLeftCompanionHint()\n        {\n            var container = EmptyContainer.Create();\n            container.RotateLeft().RotateLeft();\n        \n            var rotation = container.Child as SimpleRotate;\n            Assert.That(rotation?.GetCompanionHint(), Is.EqualTo(\"180 deg counter-clockwise\"));\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/StyledBoxTests.cs",
    "content": "using System;\nusing NUnit.Framework;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests;\n\npublic class StyledBoxTests\n{\n    [Test]\n    public void BorderShorthandSetsCorrectValues()\n    {\n        var container = EmptyContainer.Create();\n\n        container.Border(1.23f, Colors.Amber.Darken2);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.EqualTo(1.23f));\n        Assert.That(styledBox?.BorderRight, Is.EqualTo(1.23f));\n        Assert.That(styledBox?.BorderTop, Is.EqualTo(1.23f));\n        Assert.That(styledBox?.BorderBottom, Is.EqualTo(1.23f));\n        \n        Assert.That(styledBox?.BorderColor, Is.EqualTo(Colors.Amber.Darken2));\n        Assert.That(styledBox?.BackgroundColor, Is.EqualTo(Colors.Transparent));\n        \n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.Zero);\n    }\n    \n    #region Background\n\n    [Test]\n    public void BackgroundColorSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n\n        container.Background(Colors.Green.Medium);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BackgroundColor, Is.EqualTo(Colors.Green.Medium));\n    }\n    \n    [Test]\n    public void BackgroundLinearGradientCannotBeEmpty()\n    {\n        var exception = Assert.Throws<ArgumentException>(() =>\n        {\n            EmptyContainer.Create().BackgroundLinearGradient(123f, []);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The background linear-gradient colors cannot be empty. (Parameter 'colors')\"));\n    }\n    \n    [Test]\n    public void BackgroundLinearGradientSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n\n        container.BackgroundLinearGradient(30f, [ Colors.Red.Lighten3, Colors.Orange.Lighten3, Colors.Yellow.Lighten3 ]);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BackgroundGradientAngle, Is.EqualTo(30));\n        Assert.That(styledBox?.BackgroundGradientColors, Is.EqualTo([ Colors.Red.Lighten3, Colors.Orange.Lighten3, Colors.Yellow.Lighten3 ]));\n    }\n\n    #endregion\n    \n    #region Thickness\n    \n    [Test] \n    public void BorderAllSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Border(1.23f);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.EqualTo(1.23f));\n        Assert.That(styledBox?.BorderRight, Is.EqualTo(1.23f));\n        Assert.That(styledBox?.BorderTop, Is.EqualTo(1.23f));\n        Assert.That(styledBox?.BorderBottom, Is.EqualTo(1.23f));\n    }\n    \n    [Test] \n    public void BorderAllSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Border(0.25f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.EqualTo(18));\n        Assert.That(styledBox?.BorderRight, Is.EqualTo(18));\n        Assert.That(styledBox?.BorderTop, Is.EqualTo(18));\n        Assert.That(styledBox?.BorderBottom, Is.EqualTo(18));\n    }\n    \n    [Test] \n    public void BorderVerticalSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderVertical(20);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.EqualTo(20));\n        Assert.That(styledBox?.BorderRight, Is.EqualTo(20));\n        Assert.That(styledBox?.BorderTop, Is.Zero);\n        Assert.That(styledBox?.BorderBottom, Is.Zero);\n    }\n    \n    [Test] \n    public void BorderVerticalSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderVertical(0.5f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.EqualTo(36));\n        Assert.That(styledBox?.BorderRight, Is.EqualTo(36));\n        Assert.That(styledBox?.BorderTop, Is.Zero);\n        Assert.That(styledBox?.BorderBottom, Is.Zero);\n    }\n    \n    [Test] \n    public void BorderHorizontalSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderHorizontal(25);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRight, Is.Zero);\n        Assert.That(styledBox?.BorderTop, Is.EqualTo(25));\n        Assert.That(styledBox?.BorderBottom, Is.EqualTo(25));\n    }\n    \n    [Test] \n    public void BorderHorizontalSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderHorizontal(0.75f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRight, Is.Zero);\n        Assert.That(styledBox?.BorderTop, Is.EqualTo(54));\n        Assert.That(styledBox?.BorderBottom, Is.EqualTo(54));\n    }\n    \n    [Test]\n    public void BorderLeftSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderLeft(5);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.EqualTo(5));\n        Assert.That(styledBox?.BorderRight, Is.Zero);\n        Assert.That(styledBox?.BorderTop, Is.Zero);\n        Assert.That(styledBox?.BorderBottom, Is.Zero);\n    }\n    \n    [Test]\n    public void BorderLeftSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderLeft(0.25f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.EqualTo(18));\n        Assert.That(styledBox?.BorderRight, Is.Zero);\n        Assert.That(styledBox?.BorderTop, Is.Zero);\n        Assert.That(styledBox?.BorderBottom, Is.Zero);\n    }\n    \n    [TestCase(-5)]\n    [TestCase(-Size.Epsilon)]\n    public void BorderLeftCannotBeNegative(float border)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer.Create().BorderLeft(border);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The left border cannot be negative.\"));\n    }\n    \n    [Test]\n    public void BorderRightSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderRight(10);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRight, Is.EqualTo(10));\n        Assert.That(styledBox?.BorderTop, Is.Zero);\n        Assert.That(styledBox?.BorderBottom, Is.Zero);\n    }\n    \n    [Test]\n    public void BorderRightSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderRight(0.5f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRight, Is.EqualTo(36));\n        Assert.That(styledBox?.BorderTop, Is.Zero);\n        Assert.That(styledBox?.BorderBottom, Is.Zero);\n    }\n    \n    [TestCase(-5)]\n    [TestCase(-Size.Epsilon)]\n    public void BorderRightCannotBeNegative(float border)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer.Create().BorderRight(border);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The right border cannot be negative.\"));\n    }\n    \n    [Test]\n    public void BorderTopSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderTop(15);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRight, Is.Zero);\n        Assert.That(styledBox?.BorderTop, Is.EqualTo(15));\n        Assert.That(styledBox?.BorderBottom, Is.Zero);\n    }\n    \n    [Test]\n    public void BorderTopSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderTop(0.75f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRight, Is.Zero);\n        Assert.That(styledBox?.BorderTop, Is.EqualTo(54f));\n        Assert.That(styledBox?.BorderBottom, Is.Zero);\n    }\n    \n    [TestCase(-5)]\n    [TestCase(-Size.Epsilon)]\n    public void BorderTopCannotBeNegative(float border)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer.Create().BorderTop(border);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The top border cannot be negative.\"));\n    }\n    \n    [Test]\n    public void BorderBottomSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderBottom(20);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRight, Is.Zero);\n        Assert.That(styledBox?.BorderTop, Is.Zero);\n        Assert.That(styledBox?.BorderBottom, Is.EqualTo(20));\n    }\n    \n    [Test]\n    public void BorderBottomSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.BorderBottom(1f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRight, Is.Zero);\n        Assert.That(styledBox?.BorderTop, Is.Zero);\n        Assert.That(styledBox?.BorderBottom, Is.EqualTo(72f));\n    }\n    \n    [TestCase(-5)]\n    [TestCase(-Size.Epsilon)]\n    public void BorderBottomCannotBeNegative(float border)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer.Create().BorderBottom(border);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The bottom border cannot be negative.\"));\n    }\n    \n    [Test]\n    public void ZeroBorderIsSupported()\n    {\n        var container = EmptyContainer.Create();\n\n        container\n            .BorderLeft(0)\n            .BorderRight(0)\n            .BorderTop(0)\n            .BorderBottom(0);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRight, Is.Zero);\n        Assert.That(styledBox?.BorderTop, Is.Zero);\n        Assert.That(styledBox?.BorderBottom, Is.Zero);\n    }\n    \n    [Test]\n    public void BorderValuesAreOverridingEachOther()\n    {\n        var container = EmptyContainer.Create();\n\n        container\n            .Border(5)\n            .BorderVertical(10)\n            .BorderLeft(15)\n            .BorderBottom(20);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderLeft, Is.EqualTo(15));\n        Assert.That(styledBox?.BorderRight, Is.EqualTo(10));\n        Assert.That(styledBox?.BorderTop, Is.EqualTo(5));\n        Assert.That(styledBox?.BorderBottom, Is.EqualTo(20));\n    }\n    \n    [Test]\n    public void BorderSetsColorToBlack()\n    {\n        var container = EmptyContainer.Create();\n\n        container.Border(5);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderColor, Is.EqualTo(Colors.Black));\n    }\n    \n    #endregion\n\n    #region Corner Radius\n\n    [Test] \n    public void CornerRadiusAllSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadius(8);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.EqualTo(8));\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.EqualTo(8));\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.EqualTo(8));\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.EqualTo(8));\n    }\n    \n    [Test] \n    public void CornerRadiusAllSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadius(1.5f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.EqualTo(108));\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.EqualTo(108));\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.EqualTo(108));\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.EqualTo(108));\n    }\n\n    [TestCase(-5)]\n    [TestCase(-Size.Epsilon)]\n    public void CornerRadiusAllCannotBeNegative(float cornerRadius)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer.Create().CornerRadius(cornerRadius);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The top-left corner radius cannot be negative.\"));\n    }\n    \n    [Test] \n    public void CornerRadiusTopLeftSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadiusTopLeft(8);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.EqualTo(8));\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.Zero);\n    }\n    \n    [Test] \n    public void CornerRadiusTopLeftSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadiusTopLeft(0.25f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.EqualTo(18));\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.Zero);\n    }\n\n    [TestCase(-5)]\n    [TestCase(-Size.Epsilon)]\n    public void CornerRadiusTopLeftCannotBeNegative(float cornerRadius)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer.Create().CornerRadiusTopLeft(cornerRadius);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The top-left corner radius cannot be negative.\"));\n    }\n    \n    [Test] \n    public void CornerRadiusTopRightSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadiusTopRight(10);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.EqualTo(10));\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.Zero);\n    }\n    \n    [Test] \n    public void CornerRadiusTopRightSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadiusTopRight(0.5f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.EqualTo(36));\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.Zero);\n    }\n\n    [TestCase(-5)]\n    [TestCase(-Size.Epsilon)]\n    public void CornerRadiusTopRightCannotBeNegative(float cornerRadius)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer.Create().CornerRadiusTopRight(cornerRadius);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The top-right corner radius cannot be negative.\"));\n    }\n    \n    [Test] \n    public void CornerRadiusBottomLeftSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadiusBottomLeft(12);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.EqualTo(12));\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.Zero);\n    }\n    \n    [Test] \n    public void CornerRadiusBottomLeftSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadiusBottomLeft(0.75f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.EqualTo(54));\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.Zero);\n    }\n\n    [TestCase(-5)]\n    [TestCase(-Size.Epsilon)]\n    public void CornerRadiusBottomLeftCannotBeNegative(float cornerRadius)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer.Create().CornerRadiusBottomLeft(cornerRadius);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The bottom-left corner radius cannot be negative.\"));\n    }\n    \n    [Test] \n    public void CornerRadiusBottomRightSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadiusBottomRight(14);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.EqualTo(14));\n    }\n    \n    [Test] \n    public void CornerRadiusBottomRightSupportsUnitConversion()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.CornerRadiusBottomRight(1f, Unit.Inch);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.Zero);\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.EqualTo(72));\n    }\n\n    [TestCase(-5)]\n    [TestCase(-Size.Epsilon)]\n    public void CornerRadiusBottomRightCannotBeNegative(float cornerRadius)\n    {\n        var exception = Assert.Throws<ArgumentOutOfRangeException>(() =>\n        {\n            EmptyContainer.Create().CornerRadiusBottomRight(cornerRadius);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The bottom-right corner radius cannot be negative.\"));\n    }\n    \n    [Test]\n    public void CornerRadiusValuesAreOverridingEachOther()\n    {\n        var container = EmptyContainer.Create();\n\n        container\n            .CornerRadius(4)\n            .CornerRadiusTopLeft(6)\n            .CornerRadiusTopRight(8)\n            .CornerRadiusBottomLeft(10)\n            .CornerRadiusBottomRight(12)\n            .CornerRadiusBottomRight(14);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderRadiusTopLeft, Is.EqualTo(6));\n        Assert.That(styledBox?.BorderRadiusTopRight, Is.EqualTo(8));\n        Assert.That(styledBox?.BorderRadiusBottomLeft, Is.EqualTo(10));\n        Assert.That(styledBox?.BorderRadiusBottomRight, Is.EqualTo(14));\n    }\n    \n    #endregion\n\n    #region Border Style\n    \n    [Test]\n    public void BorderColorSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n\n        container.BorderColor(Colors.Red.Darken3);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderColor, Is.EqualTo(Colors.Red.Darken3));\n    }\n    \n    [Test]\n    public void BorderLinearGradientCannotBeEmpty()\n    {\n        var exception = Assert.Throws<ArgumentException>(() =>\n        {\n            EmptyContainer.Create().BorderLinearGradient(234f, []);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The border linear-gradient colors cannot be empty. (Parameter 'colors')\"));\n    }\n    \n    [Test]\n    public void BorderLinearGradientSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n\n        container.BorderLinearGradient(123f, [ Colors.Red.Darken3, Colors.Orange.Darken3, Colors.Yellow.Darken3 ]);\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderGradientAngle, Is.EqualTo(123));\n        Assert.That(styledBox?.BorderGradientColors, Is.EqualTo([ Colors.Red.Darken3, Colors.Orange.Darken3, Colors.Yellow.Darken3 ]));\n    }\n    \n    #endregion\n    \n    #region Border Alignment\n    \n    [Test]\n    public void BorderAlignmentIsMiddleWhenNoRoundedCorners()\n    {\n        var container = EmptyContainer.Create();\n        container.Border(5);\n        \n        var styledBox = container.Child as StyledBox;\n        styledBox.AdjustBorderAlignment();\n        Assert.That(styledBox?.BorderAlignment, Is.EqualTo(0.5f));\n    }\n    \n    [Test]\n    public void BorderAlignmentIsInsideWhenHasRoundedCorners()\n    {\n        var container = EmptyContainer.Create();\n        container.Border(5).CornerRadius(10);\n        \n        var styledBox = container.Child as StyledBox;\n        styledBox.AdjustBorderAlignment();\n        Assert.That(styledBox?.BorderAlignment, Is.EqualTo(0f));\n    }\n    \n    [Test]\n    public void BorderAlignmentInsideSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        container.BorderAlignmentInside();\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderAlignment, Is.Zero);\n    }\n    \n    [Test]\n    public void BorderAlignmentMiddleSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        container.BorderAlignmentMiddle();\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderAlignment, Is.EqualTo(0.5f));\n    }\n    \n    [Test]\n    public void BorderAlignmentOutsideSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        container.BorderAlignmentOutside();\n        \n        var styledBox = container.Child as StyledBox;\n        Assert.That(styledBox?.BorderAlignment, Is.EqualTo(1f));\n    }\n    \n    #endregion\n    \n    #region Shadow\n    \n    [Test]\n    public void ShadowStyleSetsCorrectValue()\n    {\n        var container = EmptyContainer.Create();\n        \n        container.Shadow(new BoxShadowStyle\n        {\n            Color = Colors.Black.WithAlpha(0.5f),\n            OffsetX = 5,\n            OffsetY = 10,\n            Blur = 15,\n            Spread = 20\n        });\n        \n        var styledBox = container.Child as StyledBox;\n        var shadow = styledBox?.Shadow;\n        \n        Assert.That(shadow.Color, Is.EqualTo(new Color(0x7F000000)));\n        Assert.That(shadow.OffsetX, Is.EqualTo(5));\n        Assert.That(shadow.OffsetY, Is.EqualTo(10));\n        Assert.That(shadow.Blur, Is.EqualTo(15));\n        Assert.That(shadow.Spread, Is.EqualTo(20));\n    }\n    \n    [Test]\n    public void ShadowStyleCannotBeNull()\n    {\n        var exception = Assert.Throws<ArgumentNullException>(() =>\n        {\n            EmptyContainer.Create().Shadow(null);\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"The box shadow style cannot be null.\"));\n    }\n    \n    [TestCase(-10)]\n    [TestCase(-Size.Epsilon)]\n    public void ShadowBlurCannotBeNegative(float blur)\n    {\n        var exception = Assert.Throws<ArgumentException>(() =>\n        {\n            EmptyContainer.Create().Shadow(new BoxShadowStyle { Blur = blur });\n        });\n        \n        Assert.That(exception.Message, Does.Contain(\"Shadow blur radius cannot be negative.\"));\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/ElementMock.cs",
    "content": "﻿using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests.TestEngine\n{\n    internal sealed class ElementMock : Element\n    {\n        public string Id { get; set; }\n        public Func<Size, SpacePlan> MeasureFunc { get; set; }\n        public Action<Size> DrawFunc { get; set; }\n\n        internal override SpacePlan Measure(Size availableSpace) => MeasureFunc(availableSpace);\n        internal override void Draw(Size availableSpace) => DrawFunc(availableSpace);\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/MockCanvas.cs",
    "content": "﻿using System;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\nusing SkiaSharp;\n\nnamespace QuestPDF.UnitTests.TestEngine\n{\n    internal sealed class MockCanvas : IDrawingCanvas\n    {\n        public Action<Position> TranslateFunc { get; set; }\n        public Action<float> RotateFunc { get; set; }\n        public Action<float, float> ScaleFunc { get; set; }\n        public Action<SkImage, Position, Size> DrawImageFunc { get; set; }\n        public Action<Position, Size, Color> DrawRectFunc { get; set; }\n\n        public DocumentPageSnapshot GetSnapshot() => throw new NotImplementedException();\n        public void DrawSnapshot(DocumentPageSnapshot snapshot) => throw new NotImplementedException();\n\n        public void Save() => throw new NotImplementedException();\n        public void Restore() => throw new NotImplementedException();\n        \n        public void SetZIndex(int index) => throw new NotImplementedException();\n        public int GetZIndex() => throw new NotImplementedException();\n        \n        public SkCanvasMatrix GetCurrentMatrix() => throw new NotImplementedException();\n        public void SetMatrix(SkCanvasMatrix matrix) => throw new NotImplementedException();\n\n        public void Translate(Position vector) => TranslateFunc(vector);\n        public void Scale(float scaleX, float scaleY) => ScaleFunc(scaleX, scaleY);\n        public void Rotate(float angle) => RotateFunc(angle);\n\n        public void DrawLine(Position start, Position end, SkPaint paint) => throw new NotImplementedException();\n        public void DrawRectangle(Position vector, Size size, SkPaint paint) => throw new NotImplementedException();\n        public void DrawComplexBorder(SkRoundedRect innerRect, SkRoundedRect outerRect, SkPaint paint) => throw new NotImplementedException();\n        public void DrawShadow(SkRoundedRect shadowRect, SkBoxShadow shadow) => throw new NotImplementedException();\n        public void DrawParagraph(SkParagraph paragraph, int lineFrom, int lineTo) => throw new NotImplementedException();\n        public void DrawImage(SkImage image, Size size) => DrawImageFunc(image, Position.Zero, size);\n        public void DrawPicture(SkPicture picture) => throw new NotImplementedException();\n        public void DrawSvgPath(string path, Color color) => throw new NotImplementedException();\n        public void DrawSvg(SkSvgImage svgImage, Size size) => throw new NotImplementedException();\n        \n        public void DrawOverflowArea(SkRect area) => throw new NotImplementedException();\n        public void ClipOverflowArea(SkRect availableSpace, SkRect requiredSpace) => throw new NotImplementedException();\n        public void ClipRectangle(SkRect clipArea) => throw new NotImplementedException();\n        public void ClipRoundedRectangle(SkRoundedRect clipArea) => throw new NotImplementedException();\n        \n        public void DrawHyperlink(Size size, string url, string? description) => throw new NotImplementedException();\n        public void DrawSectionLink(Size size, string sectionName, string? description) => throw new NotImplementedException();\n        public void DrawSection(string sectionName) => throw new NotImplementedException();\n        \n        public int GetSemanticNodeId() => throw new NotImplementedException();\n        public void SetSemanticNodeId(int nodeId) => throw new NotImplementedException();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/OperationBase.cs",
    "content": "﻿namespace QuestPDF.UnitTests.TestEngine\n{\n    public abstract class OperationBase\n    {\n        \n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/OperationRecordingCanvas.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia;\nusing QuestPDF.Skia.Text;\nusing QuestPDF.UnitTests.TestEngine.Operations;\n\nnamespace QuestPDF.UnitTests.TestEngine\n{\n    internal sealed class OperationRecordingCanvas : IDrawingCanvas\n    {\n        public ICollection<OperationBase> Operations { get; } = new List<OperationBase>();\n        \n        public DocumentPageSnapshot GetSnapshot() => throw new NotImplementedException();\n        public void DrawSnapshot(DocumentPageSnapshot snapshot) => throw new NotImplementedException();\n        \n        public void Save() => throw new NotImplementedException();\n        public void Restore() => throw new NotImplementedException();\n        \n        public void SetZIndex(int index) => throw new NotImplementedException();\n        public int GetZIndex() => throw new NotImplementedException();\n        \n        public SkCanvasMatrix GetCurrentMatrix() => throw new NotImplementedException();\n        public void SetMatrix(SkCanvasMatrix matrix) => throw new NotImplementedException();\n\n        public void Translate(Position vector) => Operations.Add(new CanvasTranslateOperation(vector));\n        public void Scale(float scaleX, float scaleY) => Operations.Add(new CanvasScaleOperation(scaleX, scaleY));\n        public void Rotate(float angle) => Operations.Add(new CanvasRotateOperation(angle));\n\n        public void DrawLine(Position start, Position end, SkPaint paint) => throw new NotImplementedException();\n        public void DrawRectangle(Position vector, Size size, SkPaint paint) => throw new NotImplementedException();\n        public void DrawComplexBorder(SkRoundedRect innerRect, SkRoundedRect outerRect, SkPaint paint) => throw new NotImplementedException();\n        public void DrawShadow(SkRoundedRect shadowRect, SkBoxShadow shadow) => throw new NotImplementedException();\n        public void DrawParagraph(SkParagraph paragraph, int lineFrom, int lineTo) => throw new NotImplementedException();\n        public void DrawImage(SkImage image, Size size) => Operations.Add(new CanvasDrawImageOperation(Position.Zero, size));\n        public void DrawPicture(SkPicture picture) => throw new NotImplementedException();\n        public void DrawSvgPath(string path, Color color) => throw new NotImplementedException();\n        public void DrawSvg(SkSvgImage svgImage, Size size) => throw new NotImplementedException();\n        \n        public void DrawOverflowArea(SkRect area) => throw new NotImplementedException();\n        public void ClipOverflowArea(SkRect availableSpace, SkRect requiredSpace) => throw new NotImplementedException();\n        public void ClipRectangle(SkRect clipArea) => throw new NotImplementedException();\n        public void ClipRoundedRectangle(SkRoundedRect clipArea) => throw new NotImplementedException();\n        \n        public void DrawHyperlink(Size size, string url, string? description) => throw new NotImplementedException();\n        public void DrawSectionLink(Size size, string sectionName, string? description) => throw new NotImplementedException();\n        public void DrawSection(string sectionName) => throw new NotImplementedException();\n        \n        public int GetSemanticNodeId() => throw new NotImplementedException();\n        public void SetSemanticNodeId(int nodeId) => throw new NotImplementedException();\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/Operations/CanvasDrawImageOperation.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests.TestEngine.Operations\n{\n    internal sealed class CanvasDrawImageOperation : OperationBase\n    {\n        public Position Position { get; }\n        public Size Size { get; }\n\n        public CanvasDrawImageOperation(Position position, Size size)\n        {\n            Position = position;\n            Size = size;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/Operations/CanvasDrawRectangleOperation.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests.TestEngine.Operations\n{\n    internal sealed class CanvasDrawRectangleOperation : OperationBase\n    {\n        public Position Position { get; } \n        public Size Size { get; }\n        public Color Color { get; }\n\n        public CanvasDrawRectangleOperation(Position position, Size size, Color color)\n        {\n            Position = position;\n            Size = size;\n            Color = color;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/Operations/CanvasDrawTextOperation.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests.TestEngine.Operations\n{\n    internal sealed class CanvasDrawTextOperation : OperationBase\n    {\n        public string Text { get; }\n        public Position Position { get; }\n        public TextStyle Style { get; }\n\n        public CanvasDrawTextOperation(string text, Position position, TextStyle style)\n        {\n            Text = text;\n            Position = position;\n            Style = style;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/Operations/CanvasRotateOperation.cs",
    "content": "﻿namespace QuestPDF.UnitTests.TestEngine.Operations\n{\n    public class CanvasRotateOperation : OperationBase\n    {\n        public float Angle { get; }\n\n        public CanvasRotateOperation(float angle)\n        {\n            Angle = angle;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/Operations/CanvasScaleOperation.cs",
    "content": "﻿namespace QuestPDF.UnitTests.TestEngine.Operations\n{\n    public class CanvasScaleOperation : OperationBase\n    {\n        public float ScaleX { get; }\n        public float ScaleY { get; }\n\n        public CanvasScaleOperation(float scaleX, float scaleY)\n        {\n            ScaleX = scaleX;\n            ScaleY = scaleY;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/Operations/CanvasTranslateOperation.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests.TestEngine.Operations\n{\n    internal sealed class CanvasTranslateOperation : OperationBase\n    {\n        public Position Position { get; }\n\n        public CanvasTranslateOperation(Position position)\n        {\n            Position = position;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/Operations/ChildDrawOperation.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests.TestEngine.Operations\n{\n    public class ChildDrawOperation : OperationBase\n    {\n        public string ChildId { get; }\n        public Size Input { get; }\n\n        public ChildDrawOperation(string childId, Size input)\n        {\n            ChildId = childId;\n            Input = input;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/Operations/ChildMeasureOperation.cs",
    "content": "﻿using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests.TestEngine.Operations\n{\n    internal sealed class ChildMeasureOperation : OperationBase\n    {\n        public string ChildId { get; }\n        public Size Input { get; }\n        public SpacePlan Output { get; }\n\n        public ChildMeasureOperation(string childId, Size input, SpacePlan output)\n        {\n            ChildId = childId;\n            Input = input;\n            Output = output;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/Operations/ElementMeasureOperation.cs",
    "content": "﻿using QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests.TestEngine.Operations\n{\n    public class ElementMeasureOperation : OperationBase\n    {\n        public ElementMeasureOperation(Size input)\n        {\n            \n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/SimpleContainerTests.cs",
    "content": "﻿using QuestPDF.Drawing;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests.TestEngine\n{\n    internal static class SimpleContainerTests\n    {\n        #region measure\n        \n        public static void Measure<TElement>() where TElement : Element, IContainer, new()\n        {\n            Measure_Wrap<TElement>();\n            Measure_PartialRender<TElement>();\n            Measure_FullRender<TElement>();\n        }\n        \n        private static void Measure_Wrap<TElement>() where TElement : Element, IContainer, new()\n        {\n            TestPlan\n                .For(x => new TElement\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(new Size(400, 300), SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Forwarded from child\"));\n        }\n        \n        private static void Measure_PartialRender<TElement>() where TElement : Element, IContainer, new()\n        {\n            TestPlan\n                .For(x => new TElement\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(new Size(400, 300), SpacePlan.PartialRender(200, 100))\n                .CheckMeasureResult(SpacePlan.PartialRender(200, 100));\n        }\n        \n        private static void Measure_FullRender<TElement>() where TElement : Element, IContainer, new()\n        {\n            TestPlan\n                .For(x => new TElement\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(400, 300))\n                .ExpectChildMeasure(new Size(400, 300), SpacePlan.FullRender(250, 150))\n                .CheckMeasureResult(SpacePlan.FullRender(250, 150));\n        }\n        \n        #endregion\n        \n        public static void Draw<TElement>() where TElement : Element, IContainer, new()\n        {\n            TestPlan\n                .For(x => new TElement\n                {\n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(1200, 900))\n                .ExpectChildDraw(new Size(1200, 900))\n                .CheckDrawResult();\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TestEngine/TestPlan.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text.Json;\nusing NUnit.Framework;\nusing NUnit.Framework.Legacy;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine.Operations;\n\nnamespace QuestPDF.UnitTests.TestEngine\n{\n    internal sealed class TestPlan\n    {\n        private const string DefaultChildName = \"child\";\n\n        private static Random Random { get; } = new Random();\n        \n        private Element Element { get; set; }\n        private IDrawingCanvas Canvas { get; }\n        \n        private Size OperationInput { get; set; }\n        private Queue<OperationBase> Operations { get; } = new Queue<OperationBase>();\n\n        public TestPlan()\n        {\n            Canvas = CreateCanvas();\n        }\n        \n        public static TestPlan For(Func<TestPlan, Element> create)\n        {\n            var plan = new TestPlan();\n            plan.Element = create(plan);\n            \n            return plan;\n        }\n\n        private T GetExpected<T>() where T : OperationBase\n        {\n            if (Operations.TryDequeue(out var value) && value is T result)\n                return result;\n\n            var gotType = value?.GetType()?.Name ?? \"null\";\n            Assert.Fail($\"Expected: {typeof(T).Name}, got {gotType}: {JsonSerializer.Serialize(value)}\");\n            return null;\n        }\n        \n        private IDrawingCanvas CreateCanvas()\n        {\n            return new MockCanvas\n            {\n                TranslateFunc = position =>\n                {\n                    var expected = GetExpected<CanvasTranslateOperation>();\n\n                    ClassicAssert.AreEqual(expected.Position.X, position.X, \"Translate X\");\n                    ClassicAssert.AreEqual(expected.Position.Y, position.Y, \"Translate Y\");\n                },\n                RotateFunc = angle =>\n                {\n                    var expected = GetExpected<CanvasRotateOperation>();\n\n                    ClassicAssert.AreEqual(expected.Angle, angle, \"Rotate angle\");\n                },\n                ScaleFunc = (scaleX, scaleY) =>\n                {\n                    var expected = GetExpected<CanvasScaleOperation>();\n\n                    ClassicAssert.AreEqual(expected.ScaleX, scaleX, \"Scale X\");\n                    ClassicAssert.AreEqual(expected.ScaleY, scaleY, \"Scale Y\");\n                },\n                DrawRectFunc = (position, size, color) =>\n                {\n                    var expected = GetExpected<CanvasDrawRectangleOperation>();\n                    \n                    ClassicAssert.AreEqual(expected.Position.X, position.X, \"Draw rectangle: X\");\n                    ClassicAssert.AreEqual(expected.Position.Y, position.Y, \"Draw rectangle: Y\");\n                    \n                    ClassicAssert.AreEqual(expected.Size.Width, size.Width, \"Draw rectangle: width\");\n                    ClassicAssert.AreEqual(expected.Size.Height, size.Height, \"Draw rectangle: height\");\n                    \n                    ClassicAssert.AreEqual(expected.Color, color, \"Draw rectangle: color\");\n                },\n                DrawImageFunc = (image, position, size) =>\n                {\n                    var expected = GetExpected<CanvasDrawImageOperation>();\n                    \n                    ClassicAssert.AreEqual(expected.Position.X, position.X, \"Draw image: X\");\n                    ClassicAssert.AreEqual(expected.Position.Y, position.Y, \"Draw image: Y\");\n                    \n                    ClassicAssert.AreEqual(expected.Size.Width, size.Width, \"Draw image: width\");\n                    ClassicAssert.AreEqual(expected.Size.Height, size.Height, \"Draw image: height\");\n                }\n            };\n        }\n\n        public Element CreateChild() => CreateChild(DefaultChildName);\n        \n        public Element CreateChild(string id)\n        {\n            return new ElementMock\n            {\n                Id = id,\n                MeasureFunc = availableSpace =>\n                {\n                    var expected = GetExpected<ChildMeasureOperation>();\n\n                    ClassicAssert.AreEqual(expected.ChildId, id);\n                    \n                    ClassicAssert.AreEqual(expected.Input.Width, availableSpace.Width, $\"Measure: width of child '{expected.ChildId}'\");\n                    ClassicAssert.AreEqual(expected.Input.Height, availableSpace.Height, $\"Measure: height of child '{expected.ChildId}'\");\n\n                    return expected.Output;\n                },\n                DrawFunc = availableSpace =>\n                {\n                    var expected = GetExpected<ChildDrawOperation>();\n\n                    ClassicAssert.AreEqual(expected.ChildId, id);\n                    \n                    ClassicAssert.AreEqual(expected.Input.Width, availableSpace.Width, $\"Draw: width of child '{expected.ChildId}'\");\n                    ClassicAssert.AreEqual(expected.Input.Height, availableSpace.Height, $\"Draw: width of child '{expected.ChildId}'\");\n                }\n            };\n        }\n        \n        public TestPlan MeasureElement(Size input)\n        {\n            OperationInput = input;\n            return this;\n        }\n        \n        public TestPlan DrawElement(Size input)\n        {\n            OperationInput = input;\n            return this;\n        }\n\n        private TestPlan AddOperation(OperationBase operationBase)\n        {\n            Operations.Enqueue(operationBase);\n            return this;\n        }\n        \n        public TestPlan ExpectChildMeasure(Size expectedInput, SpacePlan returns)\n        {\n            return ExpectChildMeasure(DefaultChildName, expectedInput, returns);\n        }\n        \n        public TestPlan ExpectChildMeasure(string child, Size expectedInput, SpacePlan returns)\n        {\n            return AddOperation(new ChildMeasureOperation(child, expectedInput, returns));\n        }\n        \n        public TestPlan ExpectChildDraw(Size expectedInput)\n        {\n            return ExpectChildDraw(DefaultChildName, expectedInput);\n        }\n        \n        public TestPlan ExpectChildDraw(string child, Size expectedInput)\n        {\n            return AddOperation(new ChildDrawOperation(child, expectedInput));\n        }\n\n        public TestPlan ExpectCanvasTranslate(Position position)\n        {\n            return AddOperation(new CanvasTranslateOperation(position));\n        }\n        \n        public TestPlan ExpectCanvasTranslate(float left, float top)\n        {\n            return AddOperation(new CanvasTranslateOperation(new Position(left, top)));\n        }\n\n        public TestPlan ExpectCanvasScale(float scaleX, float scaleY)\n        {\n            return AddOperation(new CanvasScaleOperation(scaleX, scaleY));\n        }\n        \n        public TestPlan ExpectCanvasRotate(float angle)\n        {\n            return AddOperation(new CanvasRotateOperation(angle));\n        }\n        \n        public TestPlan ExpectCanvasDrawRectangle(Position position, Size size, Color color)\n        {\n            return AddOperation(new CanvasDrawRectangleOperation(position, size, color));\n        }\n        \n        public TestPlan ExpectCanvasDrawImage(Position position, Size size)\n        {\n            return AddOperation(new CanvasDrawImageOperation(position, size));\n        }\n        \n        public TestPlan CheckMeasureResult(SpacePlan expected)\n        {\n            Element.InjectDependencies(null, Canvas);\n            \n            var actual = Element.Measure(OperationInput);\n            Element.ReleaseDisposableChildren();\n            \n            ClassicAssert.AreEqual(expected.GetType(), actual.GetType());\n            \n            ClassicAssert.AreEqual(expected.Width, actual.Width, \"Measure: width\");\n            ClassicAssert.AreEqual(expected.Height, actual.Height, \"Measure: height\");\n            ClassicAssert.AreEqual(expected.Type, actual.Type, \"Measure: height\");\n            ClassicAssert.AreEqual(expected.WrapReason, actual.WrapReason, \"Measure: wrap\");\n            \n            return this;\n        }\n        \n        public TestPlan CheckDrawResult()\n        {\n            Element.InjectDependencies(null, Canvas);\n            Element.Draw(OperationInput);\n            Element.ReleaseDisposableChildren();\n            return this;\n        }\n\n        public TestPlan CheckState(Func<Element, bool> condition)\n        {\n            ClassicAssert.IsTrue(condition(Element), \"Checking condition\");\n            return this;\n        }\n\n        public TestPlan CheckState<T>(Func<T, bool> condition) where T : Element\n        {\n            ClassicAssert.IsTrue(Element is T);\n            ClassicAssert.IsTrue(condition(Element as T), \"Checking condition\");\n            return this;\n        }\n        \n        public static Element CreateUniqueElement()\n        {\n            var content = new Container();\n\n            content\n                .AspectRatio(4 / 3f)\n                .Image(Placeholders.Image);\n            \n            return content;\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TextSpanTests.cs",
    "content": "using System;\nusing System.Linq;\nusing NUnit.Framework;\nusing QuestPDF.Elements.Text;\nusing QuestPDF.Elements.Text.Items;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.UnitTests;\n\npublic class TextSpanTests\n{\n    internal (TextSpanDescriptor, TextBlockSpan) CreateTextBlockSpan()\n    {\n        var container = EmptyContainer.Create();\n        var descriptor = container.Text(\"test\");\n\n        var textElement = container.Child as TextBlock;\n        var textBlockSpan = textElement?.Items.SingleOrDefault() as TextBlockSpan;\n        \n        return (descriptor, textBlockSpan);\n    }\n    \n    #region Override Style\n    \n    [Test]\n    public void OverridesStyle()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n\n        var customStyle = TextStyle\n            .Default\n            .FontColor(Colors.Black)\n            .BackgroundColor(Colors.Transparent)\n            .Underline()\n            .DecorationColor(Colors.Red.Medium)\n            .DecorationWavy();\n\n        descriptor\n            .FontSize(30)\n            .FontColor(Colors.Blue.Darken4)\n            .BackgroundColor(Colors.Blue.Lighten5)\n            .Bold()\n            .Style(customStyle);\n        \n        Assert.That(textBlockSpan.Style.Size, Is.EqualTo(30));\n        Assert.That(textBlockSpan.Style.Color, Is.EqualTo(Colors.Black));\n        Assert.That(textBlockSpan.Style.BackgroundColor, Is.EqualTo(Colors.Transparent));\n        Assert.That(textBlockSpan.Style.HasUnderline, Is.True);\n        Assert.That(textBlockSpan.Style.DecorationColor, Is.EqualTo(Colors.Red.Medium));\n        Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Wavy));\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Bold));\n    }\n    \n    [Test]\n    public void OverridesStyle_AcceptsNull()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n\n        descriptor\n            .FontSize(30)\n            .FontColor(Colors.Blue.Darken4)\n            .BackgroundColor(Colors.Blue.Lighten5)\n            .Bold()\n            .Style(null);\n        \n        Assert.That(textBlockSpan.Style.Size, Is.EqualTo(30));\n        Assert.That(textBlockSpan.Style.Color, Is.EqualTo(Colors.Blue.Darken4));\n        Assert.That(textBlockSpan.Style.BackgroundColor, Is.EqualTo(Colors.Blue.Lighten5));\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Bold));\n    }\n    \n    #endregion\n    \n    #region Font Color\n    \n    [Test]\n    public void SetsCorrectFontColor()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.FontColor(Colors.Blue.Medium);\n        Assert.That(textBlockSpan.Style.Color, Is.EqualTo(Colors.Blue.Medium));\n    }\n    \n    [Test]\n    public void FontColor_AlsoSetsDecorationColor()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.FontColor(Colors.Green.Darken2);\n        Assert.That(textBlockSpan.Style.DecorationColor, Is.EqualTo(Colors.Green.Darken2));\n    }\n    \n    #endregion\n    \n    #region Background Color\n    \n    [Test]\n    public void SetsCorrectBackgroundColor()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.BackgroundColor(Colors.Yellow.Lighten3);\n        Assert.That(textBlockSpan.Style.BackgroundColor, Is.EqualTo(Colors.Yellow.Lighten3));\n    }\n    \n    #endregion\n    \n    #region Font Family\n    \n    [Test]\n    public void SetsCorrectFontFamily_Single()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.FontFamily(\"Arial\");\n        Assert.That(textBlockSpan.Style.FontFamilies, Is.EqualTo(new[] { \"Arial\" }));\n    }\n    \n    [Test]\n    public void SetsCorrectFontFamily_Multiple()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.FontFamily(\"Helvetica\", \"Arial\", \"sans-serif\");\n        Assert.That(textBlockSpan.Style.FontFamilies, Is.EqualTo(new[] { \"Helvetica\", \"Arial\", \"sans-serif\" }));\n    }\n\n    [Test]\n    public void FontFamily_EmptyArray_ReturnsUnchanged()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.FontFamily([]);\n        Assert.That(textBlockSpan.Style.FontFamilies, Is.Null);\n    }\n    \n    [Test]\n    public void FontFamily_Null_ReturnsUnchanged()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.FontFamily(null);\n        Assert.That(textBlockSpan.Style.FontFamilies, Is.Null);\n    }\n    \n    #endregion\n    \n    #region Font Size\n    \n\n    [Test]\n    public void SetsCorrectFontSize()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.FontSize(18);\n        Assert.That(textBlockSpan.Style.Size, Is.EqualTo(18));\n    }\n    \n    [TestCase(-10)]\n    [TestCase(-5)]\n    [TestCase(-float.Epsilon)]\n    [TestCase(0)]\n    public void FontSize_MustBePositive(float fontSize)\n    {\n        var exception = Assert.Throws<ArgumentException>(() =>\n        {\n            var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n            descriptor.FontSize(fontSize);\n        });\n        \n        Assert.That(exception.Message, Is.EqualTo(\"Font size must be greater than 0.\"));\n    }\n\n    #endregion\n    \n    #region Line Height\n\n    [Test]\n    public void SetsCorrectLineHeight()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.LineHeight(1.5f);\n        Assert.That(textBlockSpan.Style.LineHeight, Is.EqualTo(1.5f));\n    }\n    \n    [Test]\n    public void LineHeight_Null_SetsToNormalLineHeight()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.LineHeight(null);\n        Assert.That(textBlockSpan.Style.LineHeight, Is.EqualTo(TextStyle.NormalLineHeightCalculatedFromFontMetrics));\n    }\n    \n    [TestCase(-5)]\n    [TestCase(-float.Epsilon)]\n    public void LineHeightMustBePositive(float lineHeight)\n    {\n        var exception = Assert.Throws<ArgumentException>(() =>\n        {\n            var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n            descriptor.LineHeight(lineHeight);\n        });\n        \n        Assert.That(exception.Message, Is.EqualTo(\"Line height must be greater than 0.\"));\n    }\n    \n    [Test]\n    public void LineHeight_AllowsZero()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.LineHeight(0);\n        Assert.That(textBlockSpan.Style.LineHeight, Is.Zero);\n    }\n    \n    #endregion\n    \n    #region Letter Spacing\n    \n    [Test]\n    public void SetsCorrectLetterSpacing_Positive()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.LetterSpacing(0.5f);\n        Assert.That(textBlockSpan.Style.LetterSpacing, Is.EqualTo(0.5f));\n    }\n    \n    [Test]\n    public void SetsCorrectLetterSpacing_Negative()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.LetterSpacing(-0.2f);\n        Assert.That(textBlockSpan.Style.LetterSpacing, Is.EqualTo(-0.2f));\n    }\n    \n    [Test]\n    public void LetterSpacing_DefaultParameterIsZero()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.LetterSpacing();\n        Assert.That(textBlockSpan.Style.LetterSpacing, Is.Zero);\n    }\n    \n    #endregion\n    \n    #region Word Spacing\n    \n    [Test]\n    public void SetsCorrectWordSpacing_Positive()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.WordSpacing(2.0f);\n        Assert.That(textBlockSpan.Style.WordSpacing, Is.EqualTo(2.0f));\n    }\n    \n    [Test]\n    public void SetsCorrectWordSpacing_Negative()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.WordSpacing(-1.0f);\n        Assert.That(textBlockSpan.Style.WordSpacing, Is.EqualTo(-1.0f));\n    }\n    \n    [Test]\n    public void WordSpacing_DefaultParameterIsZero()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.WordSpacing();\n        Assert.That(textBlockSpan.Style.WordSpacing, Is.Zero);\n    }\n    \n    #endregion\n    \n    #region Italic\n    \n    [Test]\n    public void SetsCorrectItalic_Enabled()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Italic();\n        Assert.That(textBlockSpan.Style.IsItalic, Is.True);\n    }\n    \n    [Test]\n    public void SetsCorrectItalic_Disabled()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Italic().Italic(false);\n        Assert.That(textBlockSpan.Style.IsItalic, Is.False);\n    }\n    \n    #endregion\n    \n    #region Text Decoration\n\n    [Test]\n    public void SetsCorrectTextDecoration_Strikethrough()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Strikethrough();\n        Assert.That(textBlockSpan.Style.HasStrikethrough, Is.True);\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_StrikethroughDisabled()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Strikethrough(false);\n        Assert.That(textBlockSpan.Style.HasStrikethrough, Is.False);\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_Underline()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Underline();\n        Assert.That(textBlockSpan.Style.HasUnderline, Is.True);\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_UnderlineDisabled()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Underline(false);\n        Assert.That(textBlockSpan.Style.HasUnderline, Is.False);\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_Overline()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Overline();\n        Assert.That(textBlockSpan.Style.HasOverline, Is.True);\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_OverlineDisabled()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Overline(false);\n        Assert.That(textBlockSpan.Style.HasOverline, Is.False);\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_DecorationColor()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DecorationColor(Colors.Red.Medium);\n        Assert.That(textBlockSpan.Style.DecorationColor, Is.EqualTo(Colors.Red.Medium));\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_DecorationThickness()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DecorationThickness(1.5f);\n        Assert.That(textBlockSpan.Style.DecorationThickness, Is.EqualTo(1.5f));\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_DecorationSolid()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DecorationSolid();\n        Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Solid));\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_DecorationDouble()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DecorationDouble();\n        Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Double));\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_DecorationWavy()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DecorationWavy();\n        Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Wavy));\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_DecorationDotted()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DecorationDotted();\n        Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Dotted));\n    }\n    \n    [Test]\n    public void SetsCorrectTextDecoration_DecorationDashed()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DecorationDashed();\n        Assert.That(textBlockSpan.Style.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Dashed));\n    }\n    \n    #endregion\n    \n    #region Font Weight\n\n    [Test]\n    public void SetsCorrectSetsCorrectFontWeight_Thin()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Thin();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Thin));\n    }\n    \n    [Test]\n    public void SetsCorrectFontWeight_ExtraLight()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.ExtraLight();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.ExtraLight));\n    }\n    \n    [Test]\n    public void SetsCorrectFontWeight_Light()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Light();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Light));\n    }\n    \n    [Test]\n    public void SetsCorrectFontWeight_Normal()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.NormalWeight();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Normal));\n    }\n    \n    [Test]\n    public void SetsCorrectFontWeight_Medium()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Medium();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Medium));\n    }\n    \n    [Test]\n    public void SetsCorrectFontWeight_SemiBold()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.SemiBold();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.SemiBold));\n    }\n    \n    [Test]\n    public void SetsCorrectFontWeight_Bold()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Bold();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Bold));\n    }\n    \n    [Test]\n    public void SetsCorrectFontWeight_ExtraBold()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.ExtraBold();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.ExtraBold));\n    }\n    \n    [Test]\n    public void SetsCorrectFontWeight_Black()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Black();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.Black));\n    }\n    \n    [Test]\n    public void SetsCorrectFontWeight_ExtraBlack()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.ExtraBlack();\n        Assert.That(textBlockSpan.Style.FontWeight, Is.EqualTo(FontWeight.ExtraBlack));\n    }\n\n    #endregion\n    \n    #region Text Position\n    \n    [Test]\n    public void SetsCorrectTextPosition_Subscript()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Subscript();\n        Assert.That(textBlockSpan.Style.FontPosition, Is.EqualTo(FontPosition.Subscript));\n    }\n    \n    [Test]\n    public void SetsCorrectTextPosition_Normal()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Superscript().NormalPosition(); // first change from default, then normal\n        Assert.That(textBlockSpan.Style.FontPosition, Is.EqualTo(FontPosition.Normal));\n    }\n    \n    [Test]\n    public void SetsCorrectTextPosition_Superscript()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.Superscript();\n        Assert.That(textBlockSpan.Style.FontPosition, Is.EqualTo(FontPosition.Superscript));\n    }\n    \n    #endregion\n    \n    #region Text Direction\n        \n    [Test]\n    public void SetsCorrectTextDirection_LeftToRight()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DirectionFromLeftToRight();\n        Assert.That(textBlockSpan.Style.Direction, Is.EqualTo(TextDirection.LeftToRight));\n    }\n        \n    [Test]\n    public void SetsCorrectTextDirection_RightToLeft()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DirectionFromRightToLeft();\n        Assert.That(textBlockSpan.Style.Direction, Is.EqualTo(TextDirection.RightToLeft));\n    }\n        \n    [Test]\n    public void SetsCorrectTextDirection_Auto()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        descriptor.DirectionFromRightToLeft().DirectionAuto();\n        Assert.That(textBlockSpan.Style.Direction, Is.EqualTo(TextDirection.Auto));\n    }\n        \n    #endregion\n    \n    #region Font Features\n    \n    [Test]\n    public void EnableFontFeature_SingleFeature()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        \n        descriptor.EnableFontFeature(FontFeatures.StandardLigatures);\n        Assert.That(textBlockSpan.Style.FontFeatures, Has.Length.EqualTo(1));\n        Assert.That(textBlockSpan.Style.FontFeatures[0], Is.EqualTo((FontFeatures.StandardLigatures, true)));\n    }\n    \n    [Test]\n    public void DisableFontFeature_SingleFeature()\n    {\n        var (descriptor, textBlockSpan) = CreateTextBlockSpan();\n        \n        descriptor.DisableFontFeature(FontFeatures.Kerning);\n        Assert.That(textBlockSpan.Style.FontFeatures, Has.Length.EqualTo(1));\n        Assert.That(textBlockSpan.Style.FontFeatures[0], Is.EqualTo((FontFeatures.Kerning, false)));\n    }\n\n    [Test]\n    public void FontFeatures_MixedEnableDisable()\n    {\n        var textStyle = TextStyle.Default\n            .EnableFontFeature(FontFeatures.StandardLigatures)\n            .DisableFontFeature(FontFeatures.Kerning)\n            .DisableFontFeature(FontFeatures.DiscretionaryLigatures)\n            .EnableFontFeature(FontFeatures.Kerning);\n        \n        Assert.That(textStyle.FontFeatures, Has.Length.EqualTo(3));\n        Assert.That(textStyle.FontFeatures[0], Is.EqualTo((FontFeatures.Kerning, true)));\n        Assert.That(textStyle.FontFeatures[1], Is.EqualTo((FontFeatures.DiscretionaryLigatures, false)));\n        Assert.That(textStyle.FontFeatures[2], Is.EqualTo((FontFeatures.StandardLigatures, true)));\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TextStyleTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing NUnit.Framework;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.Skia.Text;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class TextStyleTests\n    {\n        #region Font Color\n        \n        [Test]\n        public void FontColor_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.Color, Is.EqualTo(Colors.Black));\n        }\n        \n        [Test]\n        public void SetsCorrectFontColor()\n        {\n            var textStyle = TextStyle.Default.FontColor(Colors.Blue.Medium);\n            Assert.That(textStyle.Color, Is.EqualTo(Colors.Blue.Medium));\n        }\n        \n        [Test]\n        public void FontColor_AlsoSetsDecorationColor()\n        {\n            var textStyle = TextStyle.Default.FontColor(Colors.Green.Darken2);\n            Assert.That(textStyle.DecorationColor, Is.EqualTo(Colors.Green.Darken2));\n        }\n        \n        #endregion\n        \n        #region Background Color\n        \n        [Test]\n        public void BackgroundColor_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.BackgroundColor, Is.EqualTo(Colors.Transparent));\n        }\n        \n        [Test]\n        public void SetsCorrectBackgroundColor()\n        {\n            var textStyle = TextStyle.Default.BackgroundColor(Colors.Yellow.Lighten3);\n            Assert.That(textStyle.BackgroundColor, Is.EqualTo(Colors.Yellow.Lighten3));\n        }\n        \n        #endregion\n        \n        #region Font Family\n        \n        [Test]\n        public void FontFamily_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.FontFamilies, Is.EqualTo(new[] { \"Lato\" }));\n        }\n        \n        [Test]\n        public void SetsCorrectFontFamily_Single()\n        {\n            var textStyle = TextStyle.Default.FontFamily(\"Arial\");\n            Assert.That(textStyle.FontFamilies, Is.EqualTo(new[] { \"Arial\" }));\n        }\n        \n        [Test]\n        public void SetsCorrectFontFamily_Multiple()\n        {\n            var textStyle = TextStyle.Default.FontFamily(\"Helvetica\", \"Arial\", \"sans-serif\");\n            Assert.That(textStyle.FontFamilies, Is.EqualTo(new[] { \"Helvetica\", \"Arial\", \"sans-serif\" }));\n        }\n\n        [Test]\n        public void FontFamily_EmptyArray_ReturnsUnchanged()\n        {\n            var textStyle = TextStyle.Default.FontFamily([]);\n            Assert.That(textStyle.FontFamilies, Is.Null);\n        }\n        \n        [Test]\n        public void FontFamily_Null_ReturnsUnchanged()\n        {\n            var textStyle = TextStyle.Default.FontFamily(null);\n            Assert.That(textStyle.FontFamilies, Is.Null);\n        }\n        \n        #endregion\n        \n        #region Font Size\n        \n        [Test]\n        public void FontSize_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.Size, Is.EqualTo(12));\n        }\n        \n        [Test]\n        public void SetsCorrectFontSize()\n        {\n            var textStyle = TextStyle.Default.FontSize(18);\n            Assert.That(textStyle.Size, Is.EqualTo(18));\n        }\n        \n        [TestCase(-10)]\n        [TestCase(-5)]\n        [TestCase(-float.Epsilon)]\n        [TestCase(0)]\n        public void FontSize_MustBePositive(float fontSize)\n        {\n            var exception = Assert.Throws<ArgumentException>(() =>\n            {\n                TextStyle.Default.FontSize(fontSize);\n            });\n            \n            Assert.That(exception.Message, Is.EqualTo(\"Font size must be greater than 0.\"));\n        }\n\n        #endregion\n        \n        #region Line Height\n        \n        [Test]\n        public void LineHeight_Default()\n        {\n            // special value: 0 = normal line height calculated from font metrics\n            \n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.LineHeight, Is.Zero);\n        }\n        \n        [Test]\n        public void SetsCorrectLineHeight()\n        {\n            var textStyle = TextStyle.Default.LineHeight(1.5f);\n            Assert.That(textStyle.LineHeight, Is.EqualTo(1.5f));\n        }\n        \n        [Test]\n        public void LineHeight_Null_SetsToNormalLineHeight()\n        {\n            var textStyle = TextStyle.Default.LineHeight(2.0f).LineHeight(null);\n            Assert.That(textStyle.LineHeight, Is.EqualTo(TextStyle.NormalLineHeightCalculatedFromFontMetrics));\n        }\n        \n        [TestCase(-5)]\n        [TestCase(-float.Epsilon)]\n        public void LineHeightMustBePositive(float lineHeight)\n        {\n            var exception = Assert.Throws<ArgumentException>(() =>\n            {\n                TextStyle.Default.LineHeight(lineHeight);\n            });\n            \n            Assert.That(exception.Message, Is.EqualTo(\"Line height must be greater than 0.\"));\n        }\n        \n        [Test]\n        public void LineHeight_AllowsZero()\n        {\n            var textStyle = TextStyle.Default.LineHeight(0);\n            Assert.That(textStyle.LineHeight, Is.Zero);\n        }\n        \n        #endregion\n        \n        #region Letter Spacing\n        \n        [Test]\n        public void LetterSpacing_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.LetterSpacing, Is.Zero);\n        }\n        \n        [Test]\n        public void SetsCorrectLetterSpacing_Positive()\n        {\n            var textStyle = TextStyle.Default.LetterSpacing(0.5f);\n            Assert.That(textStyle.LetterSpacing, Is.EqualTo(0.5f));\n        }\n        \n        [Test]\n        public void SetsCorrectLetterSpacing_Negative()\n        {\n            var textStyle = TextStyle.Default.LetterSpacing(-0.2f);\n            Assert.That(textStyle.LetterSpacing, Is.EqualTo(-0.2f));\n        }\n        \n        [Test]\n        public void LetterSpacing_DefaultParameterIsZero()\n        {\n            var textStyle = TextStyle.Default.LetterSpacing();\n            Assert.That(textStyle.LetterSpacing, Is.Zero);\n        }\n        \n        #endregion\n        \n        #region Word Spacing\n        \n        [Test]\n        public void WordSpacing_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.WordSpacing, Is.Zero);\n        }\n        \n        [Test]\n        public void SetsCorrectWordSpacing_Positive()\n        {\n            var textStyle = TextStyle.Default.WordSpacing(2.0f);\n            Assert.That(textStyle.WordSpacing, Is.EqualTo(2.0f));\n        }\n        \n        [Test]\n        public void SetsCorrectWordSpacing_Negative()\n        {\n            var textStyle = TextStyle.Default.WordSpacing(-1.0f);\n            Assert.That(textStyle.WordSpacing, Is.EqualTo(-1.0f));\n        }\n        \n        [Test]\n        public void WordSpacing_DefaultParameterIsZero()\n        {\n            var textStyle = TextStyle.Default.WordSpacing();\n            Assert.That(textStyle.WordSpacing, Is.Zero);\n        }\n        \n        #endregion\n        \n        #region Italic\n        \n        [Test]\n        public void Italic_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.IsItalic, Is.False);\n        }\n        \n        [Test]\n        public void SetsCorrectItalic_Enabled()\n        {\n            var textStyle = TextStyle.Default.Italic();\n            Assert.That(textStyle.IsItalic, Is.True);\n        }\n        \n        [Test]\n        public void SetsCorrectItalic_Disabled()\n        {\n            var textStyle = TextStyle.Default.Italic().Italic(false);\n            Assert.That(textStyle.IsItalic, Is.False);\n        }\n        \n        #endregion\n        \n        #region Text Decoration\n        \n        [Test]\n        public void TextDecoration_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.HasStrikethrough, Is.False);\n            Assert.That(textStyle.HasUnderline, Is.False);\n            Assert.That(textStyle.HasOverline, Is.False);\n            Assert.That(textStyle.DecorationColor, Is.EqualTo(Colors.Black));\n            Assert.That(textStyle.DecorationThickness, Is.EqualTo(1f));\n            Assert.That(textStyle.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Solid));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_Strikethrough()\n        {\n            var textStyle = TextStyle.Default.Strikethrough();\n            Assert.That(textStyle.HasStrikethrough, Is.True);\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_StrikethroughDisabled()\n        {\n            var textStyle = TextStyle.Default.Strikethrough().Strikethrough(false);\n            Assert.That(textStyle.HasStrikethrough, Is.False);\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_Underline()\n        {\n            var textStyle = TextStyle.Default.Underline();\n            Assert.That(textStyle.HasUnderline, Is.True);\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_UnderlineDisabled()\n        {\n            var textStyle = TextStyle.Default.Underline().Underline(false);\n            Assert.That(textStyle.HasUnderline, Is.False);\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_Overline()\n        {\n            var textStyle = TextStyle.Default.Overline();\n            Assert.That(textStyle.HasOverline, Is.True);\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_OverlineDisabled()\n        {\n            var textStyle = TextStyle.Default.Overline().Overline(false);\n            Assert.That(textStyle.HasOverline, Is.False);\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_DecorationColor()\n        {\n            var textStyle = TextStyle.Default.DecorationColor(Colors.Red.Medium);\n            Assert.That(textStyle.DecorationColor, Is.EqualTo(Colors.Red.Medium));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_DecorationThickness()\n        {\n            var textStyle = TextStyle.Default.DecorationThickness(1.5f);\n            Assert.That(textStyle.DecorationThickness, Is.EqualTo(1.5f));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_DecorationSolid()\n        {\n            var textStyle = TextStyle.Default.DecorationSolid();\n            Assert.That(textStyle.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Solid));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_DecorationDouble()\n        {\n            var textStyle = TextStyle.Default.DecorationDouble();\n            Assert.That(textStyle.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Double));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_DecorationWavy()\n        {\n            var textStyle = TextStyle.Default.DecorationWavy();\n            Assert.That(textStyle.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Wavy));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_DecorationDotted()\n        {\n            var textStyle = TextStyle.Default.DecorationDotted();\n            Assert.That(textStyle.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Dotted));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDecoration_DecorationDashed()\n        {\n            var textStyle = TextStyle.Default.DecorationDashed();\n            Assert.That(textStyle.DecorationStyle, Is.EqualTo(TextStyleConfiguration.TextDecorationStyle.Dashed));\n        }\n        \n        #endregion\n        \n        #region Font Weight\n        \n        [Test]\n        public void FontWeight_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.Normal));\n        }\n        \n        [Test]\n        public void SetsCorrectSetsCorrectFontWeight_Thin()\n        {\n            var textStyle = TextStyle.Default.Thin();\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.Thin));\n        }\n        \n        [Test]\n        public void SetsCorrectFontWeight_ExtraLight()\n        {\n            var textStyle = TextStyle.Default.ExtraLight();\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.ExtraLight));\n        }\n        \n        [Test]\n        public void SetsCorrectFontWeight_Light()\n        {\n            var textStyle = TextStyle.Default.Light();\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.Light));\n        }\n        \n        [Test]\n        public void SetsCorrectFontWeight_Normal()\n        {\n            var textStyle = TextStyle.Default.Bold().NormalWeight(); // first change from default, then normal\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.Normal));\n        }\n        \n        [Test]\n        public void SetsCorrectFontWeight_Medium()\n        {\n            var textStyle = TextStyle.Default.Medium();\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.Medium));\n        }\n        \n        [Test]\n        public void SetsCorrectFontWeight_SemiBold()\n        {\n            var textStyle = TextStyle.Default.SemiBold();\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.SemiBold));\n        }\n        \n        [Test]\n        public void SetsCorrectFontWeight_Bold()\n        {\n            var textStyle = TextStyle.Default.Bold();\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.Bold));\n        }\n        \n        [Test]\n        public void SetsCorrectFontWeight_ExtraBold()\n        {\n            var textStyle = TextStyle.Default.ExtraBold();\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.ExtraBold));\n        }\n        \n        [Test]\n        public void SetsCorrectFontWeight_Black()\n        {\n            var textStyle = TextStyle.Default.Black();\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.Black));\n        }\n        \n        [Test]\n        public void SetsCorrectFontWeight_ExtraBlack()\n        {\n            var textStyle = TextStyle.Default.ExtraBlack();\n            Assert.That(textStyle.FontWeight, Is.EqualTo(FontWeight.ExtraBlack));\n        }\n        \n        #endregion\n        \n        #region Text Position\n    \n        [Test]\n        public void TextPosition_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.FontPosition, Is.EqualTo(FontPosition.Normal));\n        }\n        \n        [Test]\n        public void SetsCorrectTextPosition_Subscript()\n        {\n            var textStyle = TextStyle.Default.Subscript();\n            Assert.That(textStyle.FontPosition, Is.EqualTo(FontPosition.Subscript));\n        }\n        \n        [Test]\n        public void SetsCorrectTextPosition_Normal()\n        {\n            var textStyle = TextStyle.Default.Subscript().NormalPosition(); // first change from default, then normal\n            Assert.That(textStyle.FontPosition, Is.EqualTo(FontPosition.Normal));\n        }\n        \n        [Test]\n        public void SetsCorrectTextPosition_Superscript()\n        {\n            var textStyle = TextStyle.Default.Superscript();\n            Assert.That(textStyle.FontPosition, Is.EqualTo(FontPosition.Superscript));\n        }\n    \n        #endregion\n        \n        #region Text Direction\n        \n        [Test]\n        public void TextDirection_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.Direction, Is.EqualTo(TextDirection.Auto));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDirection_LeftToRight()\n        {\n            var textStyle = TextStyle.Default.DirectionFromLeftToRight();\n            Assert.That(textStyle.Direction, Is.EqualTo(TextDirection.LeftToRight));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDirection_RightToLeft()\n        {\n            var textStyle = TextStyle.Default.DirectionFromRightToLeft();\n            Assert.That(textStyle.Direction, Is.EqualTo(TextDirection.RightToLeft));\n        }\n        \n        [Test]\n        public void SetsCorrectTextDirection_Auto()\n        {\n            var textStyle = TextStyle.Default.DirectionFromRightToLeft().DirectionAuto(); // first change from default, then auto\n            Assert.That(textStyle.Direction, Is.EqualTo(TextDirection.Auto));\n        }\n        \n        #endregion\n        \n        #region Font Features\n\n        [Test]\n        public void FontFeatures_Default()\n        {\n            var textStyle = TextStyle.LibraryDefault;\n            Assert.That(textStyle.FontFeatures, Is.Empty);\n        }\n        \n        [Test]\n        public void EnableFontFeature_SingleFeature()\n        {\n            var textStyle = TextStyle.Default\n                .EnableFontFeature(FontFeatures.StandardLigatures);\n            \n            Assert.That(textStyle.FontFeatures, Has.Length.EqualTo(1));\n            Assert.That(textStyle.FontFeatures[0], Is.EqualTo((FontFeatures.StandardLigatures, true)));\n        }\n        \n        [Test]\n        public void DisableFontFeature_SingleFeature()\n        {\n            var textStyle = TextStyle.Default\n                .DisableFontFeature(FontFeatures.Kerning);\n            \n            Assert.That(textStyle.FontFeatures, Has.Length.EqualTo(1));\n            Assert.That(textStyle.FontFeatures[0], Is.EqualTo((FontFeatures.Kerning, false)));\n        }\n        \n        // NOTE: font features applied further down the chain override those applied earlier, and will appear first in the list\n        \n        [Test]\n        public void FontFeatures_MixedEnableDisable()\n        {\n            var textStyle = TextStyle.Default\n                .EnableFontFeature(FontFeatures.StandardLigatures)\n                .DisableFontFeature(FontFeatures.Kerning)\n                .EnableFontFeature(FontFeatures.DiscretionaryLigatures);\n            \n            Assert.That(textStyle.FontFeatures, Has.Length.EqualTo(3));\n            Assert.That(textStyle.FontFeatures[0], Is.EqualTo((FontFeatures.DiscretionaryLigatures, true)));\n            Assert.That(textStyle.FontFeatures[1], Is.EqualTo((FontFeatures.Kerning, false)));\n            Assert.That(textStyle.FontFeatures[2], Is.EqualTo((FontFeatures.StandardLigatures, true)));\n        }\n        \n        [Test]\n        public void FontFeatures_OverrideSameFeature()\n        {\n            var textStyle = TextStyle.Default\n                .EnableFontFeature(FontFeatures.StandardLigatures)\n                .DisableFontFeature(FontFeatures.Kerning)\n                .DisableFontFeature(FontFeatures.Kerning)\n                .DisableFontFeature(FontFeatures.StandardLigatures);\n            \n            Assert.That(textStyle.FontFeatures, Has.Length.EqualTo(2));\n            Assert.That(textStyle.FontFeatures[0], Is.EqualTo((FontFeatures.StandardLigatures, false)));\n            Assert.That(textStyle.FontFeatures[1], Is.EqualTo((FontFeatures.Kerning, false)));\n        }\n        \n        #endregion\n        \n        // TODO: add tests for text style inheritance\n        \n        [Test]\n        public void ApplyInheritedAndGlobalStyle()\n        {\n            // arrange\n            var defaultTextStyle = TextStyle\n                .Default\n                .FontSize(20)\n                .FontFamily(\"Arial\", \"Microsoft YaHei\")\n                .BackgroundColor(Colors.Green.Lighten2)\n                .EnableFontFeature(FontFeatures.StandardLigatures);\n\n            var spanTextStyle = TextStyle\n                .Default\n                .FontFamily(\"Times New Roman\", \"Arial\", \"Calibri\")\n                .Bold()\n                .Strikethrough()\n                .BackgroundColor(Colors.Red.Lighten2)\n                .DisableFontFeature(FontFeatures.StandardLigatures)\n                .EnableFontFeature(FontFeatures.Kerning);\n            \n            // act\n            var targetStyle = spanTextStyle.ApplyInheritedStyle(defaultTextStyle).ApplyGlobalStyle();\n            \n            // assert\n            var expectedStyle = TextStyle.LibraryDefault with\n            {\n                Id = targetStyle.Id, // expect to break when adding new TextStyle properties, so use the real one\n                Size = 20, \n                FontFamilies = new[] { \"Times New Roman\", \"Arial\", \"Calibri\", \"Microsoft YaHei\", \"Lato\" },\n                FontWeight = FontWeight.Bold,\n                BackgroundColor = Colors.Red.Lighten2,\n                FontFeatures = new[]\n                {\n                    (FontFeatures.Kerning, true),\n                    (FontFeatures.StandardLigatures, false)\n                },\n                HasStrikethrough = true\n            };\n\n            Assert.That(targetStyle, Is.Not.Null);\n            Assert.That(targetStyle.Id, Is.GreaterThan(1));\n\n            Assert.That(targetStyle.ToString(), Is.EqualTo(expectedStyle.ToString()));\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/TranslateTests.cs",
    "content": "﻿using System;\nusing NUnit.Framework;\nusing QuestPDF.Elements;\nusing QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class TranslateTests\n    {\n        [TestCase(0, 0, \"\")]\n        [TestCase(5, 0, \"X=5\")]\n        [TestCase(-10, 0, \"X=-10\")]\n        [TestCase(0, 15, \"Y=15\")]\n        [TestCase(0, -20, \"Y=-20\")]\n        [TestCase(30, -40, \"X=30   Y=-40\")]\n        [TestCase(1.2345f, -2.3456f, \"X=1.2   Y=-2.3\")]\n        public void CompanionHint(float x, float y, string expected)\n        {\n            var container = EmptyContainer.Create();\n            \n            container.TranslateX(x).TranslateY(y);\n            \n            var translationElement = container.Child as Translate;\n            var companionHint = translationElement?.GetCompanionHint();\n            \n            Assert.That(companionHint, Is.EqualTo(expected));\n        }\n        \n        [Test]\n        public void HorizontalTranslationIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.TranslateX(-5).TranslateX(10).TranslateX(20);\n        \n            var rowContainer = container.Child as Translate;\n            Assert.That(rowContainer?.TranslateX, Is.EqualTo(25));\n        }\n        \n        [Test]\n        public void VerticalTranslationIsCumulative()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.TranslateY(5).TranslateY(-10).TranslateY(20);\n        \n            var rowContainer = container.Child as Translate;\n            Assert.That(rowContainer?.TranslateY, Is.EqualTo(15));\n        }\n        \n        [Test]\n        public void HorizontalTranslationSupportsUnitConversion()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.TranslateX(2, Unit.Inch);\n        \n            var rowContainer = container.Child as Translate;\n            Assert.That(rowContainer?.TranslateX, Is.EqualTo(144));\n        }\n        \n        [Test]\n        public void VerticalTranslationSupportsUnitConversion()\n        {\n            var container = EmptyContainer.Create();\n        \n            container.TranslateY(3, Unit.Inch);\n        \n            var rowContainer = container.Child as Translate;\n            Assert.That(rowContainer?.TranslateY, Is.EqualTo(216));\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/UnconstrainedTests.cs",
    "content": "﻿using NUnit.Framework;\nusing QuestPDF.Drawing;\nusing QuestPDF.Elements;\nusing QuestPDF.Infrastructure;\nusing QuestPDF.UnitTests.TestEngine;\n\nnamespace QuestPDF.UnitTests\n{\n    [TestFixture]\n    public class UnconstrainedTests\n    {\n        #region measure\n        \n        [Test]\n        public void Measure_Wrap()\n        {\n            TestPlan\n                .For(x => new Unconstrained\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(900, 800))\n                .ExpectChildMeasure(Size.Max, SpacePlan.Wrap(\"Mock\"))\n                .CheckMeasureResult(SpacePlan.Wrap(\"Forwarded from child\"));\n        }\n        \n        [Test]\n        public void Measure_PartialRender()\n        {\n            TestPlan\n                .For(x => new Unconstrained\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(900, 800))\n                .ExpectChildMeasure(Size.Max, SpacePlan.PartialRender(1200, 1600))\n                .CheckMeasureResult(SpacePlan.PartialRender(Size.Zero));\n        }\n        \n        [Test]\n        public void Measure_FullRender()\n        {\n            TestPlan\n                .For(x => new Unconstrained\n                {\n                    Child = x.CreateChild()\n                })\n                .MeasureElement(new Size(900, 800))\n                .ExpectChildMeasure(Size.Max, SpacePlan.FullRender(1200, 1600))\n                .CheckMeasureResult(SpacePlan.FullRender(Size.Zero));\n        }\n        \n        #endregion\n        \n        #region draw\n        \n        [Test]\n        public void Draw_SkipWhenChildWraps()\n        {\n            TestPlan\n                .For(x => new Unconstrained\n                {\n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(900, 800))\n                .ExpectChildMeasure(Size.Max, SpacePlan.Wrap(\"Mock\"))\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenChildPartiallyRenders()\n        {\n            TestPlan\n                .For(x => new Unconstrained\n                {\n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(900, 800))\n                .ExpectChildMeasure(Size.Max, SpacePlan.PartialRender(1200, 1600))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(new Size(1200, 1600))\n                .ExpectCanvasTranslate(0, 0)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenChildFullyRenders()\n        {\n            TestPlan\n                .For(x => new Unconstrained\n                {\n                    Child = x.CreateChild()\n                })\n                .DrawElement(new Size(900, 800))\n                .ExpectChildMeasure(Size.Max, SpacePlan.FullRender(1600, 1000))\n                .ExpectCanvasTranslate(0, 0)\n                .ExpectChildDraw(new Size(1600, 1000))\n                .ExpectCanvasTranslate(0, 0)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenChildPartiallyRenders_RightToLeft()\n        {\n            TestPlan\n                .For(x => new Unconstrained\n                {\n                    Child = x.CreateChild(),\n                    ContentDirection = ContentDirection.RightToLeft\n                })\n                .DrawElement(new Size(900, 800))\n                .ExpectChildMeasure(Size.Max, SpacePlan.PartialRender(1200, 1600))\n                .ExpectCanvasTranslate(-1200, 0)\n                .ExpectChildDraw(new Size(1200, 1600))\n                .ExpectCanvasTranslate(1200, 0)\n                .CheckDrawResult();\n        }\n        \n        [Test]\n        public void Draw_WhenChildFullyRenders_RightToLeft()\n        {\n            TestPlan\n                .For(x => new Unconstrained\n                {\n                    Child = x.CreateChild(),\n                    ContentDirection = ContentDirection.RightToLeft\n                })\n                .DrawElement(new Size(900, 800))\n                .ExpectChildMeasure(Size.Max, SpacePlan.FullRender(1600, 1000))\n                .ExpectCanvasTranslate(-1600, 0)\n                .ExpectChildDraw(new Size(1600, 1000))\n                .ExpectCanvasTranslate(1600, 0)\n                .CheckDrawResult();\n        }\n        \n        #endregion\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.UnitTests/UnitConversionTests.cs",
    "content": "using System.Collections.Generic;\nusing NUnit.Framework;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.UnitTests;\n\n[TestFixture]\npublic class UnitConversionTests\n{\n    [TestCase(Unit.Point, 1f, 1f)]\n    [TestCase(Unit.Inch, 1f, 72f)]\n    [TestCase(Unit.Feet, 1f, 864f)]\n    [TestCase(Unit.Mil, 1000f, 72f)]\n    [TestCase(Unit.Centimetre, 2.54f, 72f)]      // 2.54 cm = 1 inch\n    [TestCase(Unit.Millimetre, 25.4f, 72f)]      // 25.4 mm = 1 inch\n    [TestCase(Unit.Meter, 0.0254f, 72f)]         // 0.0254 m = 1 inch\n    public void ToPoints_ConvertsCorrectly(Unit unit, float input, float expected)\n    {\n        var result = input.ToPoints(unit);\n        Assert.That(result, Is.EqualTo(expected));\n        \n        var result2 = (input * 2).ToPoints(unit);\n        Assert.That(result2, Is.EqualTo(expected * 2));\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.VisualTests/LineTests.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.VisualTests;\n\npublic class LineTests\n{\n    [Test]\n    public void ThicknessHorizontal(\n        [Values(1, 2, 4, 8)] float thickness)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(100)\n                .Column(column =>\n                {\n                    column.Item().Height(50).Background(Colors.Blue.Lighten4);\n                    column.Item().LineHorizontal(thickness);\n                    column.Item().Height(50).Background(Colors.Green.Lighten4);\n                });\n        });\n    }\n    \n    [Test]\n    public void ThicknessVertical(\n        [Values(1, 2, 4, 8)] float thickness)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Height(100)\n                .Row(row =>\n                {\n                    row.AutoItem().Width(50).Background(Colors.Blue.Lighten4);\n                    row.AutoItem().LineVertical(thickness);\n                    row.AutoItem().Width(50).Background(Colors.Green.Lighten4);\n                });\n        });\n    }\n    \n    private static readonly IEnumerable<Color> ColorValues = [Colors.Red.Medium, Colors.Green.Medium, Colors.Blue.Medium];\n\n    [Test]\n    public void Color(\n        [ValueSource(nameof(ColorValues))] Color color)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(100)\n                .LineHorizontal(4)\n                .LineColor(color);\n        });\n    }\n\n    private static readonly IEnumerable<Color[]> GradientValues =\n    [\n        [Colors.Red.Medium, Colors.Green.Medium],\n        [Colors.Red.Medium, Colors.Yellow.Medium, Colors.Green.Medium],\n        [Colors.Blue.Medium, Colors.LightBlue.Medium, Colors.Cyan.Medium, Colors.Teal.Medium, Colors.Green.Medium]\n    ];\n    \n    [Test]\n    public void Gradient(\n        [ValueSource(nameof(GradientValues))] Color[] colors)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(400)\n                .LineHorizontal(16)\n                .LineGradient(colors);\n        });\n    }\n\n    private static readonly IEnumerable<float[]> DashPatternCases =\n    [\n        [1, 1],\n        [1, 2],\n        [2, 1],\n        [2, 2],\n        [4, 4],\n        [8, 8],\n        [4, 4, 12, 4],\n        [4, 4, 8, 8, 12, 12],\n    ];\n    \n    [Test, TestCaseSource(nameof(DashPatternCases))]\n    public void DashPattern(float[] dashPattern)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(400)\n                .LineHorizontal(4)\n                .LineDashPattern(dashPattern);\n        });\n    }\n    \n    [Test]\n    public void Complex()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(300)\n                .LineHorizontal(8)\n                .LineDashPattern([4, 4, 8, 8, 12, 12])\n                .LineGradient([Colors.Red.Medium, Colors.Orange.Medium, Colors.Yellow.Medium]);\n        });\n    }\n    \n    #region IStateful\n    \n    [Test]\n    public void LineShouldRenderOnlyOnce()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Height(400)\n                .Width(400)\n                .Row(row =>\n                {\n                    row.RelativeItem().LineHorizontal(10);\n                    row.RelativeItem().Column(column =>\n                    {\n                        column.Item().Height(300).Background(Colors.Blue.Lighten1);\n                        column.Item().Height(200).Background(Colors.Blue.Lighten3);\n                    });\n                });\n        });\n    }\n    \n    [Test]\n    public void LineShouldRerenderWhenCombinedWithRepeat()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Height(400)\n                .Width(400)\n                .Row(row =>\n                {\n                    row.RelativeItem().Repeat().LineHorizontal(10);\n                    row.RelativeItem().Column(column =>\n                    {\n                        column.Item().Height(300).Background(Colors.Blue.Lighten1);\n                        column.Item().Height(200).Background(Colors.Blue.Lighten3);\n                    });\n                });\n        });\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.VisualTests/QuestPDF.VisualTests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <ImplicitUsings>enable</ImplicitUsings>\n        <Nullable>enable</Nullable>\n        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n        <SatelliteResourceLanguages>en</SatelliteResourceLanguages>\n\n        <IsPackable>false</IsPackable>\n        <IsTestProject>true</IsTestProject>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.13.0\" />\n        <PackageReference Include=\"NUnit\" Version=\"4.4.0\" />\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"4.11.2\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"6.1.0\" />\n        <PackageReference Include=\"SkiaSharp\" Version=\"3.119.1\" />\n        <PackageReference Include=\"SkiaSharp.NativeAssets.Linux.NoDependencies\" Version=\"3.119.1\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <ProjectReference Include=\"..\\QuestPDF\\QuestPDF.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <Using Include=\"NUnit.Framework\"/>\n    </ItemGroup>\n\n    <ItemGroup>\n        <None Include=\"Resources\\**\\*.*\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n        </None>\n    </ItemGroup>\n\n    <ItemGroup>\n        <None Include=\"ExpectedOutput\\**\\*.*\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n        </None>\n    </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF.VisualTests/RotateTests.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.VisualTests;\n\npublic class RotateTests\n{\n    [Test]\n    public void Rotate(\n        [Values(-15, 0, 30, 45, 60, 90)] int angle)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(300)\n                .Height(300)\n                .AlignCenter()\n                .AlignMiddle()\n                .Unconstrained()\n                \n                .Rotate(angle) // <-\n                \n                .TranslateX(-100)\n                .TranslateY(-50)\n                .Width(200)\n                .Height(100)\n                .Background(Colors.Grey.Lighten3)\n                .AlignCenter()\n                .AlignMiddle()\n                .Text($\"Rotation: {angle} deg\");\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.VisualTests/SimpleRotateTests.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\n\nnamespace QuestPDF.VisualTests;\n\npublic class SimpleRotateTests\n{\n    [Test]\n    public void Rotate(\n        [Values(0, 1, 2, 3)] int rotationCount)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(150)\n                .Height(150)\n                .Element(element =>\n                {\n                    foreach (var i in Enumerable.Range(0, rotationCount))\n                        element = element.RotateRight();\n    \n                    return element;\n                })\n                .Shrink()\n                .Background(Colors.Grey.Lighten3)\n                .Padding(10)\n                .Text($\"Rotation #{rotationCount}\");\n        });\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.VisualTests/StyledBoxTests.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.VisualTests;\n\npublic class StyledBoxTests\n{\n    #region Background\n\n    private static readonly IEnumerable<Color> BackgroundColorValues = [ Colors.Red.Medium, Colors.Green.Medium, Colors.Blue.Medium ];\n    \n    [Test, TestCaseSource(nameof(BackgroundColorValues))]\n    public void BackgroundColor(Color color)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(200)\n                .Height(100)\n                .Background(color);\n        });\n    }\n\n    private static readonly IEnumerable<Color[]> BackgroundGradientColorsValues =\n    [\n        [Colors.Red.Medium, Colors.Green.Darken2],\n        [Colors.Red.Medium, Colors.Yellow.Medium, Colors.Green.Medium],\n        [Colors.Blue.Medium, Colors.LightBlue.Medium, Colors.Cyan.Medium, Colors.Teal.Medium, Colors.Green.Medium]\n    ];\n    \n    [Test, TestCaseSource(nameof(BackgroundGradientColorsValues))]\n    public void BackgroundGradientColors(Color[] gradientColors)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(200)\n                .Height(100)\n                .BackgroundLinearGradient(0, gradientColors);\n        });\n    }\n    \n    [Test]\n    public void BackgroundGradientAngle(\n        [Values(0, 30, 45, 60, 90)] float angle)\n    {\n        var gradient = new[]\n        {\n            Colors.Black,\n            Colors.White\n        };\n\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(200)\n                .Height(100)\n                .BackgroundLinearGradient(angle, gradient);\n        });\n    }\n    \n    [Test]\n    public void BackgroundUniformRoundedCorners(\n        [Values(0, 5, 10, 25, 50, 100)] float radius)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(200)\n                .Height(100)\n                .Background(Colors.Grey.Medium)\n                .CornerRadius(radius);\n        });\n    }\n    \n    [TestCase(0, 10, 20, 40)]\n    [TestCase(10, 20, 40, 0)]\n    [TestCase(20, 40, 0, 10)]\n    [TestCase(40, 0, 10, 20)]\n    public void BackgroundRoundedCorners(float topLeft, float topRight, float bottomRight, float bottomLeft)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(200)\n                .Height(100)\n                .Background(Colors.Grey.Medium)\n                .CornerRadiusTopLeft(topLeft)\n                .CornerRadiusTopRight(topRight)\n                .CornerRadiusBottomRight(bottomRight)\n                .CornerRadiusBottomLeft(bottomLeft);\n        });\n    }\n    \n    #endregion\n    \n    #region Border\n    \n    [Test]\n    public void BorderThicknessUniform(\n        [Values(1, 2, 4, 8)] float thickness)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(100)\n                .Height(100)\n                .Border(thickness)\n                .BorderColor(Colors.Black)\n                .Background(Colors.Grey.Lighten2);\n        });\n    }\n    \n    [Test]\n    public void BorderThickness(\n        [Values(0, 2)] float left, \n        [Values(0, 4)] float top, \n        [Values(0, 6)] float right, \n        [Values(0, 8)] float bottom)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(100)\n                .Height(100)\n                .BorderLeft(left)\n                .BorderTop(top)\n                .BorderRight(right)\n                .BorderBottom(bottom)\n                .BorderColor(Colors.Black)\n                .Background(Colors.Grey.Lighten2);\n        });\n    }\n    \n    [Test]\n    public void BorderRoundedCornersUniform(\n        [Values(0, 5, 10, 25, 50, 100)] float radius)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(200)\n                .Height(100)\n                .Border(2)\n                .CornerRadius(radius)\n                .BorderColor(Colors.Black)\n                .Background(Colors.Grey.Lighten2);\n        });\n    }\n    \n    [Test]\n    public void BorderRoundedCornersWithVariousCornerRadius(\n        [Values(0, 5)] float left,\n        [Values(0, 5)] float top,\n        [Values(0, 5)] float right,\n        [Values(0, 5)] float bottom,\n        [Values(5, 15)] float roundedRadius)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(100)\n                .Height(50)\n                .BorderLeft(left)\n                .BorderTop(top)\n                .BorderRight(right)\n                .BorderBottom(bottom)\n                .CornerRadius(roundedRadius)\n                .Background(Colors.Blue.Lighten3);\n        });\n    }\n    \n    public static readonly IEnumerable<Color> BorderColorCases = [ Colors.Red.Medium, Colors.Green.Medium, Colors.Blue.Medium ];\n    \n    [Test, TestCaseSource(nameof(BorderColorCases))]\n    public void BorderColor(Color color)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(200)\n                .Height(100)\n                .Border(5)\n                .BorderColor(color)\n                .Background(Colors.Grey.Lighten2);\n        });\n    }\n\n    private static readonly IEnumerable<Color[]> BorderGradientColorsValues =\n    [\n        [Colors.Red.Medium, Colors.Green.Darken2],\n        [Colors.Red.Medium, Colors.Yellow.Medium, Colors.Green.Medium],\n        [Colors.Blue.Medium, Colors.LightBlue.Medium, Colors.Cyan.Medium, Colors.Teal.Medium, Colors.Green.Medium]\n    ];\n    \n    [Test, TestCaseSource(nameof(BorderGradientColorsValues))]\n    public void BorderGradientColors(Color[] gradientColors)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(200)\n                .Height(100)\n                .Border(10)\n                .CornerRadius(5)\n                .BorderLinearGradient(0, gradientColors)\n                .Background(Colors.Grey.Lighten2);\n        });\n    }\n    \n    [Test]\n    public void BorderGradientAngle(\n        [Values(0, 30, 45, 60, 90)] float angle)\n    {\n        var gradient = new[]\n        {\n            Colors.Black,\n            Colors.White\n        };\n\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(200)\n                .Height(100)\n                .Border(10)\n                .CornerRadius(5)\n                .BorderLinearGradient(angle, gradient);\n        });\n    }\n    \n    private void BorderAlignmentTest(Func<IContainer, IContainer> configuration)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(200)\n                .Height(100)\n                .Border(10)\n                .CornerRadius(10)\n                .BorderColor(Colors.Black.WithAlpha(0.5f))\n                .Apply(configuration)\n                .Background(Colors.Blue.Lighten3);\n        });\n    }\n    \n    [Test]\n    public void BorderAlignmentInside()\n    {\n        BorderAlignmentTest(x => x.BorderAlignmentInside());\n    }\n    \n    [Test]\n    public void BorderAlignmentMiddle()\n    {\n        BorderAlignmentTest(x => x.BorderAlignmentMiddle());\n    }\n    \n    [Test]\n    public void BorderAlignmentOutside()\n    {\n        BorderAlignmentTest(x => x.BorderAlignmentOutside());\n    }\n    \n    #endregion\n    \n    #region Shadow\n    \n    private static readonly IEnumerable<Color> ShadowColorValues = [ Colors.Red.Medium, Colors.Green.Medium, Colors.Blue.Medium ];\n    \n    [Test, TestCaseSource(nameof(ShadowColorValues))]\n    public void ShadowColor(Color shadowColor)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(200)\n                .Height(100)\n                .Background(Colors.White)\n                .Shadow(new BoxShadowStyle\n                {\n                    Color = shadowColor,\n                    Blur = 8\n                });\n        });\n    }\n    \n    [Test]\n    public void ShadowBlur(\n        [Values(2, 4, 8, 16)] float blur)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(100)\n                .Height(50)\n                .Background(Colors.White)\n                .Shadow(new BoxShadowStyle\n                {\n                    Color = Colors.Grey.Darken2,\n                    Blur = blur,\n                });\n        });\n    }\n    \n    [Test]\n    public void ShadowWithoutBlur(\n        [Values] bool applyRoundedCorners, \n        [Values] bool applySpread, \n        [Values] bool applyOffset)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(100)\n                .Height(50)\n                .CornerRadius(applyRoundedCorners ? 20f : 0f)\n                .Background(Colors.LightBlue.Medium)\n                .Shadow(new BoxShadowStyle\n                {\n                    Color = Colors.Grey.Darken2,\n                    OffsetX = applyOffset ? 4f : 0f,\n                    OffsetY = applyOffset ? 4f : 0f,\n                    Spread = applySpread ? 8f : 0f,\n                });\n        });\n    }\n    \n    [Test]\n    public void ShadowSpread(\n        [Values(-4, 0, 4, 8, 12)] float spread)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(100)\n                .Height(100)\n                .Background(Colors.White)\n                .Shadow(new BoxShadowStyle\n                {\n                    Color = Colors.Grey.Darken2,\n                    Blur = 4,\n                    Spread = spread\n                });\n        });\n    }\n    \n    [Test]\n    public void ShadowOffsetX(\n        [Values(-8, -4, 0, 4, 8)] float offsetX)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(100)\n                .Height(100)\n                .Background(Colors.White)\n                .Shadow(new BoxShadowStyle\n                {\n                    Color = Colors.Grey.Darken2,\n                    Blur = 8,\n                    OffsetX = offsetX\n                });\n        });\n    }\n    \n    [Test]\n    public void ShadowOffsetY(\n        [Values(-8, -4, 0, 4, 8)] float offsetY)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(100)\n                .Height(100)\n                .Background(Colors.White)\n                .Shadow(new BoxShadowStyle\n                {\n                    Color = Colors.Grey.Darken2,\n                    Blur = 8,\n                    OffsetY = offsetY\n                });\n        });\n    }\n    \n    #endregion\n    \n    #region Clipping\n    \n    [Test]\n    public void ClipImage()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(200)\n                .CornerRadius(25)\n                .Shadow(new BoxShadowStyle\n                {\n                    Color = Colors.Grey.Darken2,\n                    Blur = 8\n                })\n                .Image(\"Resources/gradient.png\");\n        });\n    }\n    \n    [Test]\n    public void ClipText()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(300)\n                .Border(2, Colors.Black)\n                .CornerRadius(75)\n                .Text(Placeholders.LoremIpsum());\n        });\n    }\n    \n    [Test]\n    public void ClipContent()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(400)\n                .Border(2, Colors.Black)\n                .CornerRadius(150)\n                .Table(table =>\n                {\n                    table.ColumnsDefinition(columns =>\n                    {\n                        foreach (var i in Enumerable.Range(1, 10))\n                            columns.RelativeColumn();\n                    });\n\n                    foreach (var i in Enumerable.Range(0, 100))\n                    {\n                        table.Cell()\n                            .Border(1)\n                            .Padding(5)\n                            .AlignCenter()\n                            .Text(i.ToString());\n                    }\n                });\n        });\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.VisualTests/TestsSetup.cs",
    "content": "﻿using QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.VisualTests\n{\n    [SetUpFixture]\n    public class TestsSetup\n    {\n        [OneTimeSetUp]\n        public static void Setup()\n        {\n            var currentRuntime = NativeDependencyProvider.GetRuntimePlatform();\n\n            if (currentRuntime != \"osx-arm64\")\n            {\n                Assert.Ignore(\n                    \"Visual tests are performed based on osx-arm64 runtime output. \" +\n                    \"Each operating system (Windows, Linux, macOS) uses different font analysis and text rendering libraries. \" +\n                    \"Moreover, each CPU architecture may produce slightly different floating-point calculation results. \" +\n                    \"This may lead to different results even though the same code and configuration are used. \" +\n                    \"Therefore, visual tests are not expected to pass entirely on other operating systems or CPU architectures.\");\n            }\n                \n            QuestPDF.Settings.License = LicenseType.Community;\n            QuestPDF.Settings.UseEnvironmentFonts = false;\n            \n            VisualTestEngine.ClearActualOutputDirectories();\n        }\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.VisualTests/TextStyleTests.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.VisualTests;\n\npublic class TextStyleTests\n{\n    private static readonly IEnumerable<Color> FontColor_Values = [ Colors.Red.Darken3, Colors.Green.Darken3, Colors.Blue.Darken3 ];\n    \n    [Test, TestCaseSource(nameof(FontColor_Values))]\n    public void FontsColor(Color fontColor)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>  \n                {\n                    text.Span(\"Text can be displayed in different \");\n                    text.Span(\"font colors\").FontColor(fontColor);\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    private static readonly IEnumerable<Color> BackgroundColor_Values = [ Colors.Red.Lighten4, Colors.Green.Lighten4, Colors.Blue.Lighten4 ];\n    \n    [Test, TestCaseSource(nameof(BackgroundColor_Values))]\n    public void BackgroundColor(Color backgroundColor)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>  \n                {\n                    text.Span(\"Text can be displayed with different \");\n                    text.Span(\"background colors\").BackgroundColor(backgroundColor);\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontSize([Values(12, 16, 24)] float fontSize)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>  \n                {\n                    text.Span(\"Text can be displayed in different \");\n                    text.Span($\"font sizes ({fontSize}pt)\").FontSize(fontSize);\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    [Test]\n    public void LineHeight([Values(0.75f, 1f, 1.5f)] float lineHeight)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(400)\n                .Text(text =>  \n                {\n                    text.Span($\"Line height: {lineHeight}\\n\\n\").Bold().FontColor(Colors.Blue.Darken2);\n                    text.Span(Placeholders.LoremIpsum()).LineHeight(lineHeight);\n                });\n        });\n    }\n    \n    [Test]\n    public void WordSpacing([Values(-0.1f, 0f, 0.25f, 1f)] float wordSpacing)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Width(400)\n                .Text(text =>  \n                {\n                    text.Span($\"Word spacing: {wordSpacing}\\n\\n\").Bold().FontColor(Colors.Blue.Darken2);\n                    text.Span(Placeholders.LoremIpsum()).WordSpacing(wordSpacing);\n                });\n        });\n    }\n    \n    [Test]\n    public void LetterSpacing([Values(-0.1f, 0f, 0.1f, 0.25f)] float letterSpacing)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Width(400)\n                .Text(text =>  \n                {\n                    text.Span($\"Letter spacing: {letterSpacing}\\n\\n\").Bold().FontColor(Colors.Blue.Darken2);\n                    text.Span(Placeholders.LoremIpsum()).LetterSpacing(letterSpacing);\n                });\n        });\n    }\n    \n    [Test]\n    public void Italic()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        { \n            container\n                .Text(text =>  \n                {\n                    text.Span(\"The \");\n                    text.Span(\"italic effect\").Italic();\n                    text.Span(\" slants the letters slightly to the right.\");\n                });\n        });\n    }\n    \n    #region Font Decoration\n    \n    [Test]\n    public void FontDecoration_Underline()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"Text can be decorated with \");\n                    text.Span(\"an underline\").Underline().DecorationThickness(2).DecorationColor(Colors.Red.Medium);\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontDecoration_Strikethrough()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"Text can be decorated with \");\n                    text.Span(\"a strikeout\").Strikethrough().DecorationThickness(2).DecorationColor(Colors.Red.Medium);\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontDecoration_Overline()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"Text can be decorated with \");\n                    text.Span(\"an overline\").Overline().DecorationThickness(2).DecorationColor(Colors.Red.Medium);\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontDecoration_Combined()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"Text may have \");\n\n                    text.Span(\"multiple decoration\")\n                        .Underline()\n                        .Strikethrough()\n                        .Overline()\n                        .DecorationThickness(2)\n                        .DecorationColor(Colors.Blue.Medium);\n                    \n                    text.Span(\" applied to it.\");\n                });\n        });\n    }\n    \n    private static readonly IEnumerable<Color> FontDecoration_Color_Values = [ Colors.Red.Medium, Colors.Green.Medium, Colors.Blue.Medium ];\n    \n    [Test, TestCaseSource(nameof(FontDecoration_Color_Values))]\n    public void FontDecoration_Color(Color decorationColor)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"The color of \");\n                    text.Span(\"the text decoration\").Underline().DecorationDashed().DecorationThickness(2).DecorationColor(decorationColor);\n                    text.Span(\" can be changed.\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontDecoration_Thickness([Values(1f, 2f, 3f)] float thickness)\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"The thickness of \");\n                    text.Span(\"the text decoration\").Underline().DecorationWavy().DecorationThickness(thickness).DecorationColor(Colors.Red.Medium);\n                    text.Span(\" can be changed.\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontDecoration_Solid()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a solid-line text decoration\").Underline().DecorationSolid();\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontDecoration_Double()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a double-line text decoration\").Underline().DecorationDouble();\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontDecoration_Wavy()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a wavy-line text decoration\").Underline().DecorationWavy();\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontDecoration_Dotted()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a dotted text decoration\").Underline().DecorationDotted();\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontDecoration_Dashed()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a dashed text decoration\").Underline().DecorationDashed();\n                    text.Span(\".\");\n                });\n        });\n    }\n    \n    #endregion\n    \n    #region Font Weight\n    \n    [Test]\n    public void FontWeight_200_ExtraLight()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"an extra-light\").ExtraLight().BackgroundColor(Colors.Grey.Lighten3);\n                    text.Span(\" font weight.\");\n                });\n        }); \n    }\n    \n    [Test]\n    public void FontWeight_300_Light()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a light\").Light().BackgroundColor(Colors.Grey.Lighten3);\n                    text.Span(\" font weight.\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontWeight_400_Regular()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a regular\").NormalWeight().BackgroundColor(Colors.Grey.Lighten3);\n                    text.Span(\" font weight.\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontWeight_500_Medium()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a medium\").Medium().BackgroundColor(Colors.Grey.Lighten3);\n                    text.Span(\" font weight.\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontWeight_600_SemiBold()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a semi-bold\").SemiBold().BackgroundColor(Colors.Grey.Lighten3);\n                    text.Span(\" font weight.\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontWeight_700_Bold()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"a bold\").Bold().BackgroundColor(Colors.Grey.Lighten3);\n                    text.Span(\" font weight.\");\n                });\n        });\n    }\n    \n    [Test]\n    public void FontWeight_800_ExtraBold()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"This example shows \");\n                    text.Span(\"an extra-bold\").ExtraBold().BackgroundColor(Colors.Grey.Lighten3 );\n                    text.Span(\" font weight.\");\n                });\n        });\n    }\n    \n    #endregion\n    \n    #region Font Position\n    \n    [Test]\n    public void FontPosition_Subscript()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"Chemical formula of sulfuric acid: H\");\n                    text.Span(\"2\").Subscript();\n                    text.Span(\"SO\");\n                    text.Span(\"4\").Subscript();\n                    text.Span(\".\");\n                });\n        });\n    }\n\n    [Test]\n    public void FontPosition_Superscript()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(text =>\n                {\n                    text.Span(\"Enstein's equation: E=mc\");\n                    text.Span(\"2\").Superscript(); \n                });\n        });\n    }\n    \n    #endregion\n    \n    #region Font Features\n    \n    [Test]\n    public void FontFeatures_StandardLigatures_Enabled()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(\"final\")\n                .EnableFontFeature(FontFeatures.StandardLigatures);\n        });\n    }\n\n    [Test]\n    public void FontFeatures_StandardLigatures_Disabled()\n    {\n        VisualTest.PerformWithDefaultPageSettings(container =>\n        {\n            container\n                .Text(\"final\")\n                .DisableFontFeature(FontFeatures.StandardLigatures);\n        });\n    }\n    \n    #endregion\n}"
  },
  {
    "path": "Source/QuestPDF.VisualTests/VisualTestEngine.cs",
    "content": "using System.Globalization;\nusing System.Text.RegularExpressions;\nusing QuestPDF.Fluent;\nusing QuestPDF.Helpers;\nusing QuestPDF.Infrastructure;\nusing SkiaSharp;\n\nnamespace QuestPDF.VisualTests;\n\npublic static class Helpers\n{\n    public static TOutput Apply<TInput, TOutput>(this TInput input, Func<TInput, TOutput> func)\n    {\n        return func(input);\n    }\n}\n\npublic static class ImageComparer\n{\n    public static bool AreImagesIdentical(SKBitmap bitmap1, SKBitmap bitmap2)\n    {\n        if (bitmap1.Width != bitmap2.Width || bitmap1.Height != bitmap2.Height)\n        {\n            Assert.Fail(\"Different image sizes: \" +\n                        $\"Image 1: {bitmap1.Width}x{bitmap1.Height}, \" +\n                        $\"Image 2: {bitmap2.Width}x{bitmap2.Height}\");\n        }\n\n        if (bitmap1.ColorType != bitmap2.ColorType)\n        {\n            Assert.Fail(\"Different image color types: \" +\n                        $\"Image 1: {bitmap1.ColorType}, \" +\n                        $\"Image 2: {bitmap2.ColorType}\");\n        }\n\n        var pixels1 = bitmap1.Pixels;\n        var pixels2 = bitmap2.Pixels;\n\n        if (pixels1.Length != pixels2.Length)\n        {\n            Assert.Fail(\"Different image pixel counts: \" +\n                        $\"Image 1: {pixels1.Length}, \" +\n                        $\"Image 2: {pixels2.Length}\");\n        }\n            \n        var differences = pixels1.Zip(pixels2, (p1, p2) => new[] {p1.Red - p2.Red, p1.Green - p2.Green, p1.Blue - p2.Blue, p1.Alpha - p2.Alpha })\n            .Select(x => x.Select(Math.Abs))\n            .Select(x => x.Max())\n            .Where(diff => diff > 0)\n            .ToArray();\n        \n\n\n        if (differences.Length > 0)\n        {\n            var min = differences.Min();\n            var max = differences.Max();\n            var average = differences.Average(x => x);\n            var message = $\"Images differ by {min} (min), {max} (max), {average:F2} (avg). Different pixels: {differences.Length}.\";\n            Assert.Fail(message);\n        }\n        \n        for (var i = 0; i < pixels1.Length; i++)\n        {\n            if (pixels1[i] != pixels2[i])\n                return false;\n        }\n        \n        return true;\n    }\n    \n    public static bool AreImagesIdentical(byte[] imageData1, byte[] imageData2)\n    {\n        using var bitmap1 = SKBitmap.Decode(imageData1);\n        using var bitmap2 = SKBitmap.Decode(imageData2);\n        \n        return AreImagesIdentical(bitmap1, bitmap2);\n    }\n}\n\npublic static class VisualTestEngine\n{\n    private static string ActualOutputDirectoryName => Path.Combine(TestContext.CurrentContext.TestDirectory, \"ActualOutput\");\n    private static string ExpectedOutputDirectoryName => Path.Combine(TestContext.CurrentContext.TestDirectory, \"ExpectedOutput\");\n    \n    private static readonly Regex TestNameRegex = new(@\"QuestPDF\\.VisualTests\\.(?<name>.*)Tests\");\n    \n    public static void ClearActualOutputDirectories()\n    {\n        if (Directory.Exists(ActualOutputDirectoryName))\n            Directory.Delete(ActualOutputDirectoryName, true);\n    }\n    \n    public static void ShouldMatchExpectedImage(this IDocument document)\n    {\n        if (TestContext.CurrentContext.Test.ClassName == null)\n            throw new Exception(\"Test class name is not set.\");\n        \n        var match = TestNameRegex.Match(TestContext.CurrentContext.Test.ClassName);\n        var testCategory = match.Groups[\"name\"].Value;\n        \n        var imageGenerationSettings = new ImageGenerationSettings\n        {\n            ImageFormat = ImageFormat.Png,\n            RasterDpi = 144\n        };\n        \n        var actualImages = document.GenerateImages(imageGenerationSettings).ToList();\n        var hasMultipleImages = actualImages.Count > 1;\n        \n        var actualOutputPath = Path.Combine(ActualOutputDirectoryName, testCategory);\n        var expectedOutputPath = Path.Combine(ExpectedOutputDirectoryName, testCategory);\n        \n        var testName = TestContext.CurrentContext.Test.Name;\n        \n        Directory.CreateDirectory(actualOutputPath);\n\n        string GetFileName(int index)\n        {\n            return hasMultipleImages ? $\"{testName}_{index}.png\" : $\"{testName}.png\";\n        }\n        \n        foreach (var i in Enumerable.Range(0, actualImages.Count))\n        {\n            var actualImagePath = Path.Combine(actualOutputPath, GetFileName(i));\n            File.WriteAllBytes(actualImagePath, actualImages[i]);\n        }\n        \n        if (!Directory.Exists(expectedOutputPath))\n            Assert.Inconclusive(\"Cannot find the expected output folder\");\n        \n        var expectedOutputFileCount = Directory.EnumerateFiles(expectedOutputPath, $\"{testName}*.png\").Count();\n        \n        if (actualImages.Count != expectedOutputFileCount)\n            Assert.Fail($\"Generated {actualImages.Count} images but expected {expectedOutputFileCount}\");\n\n        foreach (var i in Enumerable.Range(0, actualImages.Count))\n        {\n            var expectedImagePath = Path.Combine(expectedOutputPath, GetFileName(i));\n            \n            if (!File.Exists(expectedImagePath))\n                Assert.Fail($\"Cannot find expected image file {expectedImagePath}\");\n            \n            var expectedImageBytes = File.ReadAllBytes(expectedImagePath);\n            var actualImageBytes = actualImages[i];\n\n            var imagesAreIdentical = ImageComparer.AreImagesIdentical(actualImageBytes, expectedImageBytes);\n\n            if (imagesAreIdentical) \n                continue;\n            \n            var pageText = actualImages.Count > 1 ? $\" (page {i})\" : string.Empty;\n            Assert.Fail($\"Generated image does not match expected image{pageText}.\");\n        }\n    }\n}\n\npublic static class VisualTest\n{\n    public static void Perform(Action<IDocumentContainer> documentBuilder)\n    {\n        SetUpCultureInfoToInvariant();\n        \n        Document\n            .Create(documentBuilder)\n            .ShouldMatchExpectedImage();\n    }\n    \n    public static void PerformWithDefaultPageSettings(Action<IContainer> contentBuilder)\n    {\n        SetUpCultureInfoToInvariant();\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.MinSize(new PageSize(0, 0));\n                    page.MaxSize(new PageSize(1000, 1000));\n                    page.Margin(20);\n                    \n                    page.PageColor(Colors.White);\n                    page.DefaultTextStyle(x => x.FontSize(16));\n                    \n                    page.Content().Element(contentBuilder);\n                });\n            })\n            .ShouldMatchExpectedImage();\n    }\n\n    private static void SetUpCultureInfoToInvariant()\n    {\n        Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;\n        Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;\n        \n        CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;\n        CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ZUGFeRD/GenerationTest.cs",
    "content": "using QuestPDF.Fluent;\nusing QuestPDF.Infrastructure;\n\nnamespace QuestPDF.ZUGFeRD;\n\npublic class Tests\n{\n    [Test]\n    public void ZUGFeRD_Test()\n    {\n        // TODO: Please make sure that you are eligible to use the Community license.\n        // To learn more about the QuestPDF licensing, please visit:\n        // https://www.questpdf.com/pricing.html\n        QuestPDF.Settings.License = LicenseType.Community;\n        \n        Document\n            .Create(document =>\n            {\n                document.Page(page =>\n                {\n                    page.Content().Text(\"Your invoice content\");\n                });\n            })\n            .WithMetadata(new DocumentMetadata\n            {\n                Title = \"Conformance Test: ZUGFeRD\",\n                Author = \"SampleCompany\",\n                Subject = \"ZUGFeRD Test Document\",\n                Language = \"en-US\"\n            })\n            .WithSettings(new DocumentSettings { PdfA = true }) // PDF/A-3b\n            .GeneratePdf(\"invoice.pdf\");\n        \n        DocumentOperation\n            .LoadFile(\"invoice.pdf\")\n            .AddAttachment(new DocumentOperation.DocumentAttachment\n            {\n                Key = \"factur-zugferd\",\n                FilePath = \"resource-factur-x.xml\",\n                AttachmentName = \"factur-x.xml\",\n                MimeType = \"text/xml\",\n                Description = \"Factur-X Invoice\",\n                Relationship = DocumentOperation.DocumentAttachmentRelationship.Source,\n                CreationDate = DateTime.UtcNow,\n                ModificationDate = DateTime.UtcNow\n            })\n            .ExtendMetadata(File.ReadAllText(\"resource-zugferd-metadata.xml\"))\n            .Save(\"zugferd-invoice.pdf\");\n    }\n}"
  },
  {
    "path": "Source/QuestPDF.ZUGFeRD/QuestPDF.ZUGFeRD.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <TargetFramework>net10.0</TargetFramework>\n        <ImplicitUsings>enable</ImplicitUsings>\n        <Nullable>enable</Nullable>\n        <SatelliteResourceLanguages>en</SatelliteResourceLanguages>\n        <IsPackable>false</IsPackable>\n        <IsTestProject>true</IsTestProject>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.13.0\" />\n        <PackageReference Include=\"NUnit\" Version=\"4.4.0\" />\n        <PackageReference Include=\"NUnit.Analyzers\" Version=\"4.11.2\">\n          <PrivateAssets>all</PrivateAssets>\n          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n        </PackageReference>\n        <PackageReference Include=\"NUnit3TestAdapter\" Version=\"6.1.0\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <Using Include=\"NUnit.Framework\"/>\n    </ItemGroup>\n\n    <ItemGroup>\n        <ProjectReference Include=\"..\\QuestPDF\\QuestPDF.csproj\"/>\n    </ItemGroup>\n\n    <ItemGroup>\n        <None Update=\"resource-factur-x.xml\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n        </None>\n        <None Update=\"resource-zugferd-metadata.xml\">\n            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n        </None>\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Source/QuestPDF.ZUGFeRD/resource-factur-x.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<rsm:CrossIndustryInvoice xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\" xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">\n    <rsm:ExchangedDocumentContext>\n        <ram:GuidelineSpecifiedDocumentContextParameter>\n            <ram:ID>urn:cen.eu:en16931:2017</ram:ID>\n        </ram:GuidelineSpecifiedDocumentContextParameter>\n    </rsm:ExchangedDocumentContext>\n    <rsm:ExchangedDocument>\n        <ram:ID>RE-20201121/508</ram:ID>\n        <ram:TypeCode>380</ram:TypeCode>\n        <ram:IssueDateTime>\n            <udt:DateTimeString format=\"102\">20201121</udt:DateTimeString>\n        </ram:IssueDateTime>\n    </rsm:ExchangedDocument>\n    <rsm:SupplyChainTradeTransaction>\n        <ram:IncludedSupplyChainTradeLineItem>\n            <ram:AssociatedDocumentLineDocument>\n                <ram:LineID>1</ram:LineID>\n            </ram:AssociatedDocumentLineDocument>\n            <ram:SpecifiedTradeProduct>\n                <ram:Name>Design (hours)</ram:Name>\n                <ram:Description>Of a sample invoice</ram:Description>\n            </ram:SpecifiedTradeProduct>\n            <ram:SpecifiedLineTradeAgreement>\n                <ram:GrossPriceProductTradePrice>\n                    <ram:ChargeAmount>160.0000</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"HUR\">1.0000</ram:BasisQuantity>\n                </ram:GrossPriceProductTradePrice>\n                <ram:NetPriceProductTradePrice>\n                    <ram:ChargeAmount>160.0000</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"HUR\">1.0000</ram:BasisQuantity>\n                </ram:NetPriceProductTradePrice>\n            </ram:SpecifiedLineTradeAgreement>\n            <ram:SpecifiedLineTradeDelivery>\n                <ram:BilledQuantity unitCode=\"HUR\">1.0000</ram:BilledQuantity>\n            </ram:SpecifiedLineTradeDelivery>\n            <ram:SpecifiedLineTradeSettlement>\n                <ram:ApplicableTradeTax>\n                    <ram:TypeCode>VAT</ram:TypeCode>\n                    <ram:CategoryCode>S</ram:CategoryCode>\n                    <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>\n                </ram:ApplicableTradeTax>\n                <ram:SpecifiedTradeSettlementLineMonetarySummation>\n                    <ram:LineTotalAmount>160.00</ram:LineTotalAmount>\n                </ram:SpecifiedTradeSettlementLineMonetarySummation>\n            </ram:SpecifiedLineTradeSettlement>\n        </ram:IncludedSupplyChainTradeLineItem>\n        <ram:IncludedSupplyChainTradeLineItem>\n            <ram:AssociatedDocumentLineDocument>\n                <ram:LineID>2</ram:LineID>\n            </ram:AssociatedDocumentLineDocument>\n            <ram:SpecifiedTradeProduct>\n                <ram:Name>Ballons</ram:Name>\n                <ram:Description>various colors, ~2000ml</ram:Description>\n            </ram:SpecifiedTradeProduct>\n            <ram:SpecifiedLineTradeAgreement>\n                <ram:GrossPriceProductTradePrice>\n                    <ram:ChargeAmount>0.7900</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"H87\">1.0000</ram:BasisQuantity>\n                </ram:GrossPriceProductTradePrice>\n                <ram:NetPriceProductTradePrice>\n                    <ram:ChargeAmount>0.7900</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"H87\">1.0000</ram:BasisQuantity>\n                </ram:NetPriceProductTradePrice>\n            </ram:SpecifiedLineTradeAgreement>\n            <ram:SpecifiedLineTradeDelivery>\n                <ram:BilledQuantity unitCode=\"H87\">400.0000</ram:BilledQuantity>\n            </ram:SpecifiedLineTradeDelivery>\n            <ram:SpecifiedLineTradeSettlement>\n                <ram:ApplicableTradeTax>\n                    <ram:TypeCode>VAT</ram:TypeCode>\n                    <ram:CategoryCode>S</ram:CategoryCode>\n                    <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>\n                </ram:ApplicableTradeTax>\n                <ram:SpecifiedTradeSettlementLineMonetarySummation>\n                    <ram:LineTotalAmount>316.00</ram:LineTotalAmount>\n                </ram:SpecifiedTradeSettlementLineMonetarySummation>\n            </ram:SpecifiedLineTradeSettlement>\n        </ram:IncludedSupplyChainTradeLineItem>\n        <ram:IncludedSupplyChainTradeLineItem>\n            <ram:AssociatedDocumentLineDocument>\n                <ram:LineID>3</ram:LineID>\n            </ram:AssociatedDocumentLineDocument>\n            <ram:SpecifiedTradeProduct>\n                <ram:Name>Hot air „heiße Luft“ (litres)</ram:Name>\n                <ram:Description/>\n            </ram:SpecifiedTradeProduct>\n            <ram:SpecifiedLineTradeAgreement>\n                <ram:GrossPriceProductTradePrice>\n                    <ram:ChargeAmount>0.0250</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"LTR\">1.0000</ram:BasisQuantity>\n                </ram:GrossPriceProductTradePrice>\n                <ram:NetPriceProductTradePrice>\n                    <ram:ChargeAmount>0.0250</ram:ChargeAmount>\n                    <ram:BasisQuantity unitCode=\"LTR\">1.0000</ram:BasisQuantity>\n                </ram:NetPriceProductTradePrice>\n            </ram:SpecifiedLineTradeAgreement>\n            <ram:SpecifiedLineTradeDelivery>\n                <ram:BilledQuantity unitCode=\"LTR\">800.0000</ram:BilledQuantity>\n            </ram:SpecifiedLineTradeDelivery>\n            <ram:SpecifiedLineTradeSettlement>\n                <ram:ApplicableTradeTax>\n                    <ram:TypeCode>VAT</ram:TypeCode>\n                    <ram:CategoryCode>S</ram:CategoryCode>\n                    <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>\n                </ram:ApplicableTradeTax>\n                <ram:SpecifiedTradeSettlementLineMonetarySummation>\n                    <ram:LineTotalAmount>20.00</ram:LineTotalAmount>\n                </ram:SpecifiedTradeSettlementLineMonetarySummation>\n            </ram:SpecifiedLineTradeSettlement>\n        </ram:IncludedSupplyChainTradeLineItem>\n        <ram:ApplicableHeaderTradeAgreement>\n            <ram:BuyerReference>AB321</ram:BuyerReference>\n            <ram:SellerTradeParty>\n                <ram:Name>Bei Spiel GmbH</ram:Name>\n                <ram:PostalTradeAddress>\n                    <ram:PostcodeCode>12345</ram:PostcodeCode>\n                    <ram:LineOne>Ecke 12</ram:LineOne>\n                    <ram:CityName>Stadthausen</ram:CityName>\n                    <ram:CountryID>DE</ram:CountryID>\n                </ram:PostalTradeAddress>\n                <ram:SpecifiedTaxRegistration>\n                    <ram:ID schemeID=\"VA\">DE136695976</ram:ID>\n                </ram:SpecifiedTaxRegistration>\n            </ram:SellerTradeParty>\n            <ram:BuyerTradeParty>\n                <ram:ID>2</ram:ID>\n                <ram:Name>Theodor Est</ram:Name>\n                <ram:PostalTradeAddress>\n                    <ram:PostcodeCode>88802</ram:PostcodeCode>\n                    <ram:LineOne>Bahnstr. 42</ram:LineOne>\n                    <ram:CityName>Spielkreis</ram:CityName>\n                    <ram:CountryID>DE</ram:CountryID>\n                </ram:PostalTradeAddress>\n            </ram:BuyerTradeParty>\n        </ram:ApplicableHeaderTradeAgreement>\n        <ram:ApplicableHeaderTradeDelivery>\n            <ram:ActualDeliverySupplyChainEvent>\n                <ram:OccurrenceDateTime>\n                    <udt:DateTimeString format=\"102\">20201110</udt:DateTimeString>\n                </ram:OccurrenceDateTime>\n            </ram:ActualDeliverySupplyChainEvent>\n        </ram:ApplicableHeaderTradeDelivery>\n        <ram:ApplicableHeaderTradeSettlement>\n            <ram:PaymentReference>RE-20201121/508</ram:PaymentReference>\n            <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>\n            <ram:SpecifiedTradeSettlementPaymentMeans>\n                <ram:TypeCode>42</ram:TypeCode>\n                <ram:Information>Bank transfer</ram:Information>\n                <ram:PayeePartyCreditorFinancialAccount>\n                    <ram:IBANID>DE88200800000970375700</ram:IBANID>\n                    <ram:AccountName>Max Mustermann</ram:AccountName>\n                </ram:PayeePartyCreditorFinancialAccount>\n                <ram:PayeeSpecifiedCreditorFinancialInstitution>\n                    <ram:BICID>COBADEFFXXX</ram:BICID>\n                </ram:PayeeSpecifiedCreditorFinancialInstitution>\n            </ram:SpecifiedTradeSettlementPaymentMeans>\n            <ram:ApplicableTradeTax>\n                <ram:CalculatedAmount>11.20</ram:CalculatedAmount>\n                <ram:TypeCode>VAT</ram:TypeCode>\n                <ram:BasisAmount>160.00</ram:BasisAmount>\n                <ram:CategoryCode>S</ram:CategoryCode>\n                <ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>\n            </ram:ApplicableTradeTax>\n            <ram:ApplicableTradeTax>\n                <ram:CalculatedAmount>63.84</ram:CalculatedAmount>\n                <ram:TypeCode>VAT</ram:TypeCode>\n                <ram:BasisAmount>336.00</ram:BasisAmount>\n                <ram:CategoryCode>S</ram:CategoryCode>\n                <ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>\n            </ram:ApplicableTradeTax>\n            <ram:SpecifiedTradePaymentTerms>\n                <ram:Description>Zahlbar ohne Abzug bis 12.12.2020</ram:Description>\n                <ram:DueDateDateTime>\n                    <udt:DateTimeString format=\"102\">20201212</udt:DateTimeString>\n                </ram:DueDateDateTime>\n            </ram:SpecifiedTradePaymentTerms>\n            <ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n                <ram:LineTotalAmount>496.00</ram:LineTotalAmount>\n                <ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>\n                <ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>\n                <ram:TaxBasisTotalAmount>496.00</ram:TaxBasisTotalAmount>\n                <ram:TaxTotalAmount currencyID=\"EUR\">75.04</ram:TaxTotalAmount>\n                <ram:GrandTotalAmount>571.04</ram:GrandTotalAmount>\n                <ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>\n                <ram:DuePayableAmount>571.04</ram:DuePayableAmount>\n            </ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n        </ram:ApplicableHeaderTradeSettlement>\n    </rsm:SupplyChainTradeTransaction>\n</rsm:CrossIndustryInvoice>\n"
  },
  {
    "path": "Source/QuestPDF.ZUGFeRD/resource-zugferd-metadata.xml",
    "content": "<rdf:Description xmlns:fx=\"urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#\" rdf:about=\"\">\n    <fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>\n    <fx:DocumentType>INVOICE</fx:DocumentType>\n    <fx:DocumentFileName>factur-x.xml</fx:DocumentFileName>\n    <fx:Version>1.0</fx:Version>\n</rdf:Description>\n<rdf:Description xmlns:pdfaExtension=\"http://www.aiim.org/pdfa/ns/extension/\"\n                 xmlns:pdfaProperty=\"http://www.aiim.org/pdfa/ns/property#\"\n                 xmlns:pdfaSchema=\"http://www.aiim.org/pdfa/ns/schema#\"\n                 rdf:about=\"\">\n<pdfaExtension:schemas>\n    <rdf:Bag>\n        <rdf:li rdf:parseType=\"Resource\">\n            <pdfaSchema:schema>ZUGFeRD PDFA Extension Schema</pdfaSchema:schema>\n            <pdfaSchema:namespaceURI>urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#</pdfaSchema:namespaceURI>\n            <pdfaSchema:prefix>fx</pdfaSchema:prefix>\n            <pdfaSchema:property>\n                <rdf:Seq>\n                    <rdf:li rdf:parseType=\"Resource\">\n                        <pdfaProperty:name>DocumentFileName</pdfaProperty:name>\n                        <pdfaProperty:valueType>Text</pdfaProperty:valueType>\n                        <pdfaProperty:category>external</pdfaProperty:category>\n                        <pdfaProperty:description>name of the embedded XML invoice file</pdfaProperty:description>\n                    </rdf:li>\n                    <rdf:li rdf:parseType=\"Resource\">\n                        <pdfaProperty:name>DocumentType</pdfaProperty:name>\n                        <pdfaProperty:valueType>Text</pdfaProperty:valueType>\n                        <pdfaProperty:category>external</pdfaProperty:category>\n                        <pdfaProperty:description>INVOICE</pdfaProperty:description>\n                    </rdf:li>\n                    <rdf:li rdf:parseType=\"Resource\">\n                        <pdfaProperty:name>Version</pdfaProperty:name>\n                        <pdfaProperty:valueType>Text</pdfaProperty:valueType>\n                        <pdfaProperty:category>external</pdfaProperty:category>\n                        <pdfaProperty:description>The actual version of the ZUGFeRD XML schema</pdfaProperty:description>\n                    </rdf:li>\n                    <rdf:li rdf:parseType=\"Resource\">\n                        <pdfaProperty:name>ConformanceLevel</pdfaProperty:name>\n                        <pdfaProperty:valueType>Text</pdfaProperty:valueType>\n                        <pdfaProperty:category>external</pdfaProperty:category>\n                        <pdfaProperty:description>The selected ZUGFeRD profile completeness</pdfaProperty:description>\n                    </rdf:li>\n                </rdf:Seq>\n            </pdfaSchema:property>\n        </rdf:li>\n    </rdf:Bag>\n</pdfaExtension:schemas>\n</rdf:Description>"
  },
  {
    "path": "Source/QuestPDF.slnx",
    "content": "<Solution>\n  <Folder Name=\"/Configuration/\">\n    <File Path=\".editorconfig\" />\n  </Folder>\n  <Project Path=\"QuestPDF.Companion.TestRunner/QuestPDF.Companion.TestRunner.csproj\" />\n  <Project Path=\"QuestPDF.ConformanceTests/QuestPDF.ConformanceTests.csproj\" />\n  <Project Path=\"QuestPDF.DocumentationExamples/QuestPDF.DocumentationExamples.csproj\" />\n  <Project Path=\"QuestPDF.LayoutTests/QuestPDF.LayoutTests.csproj\" />\n  <Project Path=\"QuestPDF.ReportSample/QuestPDF.ReportSample.csproj\" />\n  <Project Path=\"QuestPDF.UnitTests/QuestPDF.UnitTests.csproj\" />\n  <Project Path=\"QuestPDF.VisualTests/QuestPDF.VisualTests.csproj\" />\n  <Project Path=\"QuestPDF.ZUGFeRD/QuestPDF.ZUGFeRD.csproj\" />\n  <Project Path=\"QuestPDF/QuestPDF.csproj\" />\n</Solution>\n"
  },
  {
    "path": "Source/global.json",
    "content": "{\n  \"sdk\": {\n    \"version\": \"10.0.0\",\n    \"rollForward\": \"latestMinor\",\n    \"allowPrerelease\": true\n  }\n}"
  },
  {
    "path": "Source/nuget.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n    <packageSources>\n        <clear />\n        <add key=\"nuget.org\" value=\"https://api.nuget.org/v3/index.json\" protocolVersion=\"3\" />\n    </packageSources>\n</configuration>"
  }
]