diff --git a/LICENSE b/LICENSE index 7300e256..03b0a374 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2001-2024 empira Software GmbH, Troisdorf (Cologne Area), Germany +Copyright (c) 2001-2026 empira Software GmbH, Troisdorf (Cologne Area), Germany http://docs.pdfsharp.net diff --git a/PdfSharp.sln b/PdfSharp.sln index 8795a23f..3c82ce5b 100644 --- a/PdfSharp.sln +++ b/PdfSharp.sln @@ -104,6 +104,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{31FE507C-F342-4DA4-9BE5-B3D2ED93E9CC}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + gitversion-6.x.yml = gitversion-6.x.yml gitversion.yml = gitversion.yml LICENSE = LICENSE README.md = README.md diff --git a/PdfSharp.sln.DotSettings b/PdfSharp.sln.DotSettings index a8032f59..1415191e 100644 --- a/PdfSharp.sln.DotSettings +++ b/PdfSharp.sln.DotSettings @@ -14,6 +14,13 @@ TSA URI URL + None + True + BUG + Warning + True + TODO + Edit True ID True @@ -40,6 +47,7 @@ True True True + True True True True @@ -50,6 +58,7 @@ True True True + True True True True diff --git a/README.md b/README.md index 69aaeea8..5d069c92 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # PDFsharp & MigraDoc 6 -Version **6.2.0 Preview 2** -Published **2024-12-10** +Version **6.2.4** +Published **2026-01-06** -This is a preview version of the **PDFsharp** project, the main project of PDFsharp & MigraDoc 6 with updates for C# 12 and .NET 6. +This is a final version of the **PDFsharp** project, the main project of PDFsharp & MigraDoc 6 with updates for C# 12 and .NET 8, .NET 9, and .NET 10. -PDFsharp: Copyright (c) 2005-2024 empira Software GmbH, Troisdorf (Cologne Area), Germany -MigraDoc: Copyright (c) 2001-2024 empira Software GmbH, Troisdorf (Cologne Area), Germany +PDFsharp: Copyright (c) 2005-2026 empira Software GmbH, Troisdorf (Cologne Area), Germany +MigraDoc: Copyright (c) 2001-2026 empira Software GmbH, Troisdorf (Cologne Area), Germany Published Open Source under the [MIT License](https://docs.pdfsharp.net/LICENSE.html) For more information see [docs.pdfsharp.net](https://docs.pdfsharp.net/) diff --git a/dev/build-local-nuget-packages-release.ps1 b/dev/build-local-nuget-packages-release.ps1 index d6eeba5b..14be2328 100644 --- a/dev/build-local-nuget-packages-release.ps1 +++ b/dev/build-local-nuget-packages-release.ps1 @@ -19,18 +19,18 @@ try { Push-Location .. try { - Write-Host "Invoking ’dotnet build’" + Write-Host "Invoking ‘dotnet build’" dotnet build -c release $build = $LASTEXITCODE - Write-Host "’dotnet build’ has finished" + Write-Host "‘dotnet build’ has finished" } finally { Pop-Location } if ($build -gt 0) { - Write-Host "’dotnet build’ failed with code " $build - throw "’dotnet build’ failed with code " + $build + Write-Host "‘dotnet build’ failed with code " $build + throw "‘dotnet build’ failed with code " + $build } .\update-local-nuget-packages-release.ps1 diff --git a/dev/run-tests.ps1 b/dev/run-tests.ps1 index 44caf47a..685d0982 100644 --- a/dev/run-tests.ps1 +++ b/dev/run-tests.ps1 @@ -4,15 +4,15 @@ .DESCRIPTION The script builds the solution located in the script’s root parent folder and runs 'dotnet test' for all libraries to test, that are found via its projects. - These tests are run in the following environment, as far as available: Windows with NET8 or NET6, Windows with NET462 and Linux/WSL (NET8 or NET6). + These tests are run in the following environment, as far as available: Windows with NET8 or NET10, Windows with NET462 and Linux/WSL (NET8 or NET10). For each environment, libraries not to be run (like WPF in Linux or Linux-targeting DLLs in Windows) are excluded from testing. The test results are displayed in tables per library / code base comparing the test results in the different environments. .PARAMETER Config Specifies the configuration to build and test the solution ("Debug" or "Release"). "Debug" is the default. -.PARAMETER Net6 - Specifies whether NET6 shall be tested instead of NET8. $False is the default. +.PARAMETER Net10 + Specifies whether NET10 shall be tested instead of NET8. $False is the default. .PARAMETER SkipBuild Specifies whether the build of the solution shall be skipped. $False is the default. @@ -68,7 +68,7 @@ BUG: Allow to run all tests, including GBE. param ( [Parameter(Mandatory = $false)] [string]$Config = 'Debug', - [Parameter(Mandatory = $false)] [bool]$Net6 = $false, + [Parameter(Mandatory = $false)] [bool]$Net10 = $false, [Parameter(Mandatory = $false)] [bool]$SkipBuild = $false, [Parameter(Mandatory = $false)] [bool]$RunAllTests = $false ) @@ -77,7 +77,7 @@ $script:SystemNameWindows = "Windows" $script:SystemNameLinux = "Linux" $script:SystemNameWsl = "WSL" $script:NetName462 = "net462" -$script:NetName6 = "net6" +$script:NetName10 = "net10" $script:NetName8 = "net8" @@ -112,9 +112,9 @@ function InitializeScript() exit } - Write-Host - Write-Host "Started run-tests for solution `"$script:Solution`"." - Write-Host + Write-Output "" + Write-Output "Started run-tests for solution `"$script:Solution`"." + Write-Output "" $script:TimeStart = Get-Date $script:ConsoleWidth = $Host.UI.RawUI.WindowSize.Width @@ -167,43 +167,43 @@ function InitializeScript() } # Output current system information. - Write-Host - Write-Host "Started script in $script:SystemNameHost." + Write-Output "" + Write-Output "Started script in $script:SystemNameHost." if ($script:RunOnHostedWsl) { - Write-Host "Tests will be run on $script:SystemNameHost host and hosted $script:SystemNameCurrentLinux." + Write-Output "Tests will be run on $script:SystemNameHost host and hosted $script:SystemNameCurrentLinux." } else { - Write-Host "Tests will be run on $script:SystemNameHost host only." + Write-Output "Tests will be run on $script:SystemNameHost host only." } - Write-Host + Write-Output "" - if ($script:Net6) + if ($script:Net10) { - Write-Host "NET6 Tests will be run instead of NET8." - Write-Host + Write-Output "NET10 Tests will be run instead of NET8." + Write-Output "" } if ($script:SkipBuild) { - Write-Host "Building solution in $script:Config build will be skipped." - Write-Host + Write-Output "Building solution in $script:Config build will be skipped." + Write-Output "" } if ($script:RunAllTests) { $env:PDFsharpTests = "runalltests" $script:EnvironmentForHostedWsl = "PDFsharpTests=runalltests" - Write-Host "Running all tests of solution." + Write-Output "Running all tests of solution." } else { $env:PDFsharpTests = $null $script:EnvironmentForHostedWsl = "PDFsharpTests=$null" - Write-Host "Skipping slow tests of solution." + Write-Output "Skipping slow tests of solution." } - Write-Host + Write-Output "" CheckNetRuntimes } @@ -231,8 +231,8 @@ function CheckNetRuntime($isWsl) $wslOrLocal = "the local machine" } - if ($script:Net6) { - $netMajorVersion = 6; + if ($script:Net10) { + $netMajorVersion = 10; } else { $netMajorVersion = 8; @@ -263,10 +263,10 @@ function BuildSolution() return } - Write-Host - Write-Host "Building solution in $script:Config build" - Write-Host ================================================== - Write-Host + Write-Output "" + Write-Output "Building solution in $script:Config build" + Write-Output ================================================== + Write-Output "" dotnet build $script:Solution -c $script:Config RestoreForegroundColor # The dotnet call may change the foreground color, e. g. when displaying test result exceptions. @@ -276,29 +276,31 @@ function BuildSolution() # Loads DllInfo objects for all DLLs of the solution to run dotnet test for and saves the Windows and Linux specific lists. function LoadTestDllInfos() { - Write-Host - Write-Host "Analyzing Solution to find test DLLs" - Write-Host ================================================== - Write-Host + Write-Output "" + Write-Output "Analyzing Solution to find test DLLs" + Write-Output ================================================== + Write-Output "" $dllInfos = GetDllInfos $testDllInfos = $dllInfos | Where-Object { $_.IsTestDll } - # If Net6 parameter is true, remove net8 DLLs. - if ($script:Net6) + # If Net10 parameter is true, remove net8 DLLs. + if ($script:Net10) { $testDllInfos = $testDllInfos | Where-Object ` { $_.TargetFramework.Contains("net8") -eq $false + $_.TargetFramework.Contains("net9") -eq $false } } - # If Net6 parameter is false, remove net6 DLLs. + # If Net10 parameter is false, remove net10 DLLs. else { $testDllInfos = $testDllInfos | Where-Object ` { - $_.TargetFramework.Contains("net6") -eq $false + $_.TargetFramework.Contains("net10") -eq $false + $_.TargetFramework.Contains("net9") -eq $false } } @@ -352,9 +354,9 @@ function OutputTestDlls($testDllInfos, $systemName) { $testDllsOutput = $testDllInfos | Select-Object -Property DllFileName, EnvironmentName, DllFolder - Write-Host "DLLs to test in $systemName found in `"$script:Solution`":" - Write-Host ---------------------------------------- - Write-Host ($testDllsOutput | Format-Table | Out-String) + Write-Output "DLLs to test in $systemName found in `"$script:Solution`":" + Write-Output ---------------------------------------- + Write-Output ($testDllsOutput | Format-Table | Out-String) } # Gets DllInfo objects for all DLLs of the solution. @@ -543,9 +545,9 @@ function RunTests() # Runs dotnet test for all needed DLLs for the given $systemName. function RunTestsForSystem($testDllInfos, $systemName, $isHostedWsl) { - Write-Host - Write-Host Running tests on $systemName - Write-Host ================================================== + Write-Output "" + Write-Output Running tests on $systemName + Write-Output ================================================== foreach ($testDllInfo in $testDllInfos) { # Work with absolute DLL path here to avoid errors. @@ -565,10 +567,10 @@ function RunTestsForSystem($testDllInfos, $systemName, $isHostedWsl) $TestResultsFilename = GetTestResultsFilename $testDllInfo.EnvironmentName - Write-Host - Write-Host ($systemName): dotnet test $testDllInfo.DllFileName ("(" + $testDllInfo.TargetFramework + ")")... - Write-Host ---------------------------------------- - Write-Host + Write-Output "" + Write-Output ($systemName): dotnet test $testDllInfo.DllFileName ("(" + $testDllInfo.TargetFramework + ")")... + Write-Output ---------------------------------------- + Write-Output "" # Change current location to store the trx file in the default "TestResults" folder inside the project folder. Push-Location $testDllInfo.ProjectFolder @@ -590,18 +592,18 @@ function RunTestsForSystem($testDllInfos, $systemName, $isHostedWsl) Pop-Location } } - Write-Host - Write-Host + Write-Output "" + Write-Output "" } # Gets the name of the environment for the given system and framework. function GetEnvironmentName($systemName, $targetFramework) { - if ($script:Net6 -and $targetFramework.Contains("net6")) + if ($script:Net10 -and $targetFramework.Contains("net10")) { - $frameworkName = $script:NetName6 + $frameworkName = $script:NetName10 } - elseif ($script:Net6 -eq $false -and $targetFramework.Contains("net8")) + elseif ($script:Net10 -eq $false -and $targetFramework.Contains("net8")) { $frameworkName = $script:NetName8 } @@ -617,13 +619,13 @@ function GetEnvironmentName($systemName, $targetFramework) # HACK: For Linux the frameworkName shall not be shown. if ($systemName -eq $script:SystemNameCurrentLinux) { - if ($script:Net6 -and $frameworkName -ne "net6") + if ($script:Net10 -and $frameworkName -ne "net10") { - Write-Error ("For Linux there’s only one column supported (net6) by test script with Net6 parameter set to true.") + Write-Error ("For Linux there’s only one column supported (net10) by test script with Net10 parameter set to true.") } - elseif ($script:Net6 -eq $false -and $frameworkName -ne "net8") + elseif ($script:Net10 -eq $false -and $frameworkName -ne "net8") { - Write-Error ("For Linux there’s only one column supported (net8) by test script with Net6 parameter set to false.") + Write-Error ("For Linux there’s only one column supported (net8) by test script with Net10 parameter set to false.") } return "$systemName" } @@ -662,14 +664,15 @@ function GetTestResultsFilename($environmentName) # Loads the trx files and displays the test results. function LoadAndShowTestResults() { - Write-Host - Write-Host - Write-Host "TestResults" -ForegroundColor Green # Green color is used to make it the same conspicuity like the given green Format-Table header output. - Write-Host "==================================================" -ForegroundColor Green + # TODO -ForegroundColor Green # Green color is used to make it the same conspicuity like the given green Format-Table header output. + Write-Output "" + Write-Output "" + Write-Output "TestResults" + Write-Output "==================================================" - if ($script:Net6) + if ($script:Net10) { - $netNameX = $script:NetName6 + $netNameX = $script:NetName10 } else { @@ -737,12 +740,13 @@ function LoadAndShowTestResults() $genericCodeBaseWithExtension = $genericCodeBaseInfo.GenericCodeBase + $genericCodeBaseInfo.GenericCodeBaseExtension - Write-Host - Write-Host + # TODO -ForegroundColor Green # Green color is used to make it the same conspicuity like the given green Format-Table header output. + Write-Output "" + Write-Output "" $title = ("CodeBase:").PadRight($padValue + 1, ' ') - Write-Host $title $genericCodeBaseWithExtension -ForegroundColor Green # Green color is used to make it the same conspicuity like the given green Format-Table header output. - Write-Host "----------------------------------------------------------------------------------------------------" -ForegroundColor Green - Write-Host Test files: + Write-Output $title $genericCodeBaseWithExtension + Write-Output "----------------------------------------------------------------------------------------------------" + Write-Output Test files: $codeBaseResults = @() # Collects all results for this GenericCodeBase. @@ -768,18 +772,18 @@ function LoadAndShowTestResults() # If the project is not targeting this environment. if ($notTargetingEnvironment) { - Write-Host $title Not implemented. + Write-Output $title Not implemented. } # If trx file is not found or outdated, output "No test results found" and continue loop. elseif ($testResultsFileExists -eq $false -or $testResultsFileOutdated) { $testResultsFile = $null - Write-Host $title No test results found. + Write-Output $title No test results found. } # If trx file is found and from this test run, collect results from the file. else { - Write-Host $title $testResultsFile + Write-Output $title $testResultsFile # Read trx content. [xml]$fileContent = Get-Content -Path $testResultsFile @@ -857,11 +861,12 @@ function LoadAndShowTestResults() # Add summary for all grouped test results. - Write-Host - Write-Host - Write-Host - Write-Host Summary -ForegroundColor Green # Green color is used to make it the same conspicuity like the given green Format-Table header output. - Write-Host "----------------------------------------------------------------------------------------------------" -ForegroundColor Green + # TODO -ForegroundColor Green # Green color is used to make it the same conspicuity like the given green Format-Table header output. + Write-Output "" + Write-Output "" + Write-Output "" + Write-Output Summary + Write-Output "----------------------------------------------------------------------------------------------------" # Create test summary from grouped test results. $summary = CreateTestSummary $allGroupedResults $environmentNames diff --git a/dev/set-en.ps1 b/dev/set-en.ps1 new file mode 100644 index 00000000..c5077ee6 --- /dev/null +++ b/dev/set-en.ps1 @@ -0,0 +1,16 @@ +# Sets UI language for dotnet build to en-US. +#Requires -Version 7 +#Requires -PSEdition Core + +# I want to see English messages on my German Windows dev machine +# when I run e.g. dotnet build. + +# What works: +$env:VSLANG = 1033 +Write-Output "Compiler output language set to en-US." + +# What does not work: +#$env:DOTNET_CLI_UI_LANG = 'en-US' +#$env:PreferredUILang = 'en-US' +#powershell -ExecutionPolicy Bypass -NoExit -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = 'en-US'; [System.Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US';" +#powershell -ExecutionPolicy Bypass -NoExit -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = 'en-US'; [System.Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US';" diff --git a/docs/Chars.md b/docs/Chars.md index bce9e51e..03ebbe84 100644 --- a/docs/Chars.md +++ b/docs/Chars.md @@ -4,6 +4,9 @@ · × ² ³ ½ € † … ✔ ✘ ↯ ± − × ÷ ⋅ √ ≠ ≤ ≥ ≡ ® © ← ↑ → ↓ ↔ ↕ ∅ + ✔⇒ + + Shaker´'´`’ás # Use of typographic quotation marks diff --git a/docs/MigraDoc/change-log/MD-v6.2.0-log.md b/docs/MigraDoc/change-log/MD-v6.2.0-log.md new file mode 100644 index 00000000..f820fd2c --- /dev/null +++ b/docs/MigraDoc/change-log/MD-v6.2.0-log.md @@ -0,0 +1,36 @@ +# MigraDoc 6.2.0 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **MigraDoc** `History.md`. + +## What’s new in version 6.2 + +### Breaking changes + +**Corrected bug with page orientation** +See *Issues* below. + +### Features + +**MigraDoc Preview user control restored for GDI build** +The MigraDoc Preview user control is again available in the GDI+ build. +MigraDoc Preview samples for GDI and WPF have been added to the samples repository. + +**Color.Parse no longer causes exceptions when invoked with a number value** +If Color.Parse is invoked with a number value, as in `var color = Color.Parse("#f00");`, +it no longer throws a handled exception internally. + +**MigraDoc: No more hard-coded fonts names** +It is now possible to control font names used by MigraDoc for error messages and characters for bullet lists. +PDFsharp 6.2.0 Preview 1 and earlier always used `Courier New` for error messages like Image not found and used hard-coded fonts for bullets. +[Read more](http://docs.pdfsharp.net/link/migradoc-font-resolving-6.2.html) + +### Issues + +**MigraDoc: Infinite loop in renderer** +We fixed a bug that led to an infinite loop in PDF Renderer. + +**Corrected bug with page orientation** +When opening and modifying existing PDF pages, there sometimes were issues due to page rotation and page orientation. +Behavior has changed for page format Ledger and apps supporting Ledger format must be tested and may have to be updated. +Behavior has also changed when you set a new page format or orientation after setting page height and/or page width, including modifying a *Clone()* of the *DefaultPageSetup*. The new method *ResetPageSize* should be called before setting *PageFormat* and *Orientation* for a "cloned" PageSetup. +These are breaking changes. diff --git a/docs/MigraDoc/change-log/MD-v6.2.1-log.md b/docs/MigraDoc/change-log/MD-v6.2.1-log.md new file mode 100644 index 00000000..dfdb779d --- /dev/null +++ b/docs/MigraDoc/change-log/MD-v6.2.1-log.md @@ -0,0 +1,17 @@ +# MigraDoc 6.2.1 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **MigraDoc** `History.md`. + +## What’s new in version 6.2.1 + +### Breaking changes + +*(none)* + +### Features + +The new formatting option of PDFsharp is also useful when generating PDF files from MigraDoc. + +### Issues + +The bug fixes of PDFsharp are also useful when generating PDF files from MigraDoc. diff --git a/docs/MigraDoc/change-log/MD-v6.2.2-log.md b/docs/MigraDoc/change-log/MD-v6.2.2-log.md new file mode 100644 index 00000000..9b62ac2e --- /dev/null +++ b/docs/MigraDoc/change-log/MD-v6.2.2-log.md @@ -0,0 +1,17 @@ +# MigraDoc 6.2.2 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **MigraDoc** `History.md`. + +## What’s new in version 6.2.2 + +### Breaking changes + +*(none)* + +### Features + +*(none)* + +### Issues + +The bug fixes of PDFsharp are also useful when generating PDF files from MigraDoc. diff --git a/docs/MigraDoc/change-log/MD-v6.2.3-log.md b/docs/MigraDoc/change-log/MD-v6.2.3-log.md new file mode 100644 index 00000000..216ec71e --- /dev/null +++ b/docs/MigraDoc/change-log/MD-v6.2.3-log.md @@ -0,0 +1,17 @@ +# MigraDoc 6.2.3 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **MigraDoc** `History.md`. + +## What’s new in version 6.2.3 + +### Breaking changes + +*(none)* + +### Features + +*(none)* + +### Issues + +The bug fixes of PDFsharp are also useful when generating PDF files from MigraDoc. diff --git a/docs/MigraDoc/change-log/MD-v6.2.4-log.md b/docs/MigraDoc/change-log/MD-v6.2.4-log.md new file mode 100644 index 00000000..c0155815 --- /dev/null +++ b/docs/MigraDoc/change-log/MD-v6.2.4-log.md @@ -0,0 +1,27 @@ +# MigraDoc 6.2.4 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **MigraDoc** `History.md`. + +## What’s new in version 6.2.4 + +### Breaking changes + +*(none)* + +### Features + +*(none)* + +### Issues + +**MigraDoc shows filename in PDF if image cannot be found** +If an image cannot be found, MigraDoc renders a placeholder for that image in PDF. +The placeholder now shows the path of the image that cannot be found. + +**Fixed MigraDoc memory leak after rendering PDF** +With MigraDoc 6.2.3, a reference to the MigraDoc Document was kept after rendering PDF. +Only a reference to the last document was kept. +So, when rendering 10 documents, 9 documents were released. +With MigraDoc 6.2.4, the MigraDoc Document is released after rendering. + +The bug fixes of PDFsharp are also useful when generating PDF files from MigraDoc. diff --git a/docs/MigraDoc/changes/v6.2.0-log.md b/docs/MigraDoc/changes/v6.2.0-log.md deleted file mode 100644 index 2bb645ad..00000000 --- a/docs/MigraDoc/changes/v6.2.0-log.md +++ /dev/null @@ -1,50 +0,0 @@ -# MigraDoc 6.2.0 change log - -## Version 6.2 - -MigraDoc changes come here. - -TODO / JUST A COPY OF PDFSHARP CHANTE LOG - -### PDFsharp 6.2.0 Preview 1 - -#### Features - -**Digital signatures** -PDF documents can now be signed with a digital signature. - -**Multi-colored glyphs** -Multi-colored glyphs like emojis are now supported. - -**.NET Framework 4.6.2** -All assemblies have downgraded .NET Framework references in `` from 4.7.2 to 4.6.2. -`net472` becomes `net462`. - -**.NET 8** -We added .NET 8 (`net8.0`) to ``. - -**PDF/A** -PDF documents can now be PDF/A conforming. We are still working on this feature, so currently there are some limitations. - -#### Bug fixes - -**Cleanup NuGet packages** -MigraDoc packages now depend on PDFsharp NuGet packages instead of including assemblies directly. -All packages now depend on e.g. `Microsoft.Extensions.Logging` instead of including the Microsoft assembly. - -**.restext files removed** -Some assemblies had a subfolder `de` containing German messages. -We removed all `.restext` resources. All messages are now available in US English only. - -**PDFsharp.Shared** -Code that grants friendly access to all PDFsharp Foundation assemblies lives in this new assembly. - -**Bug in parsing object referenced** -Lexer now supports white-space within object references. - -**Page orientation now works as expected** -The connection between page Width, Height, PageOrientation, and PageRotation was weird. -It was replaced by a consistent concept. -This is a breaking change. - -**CoreBuildFontResolver removed** diff --git a/docs/PDFsharp/change-log/PS-v6.2.0-log.md b/docs/PDFsharp/change-log/PS-v6.2.0-log.md new file mode 100644 index 00000000..225fd883 --- /dev/null +++ b/docs/PDFsharp/change-log/PS-v6.2.0-log.md @@ -0,0 +1,88 @@ +# PDFsharp 6.2.0 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **PDFsharp** `History.md`. + +## What’s new in version 6.2 + +### Breaking changes + +**Page orientation now works as expected** +See *Issues* below. + +### Features + +**Improved access to CropBox, ArtBox, BleedBox, TrimBox** +PdfPage now has new properties that make access to those boxes easier. +These are `HasBleedBox`, `BleedBoxReadOnly`, and `EffectiveBleedBoxReadOnly`. +Same applies to ArtBox, CropBox and TrimBox. + +**Loading images: Improved access to buffer of MemoryStream** +LoadImage from MemoryStream now works with a buffer that is not publicly visible. +For better performance, set 'publiclyVisible' to true when creating the MemoryStream. + +**MD5 replaced where possible** +The ImageSelector class needs hash codes for internal use. +We now use SHA1 instead of MD5 because MD5 is not FIPS-compliant and not supported everywhere. +Early PDF encryption uses MD5. So PDFsharp must use MD5 when opening files created with such early encryptions. +And PDFsharp must use MD5 when creating files with such early encryptions. + +**Inefficient reading of object streams** +Reading files with many objects in many object streams now works much faster. + +**Ignore incorrect "/Length" entry on streams close to EOF** +PDFsharp 6.2.0 Preview 1 failed if a PDF contained a stream close to the end of file with an incorrect /Length attribute. +PDFsharp 6.2.0 Preview 2 can correct the /Length attribute even for streams close to the end of the file. + +**ImageSelector improved** +We fixed incorrect handling of identical images with only different masks. + +**Issue with Google Slides** +PDFsharp can now open PDF files created from Google Slides. + +**Size of digital signature may vary without timestamp** +PDFsharp 6.2.0 Preview 1 took into account that the size of digital signatures with timestamp could vary from call to call. +PDFsharp 6.2.0 Preview 2 now takes into account that the size of digital signatures without timestamp can also vary from call to call. + +**Option to read images from non-seekable streams** +PDFsharp is now able to read images from streams that are not seekable. + +### Issues + +**Lexer.ScanNumber and CLexer.ScanNumber** +Based on a bug that crashed PDFsharp if a number in a PDFfile has too many leading zeros, we revised the code of **Lexer.ScanNumber** and **CLexer.ScanNumber**. + +**No more commas allowed in XUnit** +An old hack allowed **XUnit** to be assigned from a string that uses a comma as decimal separator. +This was introduced for languages like German that use a comma instead of a point as decimal separator. +Now you get an exception. Applies also to **XUnitPt**. + +**Bug fixes in PNG reader** +Fixed issues with reading PNG files in Core build. + +**Correct datetime format in XMP meta data** +Time zone was missing. + +**Handle Reverse Solidus without effect correctly** +The reverse solidus was handled incorrectly for invalid combinations of reverse solidus and other characters. + +**Fixes with encrypted PDFs** +Fixes for issues with encrypted PDFs. + +**Improved behavior or better error messages for streams with limited capabilities** +PDFsharp now shows better error messages when trying to read a PDF from streams that cannot seek, cannot report their length, or are otherwise limited. + +**Corrected bug with page orientation** +When opening and modifying existing PDF pages, there sometimes were issues due to page rotation and page orientation. +Behavior has changed for page format Ledger and apps supporting Ledger format must be tested and may have to be updated. +This is a breaking change. + +**BeginContainer issue fixed** +BeginContainer and EndContainer can now be used even in GDI build when drawing on PDF pages. + +**Bug in parsing object referenced** +Lexer now supports white-space within object references. + +**Page orientation now works as expected** +The connection between page Width, Height, PageOrientation, and PageRotation was weird. +It was replaced by a consistent concept. +This is a breaking change. diff --git a/docs/PDFsharp/change-log/PS-v6.2.1-log.md b/docs/PDFsharp/change-log/PS-v6.2.1-log.md new file mode 100644 index 00000000..c40e6171 --- /dev/null +++ b/docs/PDFsharp/change-log/PS-v6.2.1-log.md @@ -0,0 +1,38 @@ +# PDFsharp 6.2.1 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **PDFsharp** `History.md`. + +## What’s new in version 6.2 + +### Breaking changes + +*(none)* + +### Features + +**Formatting options for PDF files** +Using the *Options.Layout* member of the **PdfDocument** class, you can set how PDF files will be generated. +Use **PdfWriterLayout.Verbose** to get readable output. This is the default for Debug builds of PDFsharp. +Use **PdfWriterLayout.Compact** to get small output files. This is the default for Release builds of PDFsharp and should be used for production code. + +### Issues + +**Encrypted hyperlinks are now working** +We fixed a bug that caused PDF file encryption to throw an exception if the PDF file contained certain types of hyperlinks. + +**Character escaping for PDF names** +**PdfName** now correctly includes the curly braces ('{' and '}') in the list of characters to be escaped. + +**Fixed incorrect number formatting** +This bug could lead to incorrectly formatted Outline entries. + +**Fixed exception that occurred for files of size 1030 bytes** +PDFsharp can now open files with a size of 1030 bytes. + +**Arrays in PDF files are now written without line feeds** +When using **PdfWriterLayout.Compact**, arrays in PDF files will be written without line feeds. +The files with line feeds are technically correct, but we were informed that some printer software cannot handle those files correctly. + +**Keep both /A and /Dest entries for outlines in PDF** +According to the PDF Reference 1.7, an /A entry is not permitted if a /Dest entry is present. +PDFsharp 6.2.1 no longer deletes the /A entry if both are present. diff --git a/docs/PDFsharp/change-log/PS-v6.2.2-log.md b/docs/PDFsharp/change-log/PS-v6.2.2-log.md new file mode 100644 index 00000000..5937ddaf --- /dev/null +++ b/docs/PDFsharp/change-log/PS-v6.2.2-log.md @@ -0,0 +1,26 @@ +# PDFsharp 6.2.2 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **PDFsharp** `History.md`. + +## What’s new in version 6.2.2 + +### Breaking changes + +*(none)* + +### Features + +*(none)* + +### Issues + +**Fixed problem with JPEG images from MemoryStreams** +In special cases, JPEG images from a MemoryStream were not handled correctly. GitHub #303 + +**Avoid crash on ID duplicates in an object stream** +PDF files with duplicate IDs in an object stream were not handled correctly. +We consider such files corrupted, but PDFsharp should now handle them correctly. GitHub #296 + +**Fixed problems with signatures in DEBUG build** +The Debug build of PDFsharp adds comments to the generated PDF files. +This caused problems with the Signature field in PDFs, but was fixed now.Github #293 diff --git a/docs/PDFsharp/change-log/PS-v6.2.3-log.md b/docs/PDFsharp/change-log/PS-v6.2.3-log.md new file mode 100644 index 00000000..afd2054f --- /dev/null +++ b/docs/PDFsharp/change-log/PS-v6.2.3-log.md @@ -0,0 +1,23 @@ +# PDFsharp 6.2.3 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **PDFsharp** `History.md`. + +## What’s new in version 6.2.3 + +### Breaking changes + +*(none)* + +### Features + +*(none)* + +### Issues + +**Fixed problem with JPEG images from XImage.FromGdiPlusImage** +JPEG images created from GDI+ images were not handled correctly. GitHub #318 +This API is only available in the GDI+ build of PDFsharp. +It is recommended to avoid the *XImage.FromGdiPlusImage* API and use *XImage.FromFile* or *XImage.FromStream* instead if possible. + +**Avoid exception when reading certain corrupted files** +An incorrectly formatted logging string caused an exception when logging a warning about some corrupted PDF files. GitHub #290 diff --git a/docs/PDFsharp/change-log/PS-v6.2.4-log.md b/docs/PDFsharp/change-log/PS-v6.2.4-log.md new file mode 100644 index 00000000..1e8b7379 --- /dev/null +++ b/docs/PDFsharp/change-log/PS-v6.2.4-log.md @@ -0,0 +1,29 @@ +# PDFsharp 6.2.4 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **PDFsharp** `History.md`. + +## What’s new in version 6.2.4 + +### Breaking changes + +*(none)* + +### Features + +**Optional /Length entry for encryption added always** +The PDF viewer of Edge fails to open some encrypted PDF files if the /Length entry is not present. GitHub #261 +We now always add the /Length entry even in cases where it is optional according to PDF specifications. + +### Issues + +**CArray written without spaces** +When editing a content stream with an array, that CArray will now be saved with spaces. GitHub #300 + +**JPEG issue resolved** +JPEG JFIF files use "byte stuffing" and 0xff bytes may be followed by 0x00 bytes that must be ignored. +PDFsharp 6.2.4 now handles this 0xff 0x00 combination where PDFsharp up to 6.2.3 caused an exception. +GitHub #304, #309, #310 + +**Indirect DecodeParms now handled correctly** +PDFsharp 6.2.3 caused an exception if DecodeParms where specified as an indirect object. GitHub #323 +This indirection is valid, but very unusual. Fixed with 6.2.4. diff --git a/docs/_READ-THIS-FIRST.md b/docs/_READ-THIS-FIRST.md index eb240f7e..0094a1e9 100644 --- a/docs/_READ-THIS-FIRST.md +++ b/docs/_READ-THIS-FIRST.md @@ -1,6 +1,6 @@ # Read this first -This folder is **not* the documentation of PDFsharp. +This folder is ***not*** the documentation of PDFsharp. It contains internal technical information for/from the PDFsharp team. You find the documentation of PDFsharp [here](https://docs.pdfsharp.net/). \ No newline at end of file diff --git a/docs/change-log/README.md b/docs/change-log/README.md new file mode 100644 index 00000000..37810f73 --- /dev/null +++ b/docs/change-log/README.md @@ -0,0 +1,66 @@ +# README for logging changes + +## Rules for log files and docs.pdfsharp.net history content + +* There are **3 markdown files** to log the changes for the currently developed version: + * `gn-vX.X.X-log.md` for general changes + * `PS-vX.X.X-log.md` for PDFsharp specific changes + * `MD-vX.X.X-log.md` for MigraDoc specific changes +* All versions shall be sorted descending by date. +* The information about a **version** shall begin with the **heading** `What’s new in version X.x`. +* The information about a **preview version** shall begin with the **subheading** `PDFsharp X.X.X Preview X`. +* A horizontal line shall be included after each version and preview version. + +### Preview versions + +* Only The **log for the general changes** shall list the **preview versions separately** +* The changes of a preview version shall refer to the previous preview version, if existing - otherwise to previous version. +* The **PDFsharp and MigraDoc change logs** shall **not** list the preview versions separately. +All changes of a version (including its preview versions) shall be summarized thematically. +References to the preview version, a change was published with, shall be added to this text (e. g. `(since 6.2.0 PV3`). +* **If a "final" version is going to be released**, its **preview versions shall no longer be listed separately** in the general change log. +The changes shall be summarized like they are in the PDFsharp and MigraDoc change logs. + +### Version content + +#### General change log headings + +* **Breaking changes** + This shall **always** be included. + Explicitely write `There are no breaking changes.` if there are none. +* **General features** (optional) +* **General issues** (optional) +* Furthermore, there are headings for PDFsharp and MigraDoc specific changes. + The text here shall not go in detail and refer to the PDFsharp/MigraDoc specific history, where the change is explained. + * **PDFsharp features** (optional) + * **PDFsharp issues** (optional) + * **MigraDoc features** (optional) + * **MigraDoc issues** (optional) + +#### PDfsharp/MigraDoc change log headings + +* **Features** (optional) +* **Issues** (optional) + +### docs.pdfsharp.net + +* **If a version (or preview version) is released**, the content of the files shall be added to the **3 History.md files** in docs.pdfsharp.net. + Due to the summarization of the preview versions in the change log files, **only the general History.md file shall list preview versions separately, and only for a version, which is currently developed**. +* A horizontal line shall be included after each version. + +## Rules for version readme file + +A version readme file with the name `README-vX.X` shall be published on **docs.pdfsharp.net**. + +### Headings + +* **What’s new** + Shall **refer to the general History.md** published on docs.pdfsharp.net. + There’s **no need to to refer to the PDFsharp/MigraDoc specific Histroy.md**, as the general refers to them at its top. +* **Prerequisites** +* **Breaking changes** + This shall **always** be included. + Explicitely write `There are no breaking changes.` if there are none. + Should be a copy, summary or excerpt of the general History.md breaking changes. + At last, the **general History.md shall be referenced**. +* Perhaps further headings for additional information. \ No newline at end of file diff --git a/docs/change-log/gn-v6.2.0-log.md b/docs/change-log/gn-v6.2.0-log.md new file mode 100644 index 00000000..2624830d --- /dev/null +++ b/docs/change-log/gn-v6.2.0-log.md @@ -0,0 +1,82 @@ +# General 6.2.0 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **general** `History.md`. + +## What’s new in version 6.2 + +### Breaking changes + +**CoreBuildFontResolver removed** +See *General features* below. + +### General features + +**CoreBuildFontResolver removed** +The code was removed from PDFsharp but still exists in the samples repository. +To reactivate the old behavior under Windows, set *UseWindowsFontsUnderWindows* to true. +To reactivate the old behavior under WSL2, set *UseWindowsFontsUnderWsl2* to true. +Note that these settings only have an effect for the Core build. +Also note that these settings only have an effect under Windows or WSL2, respectively. +No fonts will be found under Linux or MacOS, so do not use these properties if you want to develop portable Core applications. + +```cs +GlobalFontSettings.UseWindowsFontsUnderWindows = true; +GlobalFontSettings.UseWindowsFontsUnderWsl2 = true; +``` + +The name is now SubstitutingFontResolver and it can be found in the PDFsharp.Samples repository. + +[Information about font resolving](https://docs.pdfsharp.net/PDFsharp/Topics/Fonts/Font-Resolving.html) + +**UTF-16LE** + +We had recently removed the code that reads UTF-16LE strings because that format was not mentioned in the PDF specs. +We found a PDF file created with Adobe PDF Library 18.0.3 that contains UTF-16 strings with a LE BOM. +PDFsharp now can again read UTF-16 strings with LE BOM. + +**Digital signatures** +PDF documents can now be signed with a digital signature. + +**Multi-colored glyphs** +Multi-colored glyphs like emojis are now supported. + +**.NET Framework 4.6.2** +All assemblies have downgraded .NET Framework references in `` from 4.7.2 to 4.6.2. +`net472` becomes `net462`. + +**.NET 8** +We added .NET 8 (`net8.0`) to ``. + +**PDF/A** +PDF documents can now be PDF/A conforming. We are still working on this feature, so currently there are some limitations. + +**PDFsharp.Shared** +Code that grants friendly access to all PDFsharp Project assemblies lives in this new assembly. + +### General issues + +**Support PDF files with indirect objects in outlines** +PDFsharp 6.2.0 no longer throws exceptions in this case. + +**Support PDF files with whitespace in ASCII85 filtered objects** +PDFsharp 6.2.0 no longer throws exceptions in this case. + +**Support encrypting PDF files with .NET Framework 4.x again** +This did not work with PDFsharp 6.2.0 Preview 2 and Preview 3. + +**Updated NuGet package references to avoid vulnerability warnings** +The warnings came from transitive packages, i.e. packages used by packages that were referenced by PDFsharp. +The vulnerable code was not invoked by PDFsharp. + +**MD5 replaced** +We use the class **MD5Managed** instead of **MD5** from .NET. +One reason is that .NET MD5 cannot be used in a FIPS-compliant environment. +Another reason is that some platforms like Blazor do not support the retired class **MD5** anymore. + +**Cleanup NuGet packages** +MigraDoc packages now depend on PDFsharp NuGet packages instead of including assemblies directly. +All packages now depend on e.g. `Microsoft.Extensions.Logging` instead of including the Microsoft assembly. + +**.restext files removed** +Some assemblies had a subfolder `de` containing German messages. +We removed all `.restext` resources. All messages are now available in US English only. diff --git a/docs/change-log/v6.2.0-log.md b/docs/change-log/gn-v6.2.0-preview-log.md similarity index 79% rename from docs/change-log/v6.2.0-log.md rename to docs/change-log/gn-v6.2.0-preview-log.md index 885e2271..4796d252 100644 --- a/docs/change-log/v6.2.0-log.md +++ b/docs/change-log/gn-v6.2.0-preview-log.md @@ -4,10 +4,48 @@ This text is copied to `docs.pdfsharp.net`. ## Version 6.2 -### PDFsharp 6.2.0 Preview 3 +### PDFsharp 6.2.0 (final release) *not yet released* +### PDFsharp 6.2.0 Preview 3 + +#### General issues + +#### PDFsharp features + +**Improved access to CropBox, ArtBox, BleedBox, TrimBox** +PdfPage now has new properties that make access to those boxes easier. +These are `HasBleedBox`, `BleedBoxReadOnly`, and `EffectiveBleedBoxReadOnly`. +Same applies to ArtBox, CropBox and TrimBox. + +**Loading images: Improved access to buffer of MemoryStream** +LoadImage from MemoryStream now works with a buffer that is not publicly visible. +For better performance, set 'publiclyVisible' to true when creating the MemoryStream. + +#### PDFsharp issues + +**Lexer.ScanNumber and CLexer.ScanNumber** +Based on a bug that crashes PDFsharp if a number in a PDFfile has to much leading zeros, we revised the code of **Lexer.ScanNumber** and **CLexer.ScanNumber**. + +**No more commas allowed in XUnit** +An old hack allows **XUnit** to be assigned from a string that uses a comma as decimal separator. +This was a introduced for languages like German, that use a comma instead of a point as decimal separator. +Now you get an exception. Applies also to **XUnitPt**. + +#### MigraDoc features + +**MigraDoc Preview user control restored for GDI build** +The MigraDoc Preview user control is again available in the GDI+ build. +MigraDoc Preview samples for GDI and WPF have been added to the samples repository. + +**Color.Parse no longer causes exceptions when invoked with a number value** +If Color.Parse is invoked with a number value, as in `var color = Color.Parse("#f00");`, +it no longer throws a handled exception internally. + +#### MigraDoc issues + + --- ### PDFsharp 6.2.0 Preview 2 @@ -140,7 +178,7 @@ We added .NET 8 (`net8.0`) to ``. PDF documents can now be PDF/A conforming. We are still working on this feature, so currently there are some limitations. **PDFsharp.Shared** -Code that grants friendly access to all PDFsharp Foundation assemblies lives in this new assembly. +Code that grants friendly access to all PDFsharp Project assemblies lives in this new assembly. #### Bug fixes diff --git a/docs/change-log/gn-v6.2.1-log.md b/docs/change-log/gn-v6.2.1-log.md new file mode 100644 index 00000000..518a8c5e --- /dev/null +++ b/docs/change-log/gn-v6.2.1-log.md @@ -0,0 +1,20 @@ +# General 6.2.1 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **general** `History.md`. + +## What’s new in version 6.2.1 + +### Breaking changes + +*(none)* + +### General features + +The new formatting option of PDFsharp is useful when generating PDF files from PDFsharp or MigraDoc. + +**Automatic download of assets folder** +TODO + +### General issues + +The bug fixes of PDFsharp are useful when generating PDF files from PDFsharp or MigraDoc. diff --git a/docs/change-log/gn-v6.2.2-log.md b/docs/change-log/gn-v6.2.2-log.md new file mode 100644 index 00000000..15466d90 --- /dev/null +++ b/docs/change-log/gn-v6.2.2-log.md @@ -0,0 +1,17 @@ +# General 6.2.2 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **general** `History.md`. + +## What’s new in version 6.2.2 + +### Breaking changes + +*(none)* + +### General features + +*(none)* + +### General issues + +The bug fixes of PDFsharp are useful when generating PDF files from PDFsharp or MigraDoc. diff --git a/docs/change-log/gn-v6.2.3-log.md b/docs/change-log/gn-v6.2.3-log.md new file mode 100644 index 00000000..be892714 --- /dev/null +++ b/docs/change-log/gn-v6.2.3-log.md @@ -0,0 +1,22 @@ +# General 6.2.3 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **general** `History.md`. + +## What’s new in version 6.2.3 + +### Breaking changes + +With version 6.2.3, we added support for .NET 9 and .NET 10. +Version 6.2.3 no longer compiles against .NET 6 which is out of support. +The NuGet packages can still be used for applications that use .NET 6. +Version 6.2.3 was built using Visual Studio 2026. +It still compiles with Visual Studio 2022, provided the .NET 10 SDK is installed, but warnings will be shown. +You can remove .NET 10 from the list of target frameworks if you do not need it. + +### General features + +*(none)* + +### General issues + +The bug fixes of PDFsharp are useful when generating PDF files from PDFsharp or MigraDoc. diff --git a/docs/change-log/gn-v6.2.4-log.md b/docs/change-log/gn-v6.2.4-log.md new file mode 100644 index 00000000..df14f1f0 --- /dev/null +++ b/docs/change-log/gn-v6.2.4-log.md @@ -0,0 +1,18 @@ +# General 6.2.4 change log + +A copy of the text below this line is added to `docs.pdfsharp.net` **general** `History.md`. + +## What’s new in version 6.2.4 + +### Breaking changes + +*(none)* + +### General features + +**Dependency on Microsoft.Extensions.Logging removed** +The new version depends on "Microsoft.Extensions.Logging.Abstractions" instead. GitHub #325 + +### General issues + +The bug fixes of PDFsharp are useful when generating PDF files from PDFsharp or MigraDoc. diff --git a/docs/docs-dummy.csproj b/docs/docs-dummy.csproj index 2731fd21..424fd82e 100644 --- a/docs/docs-dummy.csproj +++ b/docs/docs-dummy.csproj @@ -3,7 +3,7 @@ - net8.0 + net8.0 diff --git a/docs/publishing/BeforeReleases.md b/docs/publishing/BeforeReleases.md index 4bdbbd05..24489fdb 100644 --- a/docs/publishing/BeforeReleases.md +++ b/docs/publishing/BeforeReleases.md @@ -17,8 +17,8 @@ assembly-file-versioning-format: '{Major}.{Minor}.{Patch}.{env:PDFSHARP_BUILD_VE ### Update and sync used NuGet packages Update version numbers of NuGet packages used in PDFsharp code (like `MicroSoft.Extensions.Logging`) and -build tools (xunit, gitversion, ...). -Do this with `"Manage NuGet Packages for Solution..."` to see what’s new and update the version numbers +build tools (xunit, gitversion, …). +Do this with `"Manage NuGet Packages for Solution…"` to see what’s new and update the version numbers manually in `Directory.Packages.props`. Sync `Directory.Packages.props` with all other solutions, like `PDFsharp.Samples` etc. diff --git a/docs/publishing/BoilerplateText.md b/docs/publishing/BoilerplateText.md index 81d1e871..87ab7c65 100644 --- a/docs/publishing/BoilerplateText.md +++ b/docs/publishing/BoilerplateText.md @@ -4,9 +4,9 @@ ## PDFsharp -PDFsharp project - PDFsharp -PDFsharp Foundation - PDFsharp library -MigraDoc Foundation - MigraDoc library +PDFsharp Project - PDFsharp +PDFsharp Library - PDFsharp +MigraDoc Library - Library Source @@ -66,17 +66,17 @@ MigraDoc is a .NET library that allows developers to create documents such as PD Note: Do not replicate information from the metadata (like "6.0.0" or "prerelease"). PDFsharp: -This is a version of PDFsharp using .NET 6. -The package ’PdfSharp’ can be used on any platform including Windows and Linux. The Target Frameworks are ’net6.0’ and ’netstandard2.0’. -The packages ’PDFsharp-gdi’ and ’PDFsharp-wpf’ can be used under Windows only. The Target Frameworks are ’net6.0-windows’ and ’net462’. +This is a version of PDFsharp compatible with .NET 6 and higher. +The package ‘PdfSharp’ can be used on any platform including Windows and Linux. The Target Frameworks are ‘net6.0’, ‘net8.0’ and ‘netstandard2.0’. +The packages ‘PDFsharp-gdi’ and ‘PDFsharp-wpf’ can be used under Windows only. The Target Frameworks are ‘net6.0-windows’, ‘net8.0-windows’ and ‘net462’. We also publish packages that contain PDFsharp plus MigraDoc. See the project docs site for further information: https://docs.pdfsharp.net/link/readme-v6.2.html PDFsharp & MigraDoc: -This is a version of PDFsharp and MigraDoc Foundation using .NET 6. -The package ’PDFsharp-MigraDoc’ can be used on any platform including Windows and Linux. The Target Frameworks are ’net6.0’ and ’netstandard2.0’. -The packages ’PDFsharp-MigraDoc-GDI’ and ’PDFsharp-MigraDoc-WPF’ can be used under Windows only. The Target Frameworks are ’net6.0-windows’ and ’net462’. +This is a version of PDFsharp and MigraDoc compatible with .NET 6 and higher. +The package ‘PDFsharp-MigraDoc’ can be used on any platform including Windows and Linux. The Target Frameworks are ‘net6.0’, ‘net8.0’ and ‘netstandard2.0’. +The packages ‘PDFsharp-MigraDoc-GDI’ and ‘PDFsharp-MigraDoc-WPF’ can be used under Windows only. The Target Frameworks are ‘net6.0-windows’, ‘net8.0-windows’ and ‘net462’. See the project docs site for further information: https://docs.pdfsharp.net/link/readme-v6.2.html diff --git a/gitversion-6.x.yml b/gitversion-6.x.yml new file mode 100644 index 00000000..ce850d85 --- /dev/null +++ b/gitversion-6.x.yml @@ -0,0 +1,50 @@ +# Last update: 25-11-17 +assembly-versioning-scheme: MajorMinorPatch +# PDFSHARP_BUILD_VERSION are the days since 2005-01-01. #CHECK_BEFORE_RELEASE +# Command Window: ? (DateTime.Now - new DateTime(2005, 1, 1)).Days; +# C# Interactive: Console.WriteLine((DateTime.Now - new DateTime(2005, 1, 1)).Days); +assembly-file-versioning-format: '{Major}.{Minor}.{Patch}.{env:PDFSHARP_BUILD_VERSION ?? 7675}' +strategies: [Mainline] +assembly-informational-format: '{InformationalVersion}' +branches: + develop: # Current development branch + # branch: develop -- is always 'develop' + # version: {6.0.0}-develop.123 -- taken from git tag plus 'develop' plus commit count + regex: ^develop$ + mode: ContinuousDeployment + increment: None + label: develop + # Investigate this currently undocumented breaking change when switching to v6.x. + # The statement may not be needed. + # Not in v6.x: prevent-increment-of-merged-branch-version: false + # Not working: prevent-increment.of-merged-branch: false + # Not working: prevent-increment.when-branch-merged: false + track-merge-target: true + source-branches: ['feature', 'release'] + release: # Release and preview versions. + # branch: release/6.0.0-preview-3 -- must be same as git tag without leading 'v'. + # version: {6-0-0-preview-3} -- taken from git tag only + regex: ^(release[/-]|master) + # Must not have mode set to be mainline? + increment: None + label: '' + # Not in v6.x: prevent-increment-of-merged-branch-version: true + track-merge-target: true + is-release-branch: true + is-main-branch: true + source-branches: ['develop', 'release', 'feature'] + feature: # Features and bug fixes. + # branch: feature/my-new-feature -- arbitrary name, e.g. a new preview + # version: {6.0.0}-dev-{my-new-feature}.123 -- taken from git tag plus 'dev-' plus branch name plus commit count + regex: ^(user|feature|fix)[/-] + mode: ContinuousDeployment + increment: None + label: 'dev-{BranchName}' + # Not in v6.x: prevent-increment-of-merged-branch-version: true + track-merge-target: true + source-branches: ['develop', 'release', 'feature'] + pull-request: + regex: ^(pull|pull\-requests|pr)[/-] + label: PullRequest + mode: ContinuousDeployment +merge-message-formats: {} diff --git a/gitversion.yml b/gitversion.yml index 7d1cc407..caa8c9f2 100644 --- a/gitversion.yml +++ b/gitversion.yml @@ -1,9 +1,9 @@ -# Last update: 24-11-27 +# Last update: 25-11-17 assembly-versioning-scheme: MajorMinorPatch # PDFSHARP_BUILD_VERSION are the days since 2005-01-01. #CHECK_BEFORE_RELEASE # Command Window: ? (DateTime.Now - new DateTime(2005, 1, 1)).Days; # C# Interactive: Console.WriteLine((DateTime.Now - new DateTime(2005, 1, 1)).Days); -assembly-file-versioning-format: '{Major}.{Minor}.{Patch}.{env:PDFSHARP_BUILD_VERSION ?? 7283}' +assembly-file-versioning-format: '{Major}.{Minor}.{Patch}.{env:PDFSHARP_BUILD_VERSION ?? 7675}' mode: Mainline assembly-informational-format: '{NuGetVersion}' branches: diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 5368dc95..3aeeb07c 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -6,6 +6,7 @@ enable NU1507 + false @@ -26,7 +27,7 @@ PDFsharp empira Software - © 2024 empira + © 2026 empira PDFsharp Team empira Software GmbH @@ -45,4 +46,4 @@ all - \ No newline at end of file + diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index a87c9b4d..3e0c2628 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,7 +1,7 @@ - + $(DefineConstants);USE_LONG_SIZE;TEST_CODE_xxx \ No newline at end of file diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index cecab9c1..91654390 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,6 +1,7 @@ + 8.0.3 8.0.1 8.0.1 @@ -8,30 +9,33 @@ - - + + + - + - - + + - + - - + + + + \ No newline at end of file diff --git a/src/foundation/nuget/src/Directory.Build.props b/src/foundation/nuget/src/Directory.Build.props index 618588a9..6b12a5c6 100644 --- a/src/foundation/nuget/src/Directory.Build.props +++ b/src/foundation/nuget/src/Directory.Build.props @@ -43,7 +43,7 @@ $(NuspecProperties);tags=$(NuGetTags) $(NuspecProperties);NetCore_PackageVersion=$(NetCore_PackageVersion) - $(NuspecProperties);Logging_PackageVersion=$(Logging_PackageVersion) + $(NuspecProperties);Logging_Abstractions_PackageVersion=$(Logging_Abstractions_PackageVersion) $(NuspecProperties);Cryptography_PackageVersion=$(Cryptography_PackageVersion) diff --git a/src/foundation/nuget/src/Dummy-PDFsharp.NuGet-wpf/Dummy-PDFsharp.NuGet-wpf.csproj b/src/foundation/nuget/src/Dummy-PDFsharp.NuGet-wpf/Dummy-PDFsharp.NuGet-wpf.csproj index 57239e66..ed0f26e9 100644 --- a/src/foundation/nuget/src/Dummy-PDFsharp.NuGet-wpf/Dummy-PDFsharp.NuGet-wpf.csproj +++ b/src/foundation/nuget/src/Dummy-PDFsharp.NuGet-wpf/Dummy-PDFsharp.NuGet-wpf.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net462 + net8.0-windows;net462 true diff --git a/src/foundation/nuget/src/Dummy-PDFsharp.NuGet-wpf/README.md b/src/foundation/nuget/src/Dummy-PDFsharp.NuGet-wpf/README.md index a5d9f7a8..436b3fc5 100644 --- a/src/foundation/nuget/src/Dummy-PDFsharp.NuGet-wpf/README.md +++ b/src/foundation/nuget/src/Dummy-PDFsharp.NuGet-wpf/README.md @@ -14,4 +14,5 @@ According to the docs it should be possible to create NuGet packages without nus all stuff can be set in the csproj file. We still use nuspec because I cannot fix the following issues: * Set the package icon in cssproj so that it is displayed. -* We want a single package for all (e.g.) PDFsharp assemblies. Currently I don’t know how to manage that without a nuspec file. +* We want a single package for all (e.g.) PDFsharp assemblies. + Currently I don’t know how to manage that without a nuspec file. diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/Description.txt b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/Description.txt index 03e61dbb..c59d5227 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/Description.txt +++ b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/Description.txt @@ -1,4 +1,4 @@ -MigraDoc is a .NET library that allows developers to create documents such as PDF and RTF using a high-level object model. It provides an intuitive API that simplifies the creation of documents, including text formatting, tables, images, and more. MigraDoc is widely used for generating reports, invoices, and other types of documents in various applications. +MigraDoc is a .NET library that allows developers to create documents such as PDF and RTF using a high-level object model. It provides an intuitive API that simplifies the creation of documents, including text formatting, tables, images, and more. MigraDoc is widely used for generating reports, invoices, and other types of documents in various applications. This package relies on Windows Forms (GDI+) and can be used under Windows only. diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/MigraDoc.NuGet-gdi.csproj b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/MigraDoc.NuGet-gdi.csproj index b89b8c92..a6c95fb0 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/MigraDoc.NuGet-gdi.csproj +++ b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/MigraDoc.NuGet-gdi.csproj @@ -1,9 +1,9 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true - true + false True ..\..\..\..\StrongnameKey.snk diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/MigraDoc.NuGet-gdi.nuspec b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/MigraDoc.NuGet-gdi.nuspec index 9a3b155a..aaa3f15a 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/MigraDoc.NuGet-gdi.nuspec +++ b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/MigraDoc.NuGet-gdi.nuspec @@ -18,27 +18,35 @@ $title$ - - + + - - + + + + + + + - + - + - + + + + @@ -47,8 +55,9 @@ - + + diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/README.md b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/README.md index b260225d..1b3e37de 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/README.md +++ b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/README.md @@ -5,3 +5,7 @@ MigraDoc is a .NET library that allows developers to create documents such as PD This package relies on Windows Forms (GDI+) and can be used under Windows only. See [docs.pdfsharp.net](https://docs.pdfsharp.net) for details. + +See [https://www.pdfsharp.com](https://www.pdfsharp.com) for professional support offers, premium technical advice, and contract work options. +Choose a support plan that suits your needs. We offer a variety of options, from small projects to large teams, with flexible response times. +Our team provides PDFsharp expert assistance, including implementation, optimization, and tailored solutions. diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/ReleaseNotes.txt b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/ReleaseNotes.txt index 9cd08e6a..bdb0512f 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-gdi/ReleaseNotes.txt +++ b/src/foundation/nuget/src/MigraDoc.NuGet-gdi/ReleaseNotes.txt @@ -1,5 +1,5 @@ -This is a version of PDFsharp and MigraDoc Foundation using .NET 6. -The package ’PDFsharp-MigraDoc’ can be used on any platform including Windows and Linux. The Target Frameworks are ’net6.0’ and ’netstandard2.0’. -The packages ’PDFsharp-MigraDoc-GDI’ and ’PDFsharp-MigraDoc-WPF’ can be used under Windows only. The Target Frameworks are ’net6.0-windows’ and ’net462’. +This is a version of PDFsharp and MigraDoc compatible with .NET 6 and higher. +The package ‘PDFsharp-MigraDoc’ can be used on any platform including Windows and Linux. The Target Frameworks are ‘net8.0’, ‘net9.0’, ‘net10.0’, and ‘netstandard2.0’. +The packages ‘PDFsharp-MigraDoc-GDI’ and ‘PDFsharp-MigraDoc-WPF’ can be used under Windows only. The Target Frameworks are ‘net8.0-windows’, ‘net9.0-windows’, ‘net10.0-windows’, and ‘net462’. See the project docs site for further information: https://docs.pdfsharp.net/link/readme-v6.2.html diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/Description.txt b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/Description.txt index a24bae03..ff527946 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/Description.txt +++ b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/Description.txt @@ -1,4 +1,4 @@ -MigraDoc is a .NET library that allows developers to create documents such as PDF and RTF using a high-level object model. It provides an intuitive API that simplifies the creation of documents, including text formatting, tables, images, and more. MigraDoc is widely used for generating reports, invoices, and other types of documents in various applications. +MigraDoc is a .NET library that allows developers to create documents such as PDF and RTF using a high-level object model. It provides an intuitive API that simplifies the creation of documents, including text formatting, tables, images, and more. MigraDoc is widely used for generating reports, invoices, and other types of documents in various applications. This package relies on Windows Presentation Foundation (WPF) and can be used under Windows only. diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/MigraDoc.NuGet-wpf.csproj b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/MigraDoc.NuGet-wpf.csproj index 676107fe..b4b3a187 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/MigraDoc.NuGet-wpf.csproj +++ b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/MigraDoc.NuGet-wpf.csproj @@ -1,9 +1,9 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true - true + false True ..\..\..\..\StrongnameKey.snk diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/MigraDoc.NuGet-wpf.nuspec b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/MigraDoc.NuGet-wpf.nuspec index 7a5a15e7..3604cad9 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/MigraDoc.NuGet-wpf.nuspec +++ b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/MigraDoc.NuGet-wpf.nuspec @@ -18,27 +18,35 @@ $title$ - - + + - - + + + + + + + - + - + - + + + + @@ -47,8 +55,9 @@ - + + diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/README.md b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/README.md index 2aa1a171..19de2b70 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/README.md +++ b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/README.md @@ -5,3 +5,7 @@ MigraDoc is a .NET library that allows developers to create documents such as PD This package relies on Windows Presentation Foundation (WPF) and can be used under Windows only. See [docs.pdfsharp.net](https://docs.pdfsharp.net) for details. + +See [https://www.pdfsharp.com](https://www.pdfsharp.com) for professional support offers, premium technical advice, and contract work options. +Choose a support plan that suits your needs. We offer a variety of options, from small projects to large teams, with flexible response times. +Our team provides PDFsharp expert assistance, including implementation, optimization, and tailored solutions. diff --git a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/ReleaseNotes.txt b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/ReleaseNotes.txt index 9cd08e6a..bdb0512f 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet-wpf/ReleaseNotes.txt +++ b/src/foundation/nuget/src/MigraDoc.NuGet-wpf/ReleaseNotes.txt @@ -1,5 +1,5 @@ -This is a version of PDFsharp and MigraDoc Foundation using .NET 6. -The package ’PDFsharp-MigraDoc’ can be used on any platform including Windows and Linux. The Target Frameworks are ’net6.0’ and ’netstandard2.0’. -The packages ’PDFsharp-MigraDoc-GDI’ and ’PDFsharp-MigraDoc-WPF’ can be used under Windows only. The Target Frameworks are ’net6.0-windows’ and ’net462’. +This is a version of PDFsharp and MigraDoc compatible with .NET 6 and higher. +The package ‘PDFsharp-MigraDoc’ can be used on any platform including Windows and Linux. The Target Frameworks are ‘net8.0’, ‘net9.0’, ‘net10.0’, and ‘netstandard2.0’. +The packages ‘PDFsharp-MigraDoc-GDI’ and ‘PDFsharp-MigraDoc-WPF’ can be used under Windows only. The Target Frameworks are ‘net8.0-windows’, ‘net9.0-windows’, ‘net10.0-windows’, and ‘net462’. See the project docs site for further information: https://docs.pdfsharp.net/link/readme-v6.2.html diff --git a/src/foundation/nuget/src/MigraDoc.NuGet/Description.txt b/src/foundation/nuget/src/MigraDoc.NuGet/Description.txt index 0cc42ad4..78d56e99 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet/Description.txt +++ b/src/foundation/nuget/src/MigraDoc.NuGet/Description.txt @@ -1,4 +1,4 @@ -MigraDoc is a .NET library that allows developers to create documents such as PDF and RTF using a high-level object model. It provides an intuitive API that simplifies the creation of documents, including text formatting, tables, images, and more. MigraDoc is widely used for generating reports, invoices, and other types of documents in various applications. +MigraDoc is a .NET library that allows developers to create documents such as PDF and RTF using a high-level object model. It provides an intuitive API that simplifies the creation of documents, including text formatting, tables, images, and more. MigraDoc is widely used for generating reports, invoices, and other types of documents in various applications. This package does not depend on Windows and can be used on any .NET compatible platform including Linux and macOS. diff --git a/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.csproj b/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.csproj index 6103944a..ca67c46a 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.csproj +++ b/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.csproj @@ -1,8 +1,8 @@  - net6.0;net8.0;netstandard2.0 - true + net8.0;net9.0;net10.0;netstandard2.0 + false True ..\..\..\..\StrongnameKey.snk diff --git a/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.nuspec b/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.nuspec index 3f2b5634..679d8cb6 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.nuspec +++ b/src/foundation/nuget/src/MigraDoc.NuGet/MigraDoc.NuGet.nuspec @@ -18,34 +18,42 @@ $title$ - - + + - - + + + + + + + - + - - + + + + - + + diff --git a/src/foundation/nuget/src/MigraDoc.NuGet/README.md b/src/foundation/nuget/src/MigraDoc.NuGet/README.md index 096861a0..be978c7c 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet/README.md +++ b/src/foundation/nuget/src/MigraDoc.NuGet/README.md @@ -5,3 +5,7 @@ MigraDoc is a .NET library that allows developers to create documents such as PD This package does not depend on Windows and can be used on any .NET compatible platform including Linux and macOS. See [docs.pdfsharp.net](https://docs.pdfsharp.net) for details. + +See [https://www.pdfsharp.com](https://www.pdfsharp.com) for professional support offers, premium technical advice, and contract work options. +Choose a support plan that suits your needs. We offer a variety of options, from small projects to large teams, with flexible response times. +Our team provides PDFsharp expert assistance, including implementation, optimization, and tailored solutions. diff --git a/src/foundation/nuget/src/MigraDoc.NuGet/ReleaseNotes.txt b/src/foundation/nuget/src/MigraDoc.NuGet/ReleaseNotes.txt index 9cd08e6a..bdb0512f 100644 --- a/src/foundation/nuget/src/MigraDoc.NuGet/ReleaseNotes.txt +++ b/src/foundation/nuget/src/MigraDoc.NuGet/ReleaseNotes.txt @@ -1,5 +1,5 @@ -This is a version of PDFsharp and MigraDoc Foundation using .NET 6. -The package ’PDFsharp-MigraDoc’ can be used on any platform including Windows and Linux. The Target Frameworks are ’net6.0’ and ’netstandard2.0’. -The packages ’PDFsharp-MigraDoc-GDI’ and ’PDFsharp-MigraDoc-WPF’ can be used under Windows only. The Target Frameworks are ’net6.0-windows’ and ’net462’. +This is a version of PDFsharp and MigraDoc compatible with .NET 6 and higher. +The package ‘PDFsharp-MigraDoc’ can be used on any platform including Windows and Linux. The Target Frameworks are ‘net8.0’, ‘net9.0’, ‘net10.0’, and ‘netstandard2.0’. +The packages ‘PDFsharp-MigraDoc-GDI’ and ‘PDFsharp-MigraDoc-WPF’ can be used under Windows only. The Target Frameworks are ‘net8.0-windows’, ‘net9.0-windows’, ‘net10.0-windows’, and ‘net462’. See the project docs site for further information: https://docs.pdfsharp.net/link/readme-v6.2.html diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/Description.txt b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/Description.txt index 39e800a7..4b997b23 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/Description.txt +++ b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/Description.txt @@ -1,4 +1,4 @@ -PDFsharp is the Open Source library for creating and modifying PDF documents using .NET. It has an easy-to-use API that allows developers to generate or modify PDF files programmatically. PDFsharp can be used for various applications, including creating reports, invoices, and other types of documents. +PDFsharp is the Open Source library for creating and modifying PDF documents using .NET. It has an easy-to-use API that allows developers to generate or modify PDF files programmatically. PDFsharp can be used for various applications, including creating reports, invoices, and other types of documents. This package relies on Windows Forms (GDI+) and can be used under Windows only. diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/PDFsharp.NuGet-gdi.csproj b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/PDFsharp.NuGet-gdi.csproj index 76da6886..5c7f5a49 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/PDFsharp.NuGet-gdi.csproj +++ b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/PDFsharp.NuGet-gdi.csproj @@ -1,9 +1,9 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true - true + false True ..\..\..\..\StrongnameKey.snk diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/PDFsharp.NuGet-gdi.nuspec b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/PDFsharp.NuGet-gdi.nuspec index e44df4b4..1971831a 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/PDFsharp.NuGet-gdi.nuspec +++ b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/PDFsharp.NuGet-gdi.nuspec @@ -18,24 +18,31 @@ $title$ - - + + - - + + + + + + - + - + - + + + + @@ -44,8 +51,9 @@ - + + diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/README.md b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/README.md index b93dbc0d..851b3420 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/README.md +++ b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/README.md @@ -5,3 +5,7 @@ PDFsharp is the Open Source library for creating and modifying PDF documents usi This package relies on Windows Forms (GDI+) and can be used under Windows only. See [docs.pdfsharp.net](https://docs.pdfsharp.net) for details. + +See [https://www.pdfsharp.com](https://www.pdfsharp.com) for professional support offers, premium technical advice, and contract work options. +Choose a support plan that suits your needs. We offer a variety of options, from small projects to large teams, with flexible response times. +Our team provides PDFsharp expert assistance, including implementation, optimization, and tailored solutions. diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/ReleaseNotes.txt b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/ReleaseNotes.txt index 829ff6ee..a1689064 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-gdi/ReleaseNotes.txt +++ b/src/foundation/nuget/src/PDFsharp.NuGet-gdi/ReleaseNotes.txt @@ -1,6 +1,6 @@ -This is a version of PDFsharp using .NET 6. -The package ’PdfSharp’ can be used on any platform including Windows and Linux. The Target Frameworks are ’net6.0’ and ’netstandard2.0’. -The packages ’PDFsharp-gdi’ and ’PDFsharp-wpf’ can be used under Windows only. The Target Frameworks are ’net6.0-windows’ and ’net462’. -We also publish packages that contain MigraDoc and reference the corresponding PDFsharp package. +This is a version of PDFsharp compatible with .NET 6 and higher. +The package ‘PdfSharp’ can be used on any platform including Windows and Linux. The Target Frameworks are ‘net8.0’, ‘net9.0’, ‘net10.0’, and ‘netstandard2.0’. +The packages ‘PDFsharp-gdi’ and ‘PDFsharp-wpf’ can be used under Windows only. The Target Frameworks are ‘net8.0-windows’, ‘net9.0-windows’, ‘net10.0-windows’, and ‘net462’. +We also publish packages that contain PDFsharp plus MigraDoc. See the project docs site for further information: https://docs.pdfsharp.net/link/readme-v6.2.html diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/Description.txt b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/Description.txt index 2627b98f..b6028f68 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/Description.txt +++ b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/Description.txt @@ -1,4 +1,4 @@ -PDFsharp is the Open Source library for creating and modifying PDF documents using .NET. It has an easy-to-use API that allows developers to generate or modify PDF files programmatically. PDFsharp can be used for various applications, including creating reports, invoices, and other types of documents. +PDFsharp is the Open Source library for creating and modifying PDF documents using .NET. It has an easy-to-use API that allows developers to generate or modify PDF files programmatically. PDFsharp can be used for various applications, including creating reports, invoices, and other types of documents. This package relies on Windows Presentation Foundation (WPF) and can be used under Windows only. diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/PDFsharp.NuGet-wpf.csproj b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/PDFsharp.NuGet-wpf.csproj index 66ca02ae..a9c25477 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/PDFsharp.NuGet-wpf.csproj +++ b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/PDFsharp.NuGet-wpf.csproj @@ -1,9 +1,9 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true - true + false True ..\..\..\..\StrongnameKey.snk diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/PDFsharp.NuGet-wpf.nuspec b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/PDFsharp.NuGet-wpf.nuspec index d930f34b..8e242996 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/PDFsharp.NuGet-wpf.nuspec +++ b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/PDFsharp.NuGet-wpf.nuspec @@ -18,24 +18,31 @@ $title$ - - + + - - + + + + + + - + - + - + + + + @@ -44,8 +51,9 @@ - + + diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/README.md b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/README.md index 23c061b4..63c45298 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/README.md +++ b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/README.md @@ -5,3 +5,7 @@ PDFsharp is the Open Source library for creating and modifying PDF documents usi This package relies on Windows Presentation Foundation (WPF) and can be used under Windows only. See [docs.pdfsharp.net](https://docs.pdfsharp.net) for details. + +See [https://www.pdfsharp.com](https://www.pdfsharp.com) for professional support offers, premium technical advice, and contract work options. +Choose a support plan that suits your needs. We offer a variety of options, from small projects to large teams, with flexible response times. +Our team provides PDFsharp expert assistance, including implementation, optimization, and tailored solutions. diff --git a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/ReleaseNotes.txt b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/ReleaseNotes.txt index 829ff6ee..a1689064 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet-wpf/ReleaseNotes.txt +++ b/src/foundation/nuget/src/PDFsharp.NuGet-wpf/ReleaseNotes.txt @@ -1,6 +1,6 @@ -This is a version of PDFsharp using .NET 6. -The package ’PdfSharp’ can be used on any platform including Windows and Linux. The Target Frameworks are ’net6.0’ and ’netstandard2.0’. -The packages ’PDFsharp-gdi’ and ’PDFsharp-wpf’ can be used under Windows only. The Target Frameworks are ’net6.0-windows’ and ’net462’. -We also publish packages that contain MigraDoc and reference the corresponding PDFsharp package. +This is a version of PDFsharp compatible with .NET 6 and higher. +The package ‘PdfSharp’ can be used on any platform including Windows and Linux. The Target Frameworks are ‘net8.0’, ‘net9.0’, ‘net10.0’, and ‘netstandard2.0’. +The packages ‘PDFsharp-gdi’ and ‘PDFsharp-wpf’ can be used under Windows only. The Target Frameworks are ‘net8.0-windows’, ‘net9.0-windows’, ‘net10.0-windows’, and ‘net462’. +We also publish packages that contain PDFsharp plus MigraDoc. See the project docs site for further information: https://docs.pdfsharp.net/link/readme-v6.2.html diff --git a/src/foundation/nuget/src/PDFsharp.NuGet/Description.txt b/src/foundation/nuget/src/PDFsharp.NuGet/Description.txt index b6b011a5..e18be602 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet/Description.txt +++ b/src/foundation/nuget/src/PDFsharp.NuGet/Description.txt @@ -1,4 +1,4 @@ -PDFsharp is the Open Source library for creating and modifying PDF documents using .NET. It has an easy-to-use API that allows developers to generate or modify PDF files programmatically. PDFsharp can be used for various applications, including creating reports, invoices, and other types of documents. +PDFsharp is the Open Source library for creating and modifying PDF documents using .NET. It has an easy-to-use API that allows developers to generate or modify PDF files programmatically. PDFsharp can be used for various applications, including creating reports, invoices, and other types of documents. This package does not depend on Windows and can be used on any .NET compatible platform including Linux and macOS. diff --git a/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj b/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj index 1139a742..a530742a 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj +++ b/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.csproj @@ -1,8 +1,8 @@  - net6.0;net8.0;netstandard2.0 - true + net8.0;net9.0;net10.0;netstandard2.0 + false True diff --git a/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.nuspec b/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.nuspec index 4c01c173..1eeb3b59 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.nuspec +++ b/src/foundation/nuget/src/PDFsharp.NuGet/PDFsharp.NuGet.nuspec @@ -18,31 +18,38 @@ $title$ - - + + - - + + + + + + - + - - + + + + - + + diff --git a/src/foundation/nuget/src/PDFsharp.NuGet/README.md b/src/foundation/nuget/src/PDFsharp.NuGet/README.md index 4e60f763..00466f60 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet/README.md +++ b/src/foundation/nuget/src/PDFsharp.NuGet/README.md @@ -5,3 +5,7 @@ PDFsharp is the Open Source library for creating and modifying PDF documents usi This package does not depend on Windows and can be used on any .NET compatible platform including Linux and macOS. See [docs.pdfsharp.net](https://docs.pdfsharp.net) for details. + +See [https://www.pdfsharp.com](https://www.pdfsharp.com) for professional support offers, premium technical advice, and contract work options. +Choose a support plan that suits your needs. We offer a variety of options, from small projects to large teams, with flexible response times. +Our team provides PDFsharp expert assistance, including implementation, optimization, and tailored solutions. diff --git a/src/foundation/nuget/src/PDFsharp.NuGet/ReleaseNotes.txt b/src/foundation/nuget/src/PDFsharp.NuGet/ReleaseNotes.txt index 829ff6ee..a1689064 100644 --- a/src/foundation/nuget/src/PDFsharp.NuGet/ReleaseNotes.txt +++ b/src/foundation/nuget/src/PDFsharp.NuGet/ReleaseNotes.txt @@ -1,6 +1,6 @@ -This is a version of PDFsharp using .NET 6. -The package ’PdfSharp’ can be used on any platform including Windows and Linux. The Target Frameworks are ’net6.0’ and ’netstandard2.0’. -The packages ’PDFsharp-gdi’ and ’PDFsharp-wpf’ can be used under Windows only. The Target Frameworks are ’net6.0-windows’ and ’net462’. -We also publish packages that contain MigraDoc and reference the corresponding PDFsharp package. +This is a version of PDFsharp compatible with .NET 6 and higher. +The package ‘PdfSharp’ can be used on any platform including Windows and Linux. The Target Frameworks are ‘net8.0’, ‘net9.0’, ‘net10.0’, and ‘netstandard2.0’. +The packages ‘PDFsharp-gdi’ and ‘PDFsharp-wpf’ can be used under Windows only. The Target Frameworks are ‘net8.0-windows’, ‘net9.0-windows’, ‘net10.0-windows’, and ‘net462’. +We also publish packages that contain PDFsharp plus MigraDoc. See the project docs site for further information: https://docs.pdfsharp.net/link/readme-v6.2.html diff --git a/src/foundation/nuget/src/README.md b/src/foundation/nuget/src/README.md index 3093f708..0d977820 100644 --- a/src/foundation/nuget/src/README.md +++ b/src/foundation/nuget/src/README.md @@ -41,10 +41,10 @@ See Project Information for details. ### MigraDoc -MigraDoc Foundation - the Open Source .NET library that easily creates documents based on an object model with paragraphs, tables, styles, etc. and renders them into PDF or RTF. +MigraDoc - the Open Source .NET library that easily creates documents based on an object model with paragraphs, tables, styles, etc. and renders them into PDF or RTF. Text from MigraDoc 1.51: -MigraDoc Foundation - the Open Source .NET library that easily creates documents based on an object model with paragraphs, tables, styles, etc. and renders them into PDF or RTF. +MigraDoc - the Open Source .NET library that easily creates documents based on an object model with paragraphs, tables, styles, etc. and renders them into PDF or RTF. #### MigraDoc Core diff --git a/src/foundation/src/MigraDoc/features/MigraDoc.Features/MigraDoc.Features.csproj b/src/foundation/src/MigraDoc/features/MigraDoc.Features/MigraDoc.Features.csproj index 41f1d5ad..93906e8f 100644 --- a/src/foundation/src/MigraDoc/features/MigraDoc.Features/MigraDoc.Features.csproj +++ b/src/foundation/src/MigraDoc/features/MigraDoc.Features/MigraDoc.Features.csproj @@ -1,8 +1,8 @@ - + Exe - net6.0 + net8.0 diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/DateField.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/DateField.cs index 368b1aec..d841d538 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/DateField.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/DateField.cs @@ -48,7 +48,7 @@ internal override void Serialize(Serializer serializer) if (!String.IsNullOrEmpty(Values.Format)) str += "[Format = \"" + Format + "\"]"; else - str += "[]"; //Has to be appended to avoid confusion with '[' in immediately following text. + str += "[]"; // Has to be appended to avoid confusion with '[' in immediately following text. serializer.Write(str); } diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/PageField.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/PageField.cs index 2859532f..d50c2194 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/PageField.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/PageField.cs @@ -40,7 +40,7 @@ internal override void Serialize(Serializer serializer) if (!String.IsNullOrEmpty(Values.Format)) str += "[Format = \"" + Format + "\"]"; else - str += "[]"; //Has to be appended to avoid confusion with '[' in immediately following text. + str += "[]"; // Has to be appended to avoid confusion with '[' in immediately following text. serializer.Write(str); } diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/SectionField.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/SectionField.cs index 2b6b410d..45c4cdc9 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/SectionField.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Fields/SectionField.cs @@ -40,7 +40,7 @@ internal override void Serialize(Serializer serializer) if (!String.IsNullOrEmpty(Values.Format)) str += "[Format = \"" + Format + "\"]"; else - str += "[]"; //Has to be appended to avoid confusion with '[' in directly following text. + str += "[]"; // Has to be appended to avoid confusion with '[' in directly following text. serializer.Write(str); } diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlParser.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlParser.cs index ab837e78..00a983a7 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlParser.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlParser.cs @@ -728,7 +728,7 @@ void ParseFontSize(FormattedText formattedText, int nestingLevel) EnsureSymbol(Symbol.ParenLeft); ReadCode(); - //NYI: Check token for correct Unit format + // NYI: Check token for correct Unit format formattedText.Font.Size = Token; ReadCode(); EnsureSymbol(Symbol.ParenRight); @@ -960,7 +960,7 @@ void ParseHyperlink(ParagraphElements elements, int nestingLevel) ReadCode(); Hyperlink hyperlink = elements.AddHyperlink(""); - //NYI: Without name and type the hyperlink is senseless, so attributes need to be checked + // NYI: Without name and type the hyperlink is senseless, so attributes need to be checked if (Symbol == Symbol.BracketLeft) ParseAttributes(hyperlink); @@ -1255,8 +1255,8 @@ void ParseImage(Image image, bool paragraphContent) // Future syntax by example // \image("Name") // \image("Name")[...] - // \image{base64...} //NYI - // \image[...]{base64...} //NYI + // \image{base64...} // NYI + // \image[...]{base64...} // NYI Debug.Assert(image != null); try @@ -1903,7 +1903,7 @@ void ParseAttributeStatement(DocumentObject? doc) switch (Symbol) { case Symbol.Assign: - //DomValueDescriptor is needed from assignment routine. + // DomValueDescriptor is needed from assignment routine. var pvd = doc.Meta[valueName]; EnsureCondition(pvd != null, () => MdDomMsgs.InvalidValueName(valueName)); ParseAssign(doc, pvd); @@ -2609,7 +2609,7 @@ void AdjustToNextStatement() switch (Symbol) { case Symbol.Assign: - //read one more symbol + // Read one more symbol. ReadCode(); break; diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlScanner.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlScanner.cs index e87f9f2c..d038f718 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlScanner.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.IO/DdlScanner.cs @@ -94,7 +94,7 @@ internal Symbol ReadCode() Symbol = Symbol.StringLiteral; TokenType = TokenType.StringLiteral; } - //NYI: else if (IsNumber()) + // NYI: else if (IsNumber()) // symbol = ScanNumber(false); else if (IsDigit(_currChar) || _currChar is '-' or '+' && IsDigit(_nextChar)) @@ -606,7 +606,7 @@ internal bool MoveToNextParagraphContentLine(bool rootLevel) return false; } - //TODO_OLD NiSc NYI + // TODO_OLD NiSc NYI //Check.NotImplemented("empty line at non-root level"); } break; @@ -816,7 +816,7 @@ internal char ScanNextChar() break; case Chars.LF: - //NYI: Unix uses LF only + // NYI: Unix uses LF only _idxLine++; _idxLinePos = 0; break; @@ -1410,7 +1410,7 @@ string ScanStringLiteral() } break; - //NYI: octal numbers + // NYI: octal numbers //case '0': //{ // ScanNextChar(); diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/Meta.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/Meta.cs index 5a19415d..6f736716 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/Meta.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Internals/Meta.cs @@ -79,8 +79,8 @@ public void SetValue(DocumentObject dom, string name, object? val) if (trail != null) { - //REVIEW DaSt: dom.GetValue(name) and call SetValue recursively, - // or dom.GetValue(name.BisVorletzteElement) and then call SetValue? + // REVIEW DaSt: dom.GetValue(name) and call SetValue recursively, + // or dom.GetValue(name.BisVorletzteElement) and then call SetValue? var doc = (DocumentObject?)dom.GetValue(name); if (doc == null) throw new InvalidOperationException($"No value named '{name}' exists."); diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cells.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cells.cs index 12f03117..302ed6b7 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cells.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Cells.cs @@ -1,4 +1,4 @@ -// MigraDoc - Creating Documents on the Fly +// MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. using System.Diagnostics.CodeAnalysis; @@ -92,7 +92,7 @@ public Row Row } /// - /// Resizes these cells list if necessary. + /// Resizes these cells¹ list if necessary. /// void Resize(int index) { diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Column.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Column.cs index 37653e7d..7d902a82 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Column.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Tables/Column.cs @@ -1,4 +1,4 @@ -// MigraDoc - Creating Documents on the Fly +// MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. using System.Diagnostics.CodeAnalysis; @@ -118,7 +118,7 @@ public int Index /// /// Gets a cell by its row index. The first cell has index 0. /// - public Cell? this[int index] => Values.Index is not null ? Table.Rows[index][Values.Index.Value] : null; // BUG_OLD Doesnt use Index property to guarantee getter loop ran. + public Cell? this[int index] => Values.Index is not null ? Table.Rows[index][Values.Index.Value] : null; // BUG_OLD Doesn’t use Index property to guarantee getter loop ran. /// /// Sets or gets the default style name for all cells of the column. diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/VisitorBase.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/VisitorBase.cs index d4e8faa8..987686f3 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/VisitorBase.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel.Visitors/VisitorBase.cs @@ -1,4 +1,4 @@ -// MigraDoc - Creating Documents on the Fly +// MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. using MigraDoc.DocumentObjectModel.Tables; @@ -422,7 +422,7 @@ static void RealizeOrientation(PageSetup pageSetup) } /// - /// Updates the orientation according to a PageSetups PageWidth and PageHeight. + /// Updates the orientation according to a PageSetup’s PageWidth and PageHeight. /// static void UpdateOrientation(PageSetup pageSetup) { diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Color.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Color.cs index ed647ca2..4d1a106f 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Color.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Color.cs @@ -306,7 +306,7 @@ public static Color Parse(string color) // because the two operations are not always equivalent. // // While comparing a string to "" may seem like it’s checking for an empty string, it’s actually checking - // for a specific value of an empty string.This can be a problem if the empty string is represented by + // for a specific value of an empty string. This can be a problem if the empty string is represented by // something other than "" in the code, such as null or whitespace. // // On the other hand, comparing the length of a string to 0 is always checking for an empty string, @@ -314,7 +314,7 @@ public static Color Parse(string color) // a string to "", because it requires calculating the length of the string before doing the comparison. // // Therefore, the decision of whether to use a string comparison with "" or a length comparison to 0 should - // depend on the specific use case and the expected behavior of the code.In general, if you want to check if + // depend on the specific use case and the expected behavior of the code. In general, if you want to check if // a string is empty regardless of how it’s represented, a length comparison to 0 is a safer choice. // But if you specifically want to check for an empty string represented by "", then a string comparison with "" // may be more appropriate. @@ -328,16 +328,20 @@ public static Color Parse(string color) try { uint clr; - // Must use Enum.Parse because Enum.IsDefined is case-sensitive - try + // Do not parse strings that do not start with a letter, thus cannot be enum values. + if (!String.IsNullOrEmpty(color) && Char.IsLetter(color[0])) { - var obj = Enum.Parse(typeof(ColorName), color, true); - clr = (uint)obj; - return new(clr); - } - catch - { - // Ignore exception because it’s not a ColorName. + // Must use Enum.Parse because Enum.IsDefined is case-sensitive. + try + { + var obj = Enum.Parse(typeof(ColorName), color, true); + clr = (uint)obj; + return new(clr); + } + catch + { + // Ignore exception because it’s not a ColorName. + } } var numberStyle = NumberStyles.Integer; diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/DdlEncoder.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/DdlEncoder.cs index 806174bc..a841a237 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/DdlEncoder.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/DdlEncoder.cs @@ -1,4 +1,4 @@ -// MigraDoc - Creating Documents on the Fly +// MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. using System.Text; @@ -22,7 +22,7 @@ public static class DdlEncoder var sb = new StringBuilder(length + (length >> 2)); for (int index = 0; index < length; index++) { - // Dont convert characters into DDL. + // Don’t convert characters into DDL. char ch = str[index]; switch (ch) { diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Font.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Font.cs index 6ba7cad4..f417f857 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Font.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Font.cs @@ -224,21 +224,6 @@ public bool Subscript // .Kerning = 0 // .Animation = wdAnimationNone - ///// - ///// Gets a value indicating whether the specified font exists. - ///// - //[Obsolete("This function is removed from DocumentObjectModel and always returns false.")] - //public static bool Exists(string fontName) - //{ - // //System.Drawing.FontFamily[] families = System.Drawing.FontFamily.Families; - // //foreach (System.Drawing.FontFamily family in families) - // //{ - // // if (String.Compare(family.Name, fontName, true) == 0) - // // return true; - // //} - // return false; - //} - /// /// Get a bitmask of all non-null properties. /// diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Footnote.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Footnote.cs index 9cd92099..c8185b95 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Footnote.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Footnote.cs @@ -18,7 +18,7 @@ public class Footnote : DocumentObject, IVisitable public Footnote() { BaseValues = new FootnoteValues(this); - //NYI: Nested footnote check! + // NYI: Nested footnote check! } /// diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Hyperlink.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Hyperlink.cs index 85d3052e..531e936d 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Hyperlink.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Hyperlink.cs @@ -457,14 +457,14 @@ public Font Font public bool NoHyperlinkStyle { // This Property is not part of Word’s Automation Model. With this property Hyperlinks can be used without implicitly setting the Hyperlink style. - // This way they occur like linked cross references in Word, which are not implemented as an own DocumentObject type in MigraDoc. + // This way they occur like linked cross-references in Word, which are not implemented as an own DocumentObject type in MigraDoc. get => Values.NoHyperlinkStyle ?? false; set => Values.NoHyperlinkStyle = value; } /// /// For HyperlinkType Local/Bookmark: Gets or sets the target bookmark name of the Hyperlink. - /// For HyperlinkTypes File and Url/Web: Gets or sets the target filename of the Hyperlink, e.g. a path to a file or an URL. + /// For HyperlinkTypes File and Url/Web: Gets or sets the target filename of the Hyperlink, e.g. a path to a file or a URL. /// For HyperlinkType ExternalBookmark: Not valid - throws Exception. /// This property is retained due to compatibility reasons. /// @@ -503,7 +503,7 @@ public string Name } /// - /// Gets or sets the target filename of the Hyperlink, e.g. a path to a file or an URL. + /// Gets or sets the target filename of the Hyperlink, e.g. a path to a file or a URL. /// Used for HyperlinkTypes ExternalBookmark, File and Url/Web. /// public string Filename @@ -514,7 +514,7 @@ public string Filename /// /// Gets or sets the target bookmark name of the Hyperlink. - ///Used for HyperlinkTypes ExternalBookmark and Bookmark. + /// Used for HyperlinkTypes ExternalBookmark and Bookmark. /// public string BookmarkName { diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Style.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Style.cs index de562a8b..a45c9b3f 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Style.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Style.cs @@ -232,7 +232,7 @@ public StyleType Type if (Values.BaseStyle == "") throw new ArgumentException("User-defined Style defined without a BaseStyle"); - //REVIEW KlPo4StLa Special treatment for DefaultParagraphFont faulty (DefaultParagraphFont not returned via styles["name"]). + // REVIEW KlPo4StLa Special treatment for DefaultParagraphFont faulty (DefaultParagraphFont not returned via styles["name"]). if (Values.BaseStyle == DefaultParagraphFontName) return styles[0]; diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Styles.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Styles.cs index e7107148..10a69930 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Styles.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/DocumentObjectModel/Styles.cs @@ -428,7 +428,7 @@ internal override void Serialize(Serializer serializer) fSerialized[0] = true; // consider DefaultParagraphFont as serialized bool[] fSerializePending = new bool[count]; // currently serializing bool newLine = false; // gets true if at least one style was written - //Start from 1 and do not serialize DefaultParagraphFont + // Start from 1 and do not serialize DefaultParagraphFont for (int index = 1; index < count; index++) { if (!fSerialized[index]) diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/MigraDoc.DocumentObjectModel.csproj b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/MigraDoc.DocumentObjectModel.csproj index b97949f3..e7f47f6d 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/MigraDoc.DocumentObjectModel.csproj +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/MigraDoc.DocumentObjectModel.csproj @@ -1,10 +1,11 @@  - net6.0;net8.0;net462;netstandard2.0 + net8.0;net9.0;net10.0;net462;netstandard2.0 MigraDoc True ..\..\..\..\..\StrongnameKey.snk + true diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/Properties/MigraDocProductVersionInformation.cs b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/Properties/MigraDocProductVersionInformation.cs index 0ad14211..91d45086 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/Properties/MigraDocProductVersionInformation.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/Properties/MigraDocProductVersionInformation.cs @@ -1,7 +1,7 @@ // MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. -#pragma warning disable 0436 +using PdfSharp.Internal; namespace MigraDoc { @@ -27,43 +27,43 @@ public static class MigraDocProductVersionInformation /// /// The major version number of the product. /// - public static readonly string VersionMajor = GitVersionInformation.Major; + public static readonly string VersionMajor = PdfSharpGitVersionInformation.Major; /// /// The minor version number of the product. /// - public static readonly string VersionMinor = GitVersionInformation.Minor; + public static readonly string VersionMinor = PdfSharpGitVersionInformation.Minor; /// /// The patch number of the product. /// - public static readonly string VersionPatch = GitVersionInformation.Patch; + public static readonly string VersionPatch = PdfSharpGitVersionInformation.Patch; /// /// The Version pre-release string for NuGet. /// - public static readonly string VersionPreRelease = GitVersionInformation.NuGetPreReleaseTagV2; + public static readonly string VersionPreRelease = PdfSharpGitVersionInformation.PreReleaseLabel; /// /// The PDF creator application information string. /// The PDF producer (created by) is PDFsharp anyway. /// - public static readonly string Creator = $"{Title} {GitVersionInformation.NuGetVersion} ({Url})"; + public static readonly string Creator = $"{Title} {PdfSharpGitVersionInformation.InformationalVersion} ({Url})"; /// /// The full version number. /// - public static readonly string Version = GitVersionInformation.MajorMinorPatch; + public static readonly string Version = PdfSharpGitVersionInformation.MajorMinorPatch; /// /// The full semantic version number created by GitVersion. /// - public static readonly string SemanticVersion = GitVersionInformation.SemVer; + public static readonly string SemanticVersion = PdfSharpGitVersionInformation.SemVer; /// /// The home page of this product. /// - public const string Url = "www.pdfsharp.net"; + public const string Url = "www.pdfsharp.com"; /// /// Unused. @@ -83,7 +83,7 @@ public static class MigraDocProductVersionInformation /// /// The copyright information. /// - public const string Copyright = "Copyright © 2001-2024 empira Software GmbH."; // Also used as NuGet Copyright. + public const string Copyright = "Copyright © 2001-2026 empira Software GmbH."; // Also used as NuGet Copyright. /// /// The trademark of the product. @@ -103,83 +103,83 @@ public static class MigraDocProductVersionInformation // ReSharper restore RedundantNameQualifier #endif -#if Not_used_anymore - - /// - /// E.g. "2005-01-01", for use in NuGet Script - /// - public const string VersionReferenceDate = "2005-01-01"; - - /// - /// Use _ instead of blanks and special characters. Can be complemented with a suffix in the NuGet Script. - /// Nuspec Doc: The unique identifier for the package. This is the package name that is shown when packages are listed using the Package Manager Console. - /// These are also used when installing a package using the Install-Package command within the Package Manager Console. - /// Package IDs may not contain any spaces or characters that are invalid in an URL. In general, they follow the same rules as .NET namespaces do. - /// So Foo.Bar is a valid ID, Foo! and Foo Bar are not. - /// - public const string NuGetID = "PDFsharp-MigraDoc"; - - /// - /// Nuspec Doc: The human-friendly title of the package displayed in the Manage NuGet Packages dialog. If none is specified, the ID is used instead. - /// - public const string NuGetTitle = "PDFsharp + MigraDoc"; - - /// - /// Nuspec Doc: A comma-separated list of authors of the package code. - /// - public const string NuGetAuthors = "empira Software GmbH"; - - /// - /// Nuspec Doc: A comma-separated list of the package creators. This is often the same list as in authors. This is ignored when uploading the package to the NuGet.org Gallery. - /// - public const string NuGetOwners = "empira Software GmbH"; - - /// - /// Nuspec Doc: A long description of the package. This shows up in the right pane of the Add Package Dialog as well as in the Package Manager Console when listing packages using the Get-Package command. - /// - public const string NuGetDescription = "MigraDoc Foundation - the Open Source .NET library that easily creates documents based on an object model with paragraphs, tables, styles, etc. and renders them into PDF or RTF."; - - /// - /// Nuspec Doc: A description of the changes made in each release of the package. This field only shows up when the _Updates_ tab is selected and the package is an update to a previously installed package. - /// It is displayed where the Description would normally be displayed. - /// - public const string NuGetReleaseNotes = ""; - - /// - /// Nuspec Doc: A short description of the package. If specified, this shows up in the middle pane of the Add Package Dialog. If not specified, a truncated version of the description is used instead. - /// - public const string NuGetSummary = "Creating Documents on the Fly."; - - /// - /// Nuspec Doc: The locale ID for the package, such as en-us. - /// - public const string NuGetLanguage = ""; - - /// - /// Nuspec Doc: A URL for the home page of the package. - /// - public const string NuGetProjectUrl = "http://www.pdfsharp.net/"; - - /// - /// Nuspec Doc: A URL for the image to use as the icon for the package in the Manage NuGet Packages dialog box. This should be a 32x32-pixel .png file that has a transparent background. - /// - public const string NuGetIconUrl = "http://www.pdfsharp.net/resources/MigraDoc-Logo-32x32.png"; - - /// - /// Nuspec Doc: A link to the license that the package is under. - /// - public const string NuGetLicenseUrl = "http://www.pdfsharp.net/MigraDoc_License.ashx"; - - /// - /// Nuspec Doc: A Boolean value that specifies whether the client needs to ensure that the package license (described by licenseUrl) is accepted before the package is installed. - /// - public const bool NuGetRequireLicenseAcceptance = false; - - /// - /// Nuspec Doc: A space-delimited list of tags and keywords that describe the package. This information is used to help make sure users can find the package using - /// searches in the Add Package Reference dialog box or filtering in the Package Manager Console window. - /// - public const string NuGetTags = "MigraDoc PdfSharp Pdf Document Generation"; -#endif +//#if Not_used_anymore // #DELETE 25-12-31 + +// /// +// /// E.g. "2005-01-01", for use in NuGet Script +// /// +// public const string VersionReferenceDate = "2005-01-01"; + +// /// +// /// Use _ instead of blanks and special characters. Can be complemented with a suffix in the NuGet Script. +// /// Nuspec Doc: The unique identifier for the package. This is the package name that is shown when packages are listed using the Package Manager Console. +// /// These are also used when installing a package using the Install-Package command within the Package Manager Console. +// /// Package IDs may not contain any spaces or characters that are invalid in a URL. In general, they follow the same rules as .NET namespaces do. +// /// So Foo.Bar is a valid ID, Foo! and Foo Bar are not. +// /// +// public const string NuGetID = "PDFsharp-MigraDoc"; + +// /// +// /// Nuspec Doc: The human-friendly title of the package displayed in the Manage NuGet Packages dialog. If none is specified, the ID is used instead. +// /// +// public const string NuGetTitle = "PDFsharp + MigraDoc"; + +// /// +// /// Nuspec Doc: A comma-separated list of authors of the package code. +// /// +// public const string NuGetAuthors = "empira Software GmbH"; + +// /// +// /// Nuspec Doc: A comma-separated list of the package creators. This is often the same list as in authors. This is ignored when uploading the package to the NuGet.org Gallery. +// /// +// public const string NuGetOwners = "empira Software GmbH"; + +// /// +// /// Nuspec Doc: A long description of the package. This shows up in the right pane of the Add Package Dialog as well as in the Package Manager Console when listing packages using the Get-Package command. +// /// +// public const string NuGetDescription = "MigraDoc - the Open Source .NET library that easily creates documents based on an object model with paragraphs, tables, styles, etc. and renders them into PDF or RTF."; + +// /// +// /// Nuspec Doc: A description of the changes made in each release of the package. This field only shows up when the _Updates_ tab is selected and the package is an update to a previously installed package. +// /// It is displayed where the Description would normally be displayed. +// /// +// public const string NuGetReleaseNotes = ""; + +// /// +// /// Nuspec Doc: A short description of the package. If specified, this shows up in the middle pane of the Add Package Dialog. If not specified, a truncated version of the description is used instead. +// /// +// public const string NuGetSummary = "Creating Documents on the Fly."; + +// /// +// /// Nuspec Doc: The locale ID for the package, such as en-us. +// /// +// public const string NuGetLanguage = ""; + +// /// +// /// Nuspec Doc: A URL for the home page of the package. +// /// +// public const string NuGetProjectUrl = "http://www.pdfsharp.com/"; + +// /// +// /// Nuspec Doc: A URL for the image to use as the icon for the package in the Manage NuGet Packages dialog box. This should be a 32x32-pixel .png file that has a transparent background. +// /// +// public const string NuGetIconUrl = "http://www.pdf/sharp.net/resources/MigraDoc-Logo-32x32.png"; + +// /// +// /// Nuspec Doc: A link to the license that the package is under. +// /// +// public const string NuGetLicenseUrl = "http://www.pdf/sharp.net/MigraDoc_License.ashx"; + +// /// +// /// Nuspec Doc: A Boolean value that specifies whether the client needs to ensure that the package license (described by licenseUrl) is accepted before the package is installed. +// /// +// public const bool NuGetRequireLicenseAcceptance = false; + +// /// +// /// Nuspec Doc: A space-delimited list of tags and keywords that describe the package. This information is used to help make sure users can find the package using +// /// searches in the Add Package Reference dialog box or filtering in the Package Manager Console window. +// /// +// public const string NuGetTags = "MigraDoc PdfSharp Pdf Document Generation"; +//#endif } } diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/README.md b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/README.md index 6c1d18fe..aff137a8 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/README.md +++ b/src/foundation/src/MigraDoc/src/MigraDoc.DocumentObjectModel/README.md @@ -3,5 +3,5 @@ One single build with all target frameworks: ```xml -net6.0;net8.0;net462;netstandard2.0 +net8.0;net9.0;net10.0;net462;netstandard2.0 ``` diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/MigraDoc.Rendering-gdi.csproj b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/MigraDoc.Rendering-gdi.csproj index ba85e789..2a586f0c 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/MigraDoc.Rendering-gdi.csproj +++ b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/MigraDoc.Rendering-gdi.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true MigraDoc true @@ -9,6 +9,7 @@ GDI True ..\..\..\..\..\StrongnameKey.snk + true diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/Rendering.Forms/DocumentPreview.cs b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/Rendering.Forms/DocumentPreview.cs new file mode 100644 index 00000000..301d4818 --- /dev/null +++ b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/Rendering.Forms/DocumentPreview.cs @@ -0,0 +1,521 @@ +// MigraDoc - Creating Documents on the Fly +// See the LICENSE file in the solution root for more information. + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using PdfSharp.Drawing; + +namespace MigraDoc.Rendering.Forms +{ + /// + /// Event handler for the PagePreview event. + /// + public delegate void PagePreviewEventHandler(object sender, EventArgs e); + + /// + /// Represents a Windows control to display a MigraDoc document. + /// + public class DocumentPreview : UserControl + { + private PdfSharp.Forms.PagePreview _preview; + private readonly Container _components = null!; + + /// + /// Initializes a new instance of the class. + /// + public DocumentPreview() + { + InitializeComponent(); + _preview!.ZoomChanged += PreviewZoomChanged; + _preview.SetRenderFunction(RenderPage); + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_components != null!) + _components.Dispose(); + } + base.Dispose(disposing); + } + + Zoom GetNewZoomFactor(int currentZoom, bool larger) + { + int[] values = new int[] + { + 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, + 250, 300, 350, 400, 450, 500, 600, 700, 800 + }; + + if (currentZoom <= 10 && !larger) + return Zoom.Percent10; + if (currentZoom >= 800 && larger) + return Zoom.Percent800; + + if (larger) + { + for (int i = 0; i < values.Length; i++) + { + if (currentZoom < values[i]) + return (Zoom)values[i]; + } + } + else + { + for (int i = values.Length - 1; i >= 0; i--) + { + if (currentZoom > values[i]) + return (Zoom)values[i]; + } + } + return Zoom.Percent100; + } + + /// + /// Gets or sets the border style of the tree view control. + /// + /// + /// + /// One of the values. The default is . + /// + /// + /// The assigned value is not one of the values. + /// + /// + /// + /// + [DefaultValue((int)BorderStyle.Fixed3D), Description("Determines the style of the border."), Category("Preview Properties")] + public new BorderStyle BorderStyle + { + get { return _preview.BorderStyle; } + set { _preview.BorderStyle = value; } + } + + // #PFC + //w/// + ///// Gets or sets the private fonts of the document. If used, must be set before Ddl is set! + ///// + //public XPrivateFontCollection PrivateFonts + //{ + // get { return _privateFonts; } + // set { _privateFonts = value; } + //} + //internal XPrivateFontCollection _privateFonts; + + /// + /// Gets or sets a DDL string or file. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Ddl + { + get { return _ddl; } + set + { + _ddl = value; + DdlUpdated(); + } + } + string _ddl = null!; + + /// + /// Gets or sets the current page. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public int Page + { + get { return _page; } + set + { + try + { + if (_preview != null!) + { + if (_page != value) + { + _page = value; + PageInfo pageInfo = _renderer.FormattedDocument.GetPageInfo(_page); + if (pageInfo.Orientation == PdfSharp.PageOrientation.Portrait) + _preview.PageSize = new Size((int)pageInfo.Width, (int)pageInfo.Height); + else + _preview.PageSize = new Size((int)pageInfo.Height, (int)pageInfo.Width); + + _preview.Invalidate(); + OnPageChanged(EventArgs.Empty); + } + } + else + _page = -1; + } + // ReSharper disable once EmptyGeneralCatchClause + catch { } + } + } + int _page; + + /// + /// Gets the number of pages. + /// + public int PageCount + { + get + { + if (_renderer != null!) + return _renderer.FormattedDocument.PageCount; + return 0; + } + } + + /// + /// Goes to the first page. + /// + public void FirstPage() + { + if (_renderer != null!) + { + Page = 1; + _preview.Invalidate(); + OnPageChanged(EventArgs.Empty); + } + } + + /// + /// Goes to the next page. + /// + public void NextPage() + { + if (_renderer != null! && _page < PageCount) + { + Page++; + _preview.Invalidate(); + OnPageChanged(EventArgs.Empty); + } + } + + /// + /// Goes to the previous page. + /// + public void PrevPage() + { + if (_renderer != null! && _page > 1) + { + Page--; + } + } + + /// + /// Goes to the last page. + /// + public void LastPage() + { + if (_renderer != null!) + { + Page = PageCount; + _preview.Invalidate(); + OnPageChanged(EventArgs.Empty); + } + } + + ///// + ///// Gets or sets the working directory. + ///// + //public string WorkingDirectory + //{ + // get + // { + // return this.workingDirectory; + // } + // set + // { + // this.workingDirectory = value; + // } + //} + //string workingDirectory = ""; + + /// + /// Called when the Ddl property has changed. + /// + void DdlUpdated() + { + if (_ddl != null!) + { + _document = DocumentObjectModel.IO.DdlReader.DocumentFromString(_ddl); + _renderer = new DocumentRenderer(_document); + //_renderer.PrivateFonts = _privateFonts; + _renderer.PrepareDocument(); + Page = 1; + _preview.Invalidate(); + } + // if (this.job != null) + // this.job.Dispose(); + // + // if (this.ddl == null || this.ddl == "") + // return; + // + // this.job = new PrintJob(); + // this.job.Type = JobType.Standard; + // this.job.Ddl = this.ddl; + // this.job.WorkingDirectory = this.workingDirectory; + // this.job.InitDocument(); + // this.preview = this.job.GetPreview(this.Handle); + // this.previewHandle = this.preview.Hwnd; + // + // if (this.preview != null) + // this.preview.Page = 1; + } + + /// + /// Gets or sets the MigraDoc document that is previewed in this control. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public MigraDoc.DocumentObjectModel.Document Document + { + get { return _document; } + set + { + if (value != null!) + { + _document = value; + _renderer = new DocumentRenderer(value); + _renderer.PrepareDocument(); + Page = 1; + _preview.Invalidate(); + } + else + { + _document = null!; + _renderer = null!; + _preview.Invalidate(); + } + } + } + DocumentObjectModel.Document _document = null!; + + /// + /// Gets the underlying DocumentRenderer of the document currently in preview, or null, if no renderer exists. + /// You can use this renderer for printing or creating PDF file. This evades the necessity to format the + /// document a second time when you want to print it or convert it into PDF. + /// + public DocumentRenderer Renderer + { + get { return _renderer; } + } + + void RenderPage(XGraphics gfx) + { + if (_renderer == null!) + return; + + if (_renderer != null!) + { + try + { + _renderer.RenderPage(gfx, _page); + } + // ReSharper disable once EmptyGeneralCatchClause + catch { }; + } + } + DocumentRenderer _renderer = null!; + + /// + /// Gets or sets a predefined zoom factor. + /// + [DefaultValue((int)Zoom.FullPage), Description("Determines the zoom of the page."), Category("Preview Properties")] + public Zoom Zoom + { + get { return (Zoom)_preview.Zoom; } + set + { + if (_preview.Zoom != (PdfSharp.Forms.Zoom)value) + { + _preview.Zoom = (PdfSharp.Forms.Zoom)value; + OnZoomChanged(EventArgs.Empty); + } + } + } + + /// + /// Gets or sets an arbitrary zoom factor. The range is from 10 to 800. + /// + [DefaultValue((int)Zoom.FullPage), Description("Determines the zoom of the page."), Category("Preview Properties")] + public int ZoomPercent + { + get { return _preview.ZoomPercent; } + set + { + if (_preview.ZoomPercent != value) + { + _preview.ZoomPercent = value; + OnZoomChanged(EventArgs.Empty); + } + } + } + //internal int _zoomPercent = 100; + + /// + /// Makes zoom factor smaller. + /// + public void MakeSmaller() + { + ZoomPercent = (int)GetNewZoomFactor(ZoomPercent, false); + } + + /// + /// Makes zoom factor larger. + /// + public void MakeLarger() + { + ZoomPercent = (int)GetNewZoomFactor(ZoomPercent, true); + } + + /// + /// Gets or sets the color of the page. + /// + /// The color of the page. + [Description("The background color of the page."), Category("Preview Properties")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Color PageColor + { + get { return _preview.PageColor; } + set { _preview.PageColor = value; } + } + Color _pageColor = Color.GhostWhite; + + /// + /// Gets or sets the color of the desktop. + /// + /// The color of the desktop. + [Description("The color of the desktop."), Category("Preview Properties")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Color DesktopColor + { + get { return _preview.DesktopColor; } + set { _preview.DesktopColor = value; } + } + internal Color desktopColor = SystemColors.ControlDark; + + /// + /// Gets or sets a value indicating whether to show scrollbars. + /// + /// true if [show scrollbars]; otherwise, false. + [DefaultValue(true), Description("Determines whether the scrollbars are visible."), Category("Preview Properties")] + public bool ShowScrollbars + { + get { return _preview.ShowScrollbars; } + set { _preview.ShowScrollbars = value; } + } + internal bool showScrollbars = true; + + /// + /// Gets or sets a value indicating whether to show the page. + /// + /// true if [show page]; otherwise, false. + [DefaultValue(true), Description("Determines whether the page visible."), Category("Preview Properties")] + public bool ShowPage + { + get { return _preview.ShowPage; } + set { _preview.ShowPage = value; } + } + internal bool showPage = true; + + /// + /// Gets or sets the page size in point. + /// + [Description("Determines the size (in points) of the page."), Category("Preview Properties")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Size PageSize + { + get { return new Size((int)_preview.PageSize.Width, (int)_preview.PageSize.Height); } + set { _preview.PageSize = value; } + } + + /// + /// Raises the ZoomChanged event when the zoom factor changed. + /// + protected virtual void OnZoomChanged(EventArgs e) + { + if (ZoomChanged != null!) + ZoomChanged(this, e); + } + + /// + /// Occurs when the zoom factor changed. + /// + [Description("Occurs when the zoom factor changed."), Category("Preview Properties")] + public event PagePreviewEventHandler ZoomChanged = null!; + + /// + /// Raises the ZoomChanged event when the current page changed. + /// + protected virtual void OnPageChanged(EventArgs e) + { + if (PageChanged != null!) + PageChanged(this, e); + } + + /// + /// Occurs when the current page changed. + /// + [Description("Occurs when the current page changed."), Category("Preview Properties")] + public event PagePreviewEventHandler PageChanged = null!; + + + #region Component Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + _preview = new PdfSharp.Forms.PagePreview(); + SuspendLayout(); + // + // preview + // + _preview.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + _preview.DesktopColor = System.Drawing.SystemColors.ControlDark; + _preview.Dock = System.Windows.Forms.DockStyle.Fill; + _preview.Location = new System.Drawing.Point(0, 0); + _preview.Name = "_preview"; + _preview.PageColor = System.Drawing.Color.GhostWhite; + _preview.PageSize = new System.Drawing.Size(595, 842); + _preview.Size = new System.Drawing.Size(200, 200); + _preview.TabIndex = 0; + _preview.Zoom = PdfSharp.Forms.Zoom.FullPage; + _preview.ZoomPercent = 15; + // + // PagePreview + // + this.Controls.Add(_preview); + Name = "PagePreview"; + Size = new System.Drawing.Size(200, 200); + this.ResumeLayout(false); + + } + #endregion + + /// + /// Raises the event. + /// + /// A that contains the event data. + protected override void OnMouseWheel(MouseEventArgs e) + { + int delta = e.Delta; + if (delta > 0) + PrevPage(); + else if (delta < 0) + NextPage(); + } + + private void PreviewZoomChanged(object? sender, EventArgs e) + { + OnZoomChanged(e); + } + } +} diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/MdPdfMsg.de.resx b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/Rendering.Forms/DocumentPreview.resx similarity index 73% rename from src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/MdPdfMsg.de.resx rename to src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/Rendering.Forms/DocumentPreview.resx index 1b7707d9..19dc0dd8 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/MdPdfMsg.de.resx +++ b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering-gdi/Rendering.Forms/DocumentPreview.resx @@ -1,4 +1,4 @@ - + - - - diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering-wpf/MigraDoc.RtfRendering-wpf.csproj b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering-wpf/MigraDoc.RtfRendering-wpf.csproj index 0eec2a3f..f9d150e8 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering-wpf/MigraDoc.RtfRendering-wpf.csproj +++ b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering-wpf/MigraDoc.RtfRendering-wpf.csproj @@ -1,6 +1,6 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true MigraDoc WPF @@ -9,6 +9,7 @@ OnBuildSuccess True ..\..\..\..\..\StrongnameKey.snk + true diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/MigraDoc.RtfRendering.csproj b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/MigraDoc.RtfRendering.csproj index 10518896..93dcc6ce 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/MigraDoc.RtfRendering.csproj +++ b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/MigraDoc.RtfRendering.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;netstandard2.0 + net8.0;net9.0;net10.0;netstandard2.0 MigraDoc ..\..\..\..\..\StrongnameKey.snk True diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/CharacterRenderer.cs b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/CharacterRenderer.cs index 9550de19..a78a4d52 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/CharacterRenderer.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/CharacterRenderer.cs @@ -1,4 +1,4 @@ -// MigraDoc - Creating Documents on the Fly +// MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. using System.Diagnostics; @@ -37,7 +37,7 @@ internal override void Render() case SymbolName.Blank: for (int idx = 0; idx < count; idx++) _rtfWriter.WriteBlank(); - //WriteText wouldnt work if there was a control before. + //WriteText wouldn’t work if there was a control before. break; case SymbolName.Bullet: @@ -54,7 +54,7 @@ internal override void Render() for (int idx = 0; idx < count; idx++) { _rtfWriter.WriteControl("u", "8195"); - //I dont know why, but it works: + //I don’t know why, but it works: _rtfWriter.WriteHex(0x20); } break; @@ -63,7 +63,7 @@ internal override void Render() for (int idx = 0; idx < count; idx++) { _rtfWriter.WriteControl("u", "8197"); - //I dont know why, but it works: + //I don’t know why, but it works: _rtfWriter.WriteHex(0x20); } break; @@ -72,7 +72,7 @@ internal override void Render() for (int idx = 0; idx < count; idx++) { _rtfWriter.WriteControl("u", "8194"); - //I dont know why, but it works: + //I don’t know why, but it works: _rtfWriter.WriteHex(0x20); } break; diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/MdRtfMsgs.cs b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/MdRtfMsgs.cs index c5bfca27..234a965f 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/MdRtfMsgs.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/MdRtfMsgs.cs @@ -1,4 +1,4 @@ -// MigraDoc - Creating Documents on the Fly +// MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. using PdfSharp.Internal; @@ -48,7 +48,7 @@ internal static MdRtfMsg InvalidNumericFieldFormat(string format) => new(MdRtfMsgId.InvalidNumericFieldFormat, $"'{format}' is not a valid format for a numeric field and will be ignored."); internal static MdRtfMsg CharacterNotAllowedInDateFormat(char character) - => new(MdRtfMsgId.CharacterNotAllowedInDateFormat, $"The character '{character}' is not allowed in a date fields format string and will be ignored."); + => new(MdRtfMsgId.CharacterNotAllowedInDateFormat, $"The character '{character}' is not allowed in a date field’s format string and will be ignored."); internal static MdRtfMsg UpdateField => new(MdRtfMsgId.UpdateField, "< Please update this field. >"); diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/RendererBase.cs b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/RendererBase.cs index fa9f7782..7994c802 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/RendererBase.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/RendererBase.cs @@ -1,4 +1,4 @@ -// MigraDoc - Creating Documents on the Fly +// MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. using System.Diagnostics; @@ -357,7 +357,7 @@ protected object GetValueOrDefault(string valName, object valDefault) } /// - /// Renders a trailing standard paragraph in case the last element in elements isnt a paragraph. + /// Renders a trailing standard paragraph in case the last element in elements isn’t a paragraph. /// (Some RTF elements need to close with a paragraph.) /// protected void RenderTrailingParagraph(DocumentElements elements) diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/RtfDocumentRenderer.cs b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/RtfDocumentRenderer.cs index aafafea6..ab92aabb 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/RtfDocumentRenderer.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.RtfRendering/RtfRendering/RtfDocumentRenderer.cs @@ -35,25 +35,6 @@ internal override void Render() /// public void Render(Document doc, string file, string workingDirectory) { - // #DELETE - //#if NET6_0_OR_GREATER - // var ansiEncoding = CodePagesEncodingProvider.Instance.GetEncoding(1252)!; - //#else - // Encoding? ansiEncoding; - // try - // { - // // Try to get ANSI encoding. - // ansiEncoding = Encoding.GetEncoding(1252); - // } - // catch (NotSupportedException) - // { - //#if NET6_0_OR_GREATER - // // Register provider if ANSI encoding is not available. - // Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - //#endif - // ansiEncoding = Encoding.GetEncoding(1252); - // } - //#endif var ansiEncoding = PdfEncoders.WinAnsiEncoding; StreamWriter? streamWriter = null; diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/Helper/TestHelper.cs b/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/Helper/TestHelper.cs index 2cef5e9b..11be8c9b 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/Helper/TestHelper.cs +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/Helper/TestHelper.cs @@ -10,21 +10,6 @@ namespace MigraDoc.DocumentObjectModel.Tests.Helper { public class TestHelper { - //[Obsolete("Not needed anymore")] - //public static void InitializeFontResolver() - //{ - //} - - //[Obsolete("Not needed anymore")] - //public static void InitializeFontResolverWithSegoeWpAsDefault(Document doc) - //{ - // InitializeFontResolver(); - - // var style = doc.Styles[StyleNames.Normal]; - // style.Should().NotBeNull(); - // //style!.Font.Name = "segoe wp"; - //} - public static void RemoveStyles(Document doc) { for (var i = doc.Styles.Count - 1; i >= 0; i--) diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/MigraDoc.DocumentObjectModel.Tests.csproj b/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/MigraDoc.DocumentObjectModel.Tests.csproj index f8eaccf5..da9cceef 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/MigraDoc.DocumentObjectModel.Tests.csproj +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/MigraDoc.DocumentObjectModel.Tests.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net462 + net8.0;net9.0;net10.0;net462 diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/Structs/UnitTests.cs b/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/Structs/UnitTests.cs index 8ea56049..040dc0a5 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/Structs/UnitTests.cs +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.DocumentObjectModel.Tests/Structs/UnitTests.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. using FluentAssertions; @@ -60,7 +60,7 @@ public void Unit_Test() (unitNull == null).Should().BeTrue(); (unitNull != null).Should().BeFalse(); - // Only check cm variables, which are totally equal because str2Cm with "2cm" wont cause rounding errors. + // Only check cm variables, which are totally equal because str2Cm with "2cm" won’t cause rounding errors. (unit2Cm2 == unit2Cm).Should().BeTrue(); // Use IsSameValue() for other variables. @@ -69,7 +69,7 @@ public void Unit_Test() unit2CmPt2.IsSameValue(unit2CmPt).Should().BeTrue(); unit2CmPc2.IsSameValue(unit2CmPc).Should().BeTrue(); - // Only check cm variables, which are totally equal because str2Cm with "2cm" wont cause rounding errors. + // Only check cm variables, which are totally equal because str2Cm with "2cm" won’t cause rounding errors. (unit2Cm2 != unit2Cm).Should().BeFalse(); // Same value - other unit. diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.GBE-Runner/MigraDoc.GBE-Runner.csproj b/src/foundation/src/MigraDoc/tests/MigraDoc.GBE-Runner/MigraDoc.GBE-Runner.csproj index 52ee0ccf..91eaa028 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.GBE-Runner/MigraDoc.GBE-Runner.csproj +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.GBE-Runner/MigraDoc.GBE-Runner.csproj @@ -2,7 +2,7 @@ Exe - net6.0;net8.0;net462 + net8.0;net9.0;net10.0;net462 MigraDoc.GBE_Runner MigraDoc.GBE_Runner.Program diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-GDI/MigraDoc.GrammarByExample-GDI.csproj b/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-GDI/MigraDoc.GrammarByExample-GDI.csproj index b25f466e..60749bf9 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-GDI/MigraDoc.GrammarByExample-GDI.csproj +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-GDI/MigraDoc.GrammarByExample-GDI.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 MigraDoc.GrammarByExample_GDI true true diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-WPF/MigraDoc.GrammarByExample-WPF.csproj b/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-WPF/MigraDoc.GrammarByExample-WPF.csproj index ec74ce24..8afb911c 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-WPF/MigraDoc.GrammarByExample-WPF.csproj +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-WPF/MigraDoc.GrammarByExample-WPF.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 MigraDoc.GrammarByExample_WPF true true diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample/MigraDoc.GrammarByExample.csproj b/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample/MigraDoc.GrammarByExample.csproj index b69b50dc..317b2cd8 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample/MigraDoc.GrammarByExample.csproj +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample/MigraDoc.GrammarByExample.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net462 + net8.0;net9.0;net10.0;net462 false diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests-gdi/MigraDoc.Tests-gdi.csproj b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests-gdi/MigraDoc.Tests-gdi.csproj index 1fe83cdd..72425076 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests-gdi/MigraDoc.Tests-gdi.csproj +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests-gdi/MigraDoc.Tests-gdi.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true True ..\..\..\..\..\StrongnameKey.snk @@ -42,6 +42,7 @@ + diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests-wpf/MigraDoc.Tests-wpf.csproj b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests-wpf/MigraDoc.Tests-wpf.csproj index b53d9512..46e32c27 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests-wpf/MigraDoc.Tests-wpf.csproj +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests-wpf/MigraDoc.Tests-wpf.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true true True @@ -43,6 +43,7 @@ + diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/CultureAndRegionTests.cs b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/CultureAndRegionTests.cs index 9d73c186..70b1adf8 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/CultureAndRegionTests.cs +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/CultureAndRegionTests.cs @@ -1,4 +1,4 @@ -// MigraDoc - Creating Documents on the Fly +// MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. using System.Globalization; @@ -50,7 +50,7 @@ public void DateTimeTest() var englishMonths = new[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; var amPm = new[] { "AM", "PM" }; var germanWeekdays = new[] { "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag" }; - var germanMonths = new[] { "Januar", "Februar", "Mrz", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember" }; + var germanMonths = new[] { "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember" }; // filenamePattern with placeholder for cultureInfo. var filenamePattern = IOUtility.GetTempFileName("DateTime{0}", "pdf"); diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/Extensions/XunitHelper.cs b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/Extensions/XunitHelper.cs index 209a0881..a51ac72d 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/Extensions/XunitHelper.cs +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/Extensions/XunitHelper.cs @@ -1,4 +1,7 @@ -using System; +// MigraDoc - Creating Documents on the Fly +// See the LICENSE file in the solution root for more information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/Fonts/PredefinedFontsTests.cs b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/Fonts/PredefinedFontsTests.cs index 7ce3ca3c..29571259 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/Fonts/PredefinedFontsTests.cs +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/Fonts/PredefinedFontsTests.cs @@ -267,8 +267,9 @@ void CheckErrorFont(PdfDocument pdfDocument, string expectedFontName) // Check font of the error message. var fontName = PdfFileHelper.GetCurrentFontName(0, pdfDocument, streamEnumerator => { - // Move to "Image '???' not found.". - streamEnumerator.Text.MoveAndGetNext(x => x.Text == "Image '???' not found.", true, out _).Should().BeTrue(); + // Move to "Image '' not found.". + // Move to "Image 'c:/not-existing-image' not found.". + streamEnumerator.Text.MoveAndGetNext(x => x.Text == "Image 'c:/not-existing-image' not found.", true, out _).Should().BeTrue(); }); fontName.ToLower().Should().Be(expectedFontName.ToLower()); } @@ -340,7 +341,7 @@ static Document CreateDocumentWithErrorMessage() var section = document.AddSection(); // Add a not existing image to force error message. - section.AddImage("not-existing-image"); + section.AddImage("c:/not-existing-image"); return document; } diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/MigraDoc.Tests.csproj b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/MigraDoc.Tests.csproj index 60f0258a..1957a8a3 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/MigraDoc.Tests.csproj +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/MigraDoc.Tests.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net462 + net8.0;net9.0;net10.0;net462 True ..\..\..\..\..\StrongnameKey.snk @@ -30,6 +30,7 @@ + diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/PageSizeTests.cs b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/PageSizeTests.cs index b3c41387..891cf7b9 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/PageSizeTests.cs +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/PageSizeTests.cs @@ -1,4 +1,7 @@ -using System; +// MigraDoc - Creating Documents on the Fly +// See the LICENSE file in the solution root for more information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/SecurityTests.cs b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/SecurityTests.cs index 6709fc87..ce761805 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/SecurityTests.cs +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.Tests/SecurityTests.cs @@ -1,23 +1,27 @@ // MigraDoc - Creating Documents on the Fly // See the LICENSE file in the solution root for more information. -using PdfSharp.Pdf; -using PdfSharp.Pdf.IO; -using PdfSharp.Pdf.Security; -using MigraDoc.Rendering; -using Xunit; +using System.IO; +using System.Security.Cryptography.X509Certificates; using FluentAssertions; using Microsoft.Extensions.Logging; using MigraDoc.DocumentObjectModel; +using MigraDoc.Rendering; using PdfSharp; using PdfSharp.Drawing; +using PdfSharp.Drawing.Layout; using PdfSharp.Fonts; using PdfSharp.Logging; +using PdfSharp.Pdf; +using PdfSharp.Pdf.IO; +using PdfSharp.Pdf.Security; +using PdfSharp.Pdf.Signatures; using PdfSharp.Quality; using PdfSharp.TestHelper; using PdfSharp.TestHelper.Analysis.ContentStream; -using static PdfSharp.TestHelper.SecurityTestHelper; +using Xunit; using static MigraDoc.Tests.Helper.SecurityTestHelper; +using static PdfSharp.TestHelper.SecurityTestHelper; namespace MigraDoc.Tests { @@ -355,7 +359,7 @@ public void Test_Read_OwnerPassword(TestOptionsEnum optionsEnum) [SkippableTheory] [ClassData(typeof(TestData.AllWriteVersions))] [ClassData(typeof(TestData.AllWriteVersionsSkipped), Skip = SkippedTestOptionsMessage)] - public void Test_Write_UserOwnerPassword(TestOptionsEnum optionsEnum) + public void Test_Write_UserAndOwnerPassword(TestOptionsEnum optionsEnum) { Skip.If(SkippableTests.SkipSlowTestsUnderDotNetFramework()); @@ -991,5 +995,129 @@ public void Test_Strings(TestOptionsEnum optionsEnum) LogHost.Factory = oldLoggerFactory; } } + + + [Fact] + public void Test_Hyperlink() + { + // Create a MigraDoc document. + var document = CreateDocument(); + // Associate the MigraDoc document with a renderer. + var pdfRenderer = new PdfDocumentRenderer + { + Document = document, + PdfDocument = new PdfDocument + { + PageLayout = PdfPageLayout.SinglePage + } + }; + // Layout and render document to PDF. + pdfRenderer.RenderDocument(); + // Set security settings directly on the PDF document + var securitySettings = pdfRenderer.PdfDocument.SecuritySettings; + securitySettings.OwnerPassword = "Secret"; + // Save the document... + var filename = PdfFileUtility.GetTempPdfFullFileName("HyperlinkWithEncryptionTest"); + pdfRenderer.PdfDocument.Save(filename); + // ...and start a viewer. + // Process.Start(new ProcessStartInfo(filename) { UseShellExecute = true }); + // Creates minimalistic document with hyperlink. + static Document CreateDocument() + { + // Create a new MigraDoc document. + var document = new Document(); + // Add a section to the document. + var section = document.AddSection(); + // Add a paragraph to the section. + var paragraph = section.AddParagraph(); + // Add a hyperlink to a web URL to the paragraph. + var hyperlink = paragraph.AddHyperlink("https://docs.pdfsharp.net", HyperlinkType.Url); + hyperlink.AddText("link"); + return document; + } + } + + [SkippableTheory] + [ClassData(typeof(TestData.AllWriteVersions))] + [ClassData(typeof(TestData.AllWriteVersionsSkipped), Skip = SkippedTestOptionsMessage)] + public void Test_SignedDocument(TestOptionsEnum optionsEnum) + { + var options = TestOptions.ByEnum(optionsEnum); + options.SetDefaultPasswords(true); + + var filename = AddPrefixToFilename("SigningWithEncryptionTest.pdf", options); + + var document = CreateDocument(); + SecureDocument(document, options); + + // Save the document. + document.Save(filename); + + + // Creates minimalistic document with hyperlink. + static PdfDocument CreateDocument() + { + const int requiredAssets = 1014; + string? timestampURL = null; + + var certType = "test-cert_rsa_1024"; + var digestType = PdfMessageDigestType.SHA256; + + IOUtility.EnsureAssetsVersion(requiredAssets); + + var font = new XFont("Verdana", 10, XFontStyleEx.Regular); + var fontHeader = new XFont("Verdana", 18, XFontStyleEx.Regular); + var document = new PdfDocument(); + var pdfPage = document.AddPage(); + var xGraphics = XGraphics.FromPdfPage(pdfPage); + var layoutRectangle = new XRect(0, 72, pdfPage.Width.Point, pdfPage.Height.Point); + xGraphics.DrawString("Document Signature Test", fontHeader, XBrushes.Black, layoutRectangle, XStringFormats.TopCenter); + var textFormatter = new XTextFormatter(xGraphics); + layoutRectangle = new XRect(72, 144, pdfPage.Width.Point - 144, pdfPage.Height.Point - 144); + + var text = "Lorem ipsum..."; + textFormatter.DrawString(text, font, new XSolidBrush(XColor.FromKnownColor(XKnownColor.Black)), layoutRectangle, XStringFormats.TopLeft); + + var pdfPosition = xGraphics.Transformer.WorldToDefaultPage(new XPoint(144, 216)); + var options = new DigitalSignatureOptions + { + // We do not set an appearance handler, so the default handler is used. + // It is highly recommended to set an appearance handler to get a nicer representation of the signature. + ContactInfo = "John Doe", + Location = "Seattle", + Reason = "License Agreement", + Rectangle = new XRect(pdfPosition.X, pdfPosition.Y, 200, 50), + AppName = "PDFsharp Library" + }; + + Uri? timestampURI = String.IsNullOrEmpty(timestampURL) ? null : new Uri(timestampURL, UriKind.Absolute); + + var pdfSignatureHandler = DigitalSignatureHandler.ForDocument(document, new PdfSharpDefaultSigner(GetCertificate(certType), digestType, timestampURI), options); + + return document; + } + + static X509Certificate2 GetCertificate(string certName) + { + var certFolder = IOUtility.GetAssetsPath("pdfsharp-6.x/signatures"); + var pfxFile = Path.Combine(certFolder ?? throw new InvalidOperationException("Call Download-Assets.ps1 before running the tests."), $"{certName}.pfx"); + var rawData = File.ReadAllBytes(pfxFile); + + // Do not use password literals for real certificates in source code. + var certificatePassword = "Seecrit1243"; // Used in certificate. + +#if NET9_0_OR_GREATER + // New API introduced with .NET 9. + var certificate = X509CertificateLoader.LoadPkcs12(rawData, certificatePassword, + X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); +#else + // Old API, obsolete since .NET 9. + var certificate = new X509Certificate2(rawData, + certificatePassword, + /*X509KeyStorageFlags.MachineKeySet |*/ X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); +#endif + return certificate; + } + } } -} +} \ No newline at end of file diff --git a/src/foundation/src/PDFsharp/docs/AboutFonts.md b/src/foundation/src/PDFsharp/docs/AboutFonts.md index 664e05b4..8934b30e 100644 --- a/src/foundation/src/PDFsharp/docs/AboutFonts.md +++ b/src/foundation/src/PDFsharp/docs/AboutFonts.md @@ -65,7 +65,7 @@ The **XFont** exists independently of a PDF docuemnt. You can think of an XFont as a moniker to a specific font face plus a specific font size. It is a fascade to XGlyphTypeface. Holds a reference to **OpenTypeDescriptor** to get all information about a the font face. -This is possible because once loaded font faces persists in memory. +This is possible because once loaded font faces persist in memory. Holds a reference to **XGlyphTypeface**. That keeps the reference to the font face. In contrast to an **XGlyphTypeface** a font holds the following additional information. * The font em-size used for rendering the font. @@ -152,7 +152,7 @@ Holds a reference ... The class **PdfCIDFont** represents character encoded PDF fonts. It is used together with **PdfType0Font** to represent text in a content by a sequence of the -glyph ids of the Unicode code points of the original UTF-32 encoded text. +glyph IDs of the Unicode code points of the original UTF-32 encoded text. ### PdfTrueTypeFont : PdfFont @@ -165,7 +165,7 @@ but the character set is limited to (roughly) ANSI characters (codepage 1252). The class **PdfType0Font** represents a PDF font dictionary derived from **PdfCIDFont**. Together with **PdfCIDFont** t is used to represent text in a content stream by a sequende of -glyph ids of the Unicode code points of the original text. This class hold the reference to the +glyph IDs of the Unicode code points of the original text. This class hold the reference to the ToUnicode map. ### sealed PdfFontDescriptor : PdfDictionary diff --git a/src/foundation/src/PDFsharp/features/PDFsharp.Features-gdi/PDFsharp.Features-gdi.csproj b/src/foundation/src/PDFsharp/features/PDFsharp.Features-gdi/PDFsharp.Features-gdi.csproj index 0bb0db5e..cd3012c2 100644 --- a/src/foundation/src/PDFsharp/features/PDFsharp.Features-gdi/PDFsharp.Features-gdi.csproj +++ b/src/foundation/src/PDFsharp/features/PDFsharp.Features-gdi/PDFsharp.Features-gdi.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net462 + net8.0-windows;net462 true PDFsharp.Features true diff --git a/src/foundation/src/PDFsharp/features/PDFsharp.Features-wpf/PDFsharp.Features-wpf.csproj b/src/foundation/src/PDFsharp/features/PDFsharp.Features-wpf/PDFsharp.Features-wpf.csproj index 95f17553..506da2b2 100644 --- a/src/foundation/src/PDFsharp/features/PDFsharp.Features-wpf/PDFsharp.Features-wpf.csproj +++ b/src/foundation/src/PDFsharp/features/PDFsharp.Features-wpf/PDFsharp.Features-wpf.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net462 + net8.0-windows;net462 true PDFsharp.Features true diff --git a/src/foundation/src/PDFsharp/features/PDFsharp.Features.Runner-gdi/PDFsharp.Features.Runner-gdi.csproj b/src/foundation/src/PDFsharp/features/PDFsharp.Features.Runner-gdi/PDFsharp.Features.Runner-gdi.csproj index 3b391394..0ca4840a 100644 --- a/src/foundation/src/PDFsharp/features/PDFsharp.Features.Runner-gdi/PDFsharp.Features.Runner-gdi.csproj +++ b/src/foundation/src/PDFsharp/features/PDFsharp.Features.Runner-gdi/PDFsharp.Features.Runner-gdi.csproj @@ -2,7 +2,7 @@ Exe - net6.0-windows;net462 + net8.0-windows;net462 true PDFsharp.Features true diff --git a/src/foundation/src/PDFsharp/features/PDFsharp.Features.Runner-wpf/PDFsharp.Features.Runner-wpf.csproj b/src/foundation/src/PDFsharp/features/PDFsharp.Features.Runner-wpf/PDFsharp.Features.Runner-wpf.csproj index 9f46155e..a22f8c63 100644 --- a/src/foundation/src/PDFsharp/features/PDFsharp.Features.Runner-wpf/PDFsharp.Features.Runner-wpf.csproj +++ b/src/foundation/src/PDFsharp/features/PDFsharp.Features.Runner-wpf/PDFsharp.Features.Runner-wpf.csproj @@ -2,7 +2,7 @@ Exe - net6.0-windows;net462 + net8.0-windows;net462 true PDFsharp.Features true diff --git a/src/foundation/src/PDFsharp/features/PdfSharp.Features.Runner/PdfSharp.Features.Runner.csproj b/src/foundation/src/PDFsharp/features/PdfSharp.Features.Runner/PdfSharp.Features.Runner.csproj index 5a877abf..7791be9f 100644 --- a/src/foundation/src/PDFsharp/features/PdfSharp.Features.Runner/PdfSharp.Features.Runner.csproj +++ b/src/foundation/src/PDFsharp/features/PdfSharp.Features.Runner/PdfSharp.Features.Runner.csproj @@ -2,7 +2,7 @@ Exe - net6.0;net462 + net8.0;net462 CORE diff --git a/src/foundation/src/PDFsharp/features/PdfSharp.Features/PdfSharp.Features.csproj b/src/foundation/src/PDFsharp/features/PdfSharp.Features/PdfSharp.Features.csproj index f1e8b630..7a112f72 100644 --- a/src/foundation/src/PDFsharp/features/PdfSharp.Features/PdfSharp.Features.csproj +++ b/src/foundation/src/PDFsharp/features/PdfSharp.Features/PdfSharp.Features.csproj @@ -1,7 +1,7 @@  - net6.0;netstandard2.0 + net8.0;netstandard2.0 CORE diff --git a/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/DeviceInfos.cs b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/DeviceInfos.cs new file mode 100644 index 00000000..88e89fdb --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/DeviceInfos.cs @@ -0,0 +1,102 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Security; +//using System.Security.Permissions; + +#if GDI +namespace PdfSharp.Forms +{ + /// + /// Contains information about a physical device like a display or a printer. + /// + public struct DeviceInfos + { + /// + /// Width, in millimeters, of the physical screen or device. + /// + public int HorizontalSize; + + /// + /// Height, in millimeters, of the physical screen or device. + /// + public int VerticalSize; + + /// + /// Width, in pixels, of the screen or device. + /// + public int HorizontalResolution; + + /// + /// Height, in pixels, of the screen or device. + /// + public int VerticalResolution; + + /// + /// Number of pixels per logical inch along the screen or device width. + /// + public int LogicalDpiX; + + /// + /// Number of pixels per logical inch along the screen or device height. + /// + public int LogicalDpiY; + + /// + /// Number of pixels per physical inch along the screen or device width. + /// + public float PhysicalDpiX; + + /// + /// Number of pixels per physical inch along the screen or device height. + /// + public float PhysicalDpiY; + + /// + /// The ratio of LogicalDpiX and PhysicalDpiX. + /// + public float ScaleX; + + /// + /// The ratio of LogicalDpiY and PhysicalDpiY. + /// + public float ScaleY; + + /// + /// Gets a DeviceInfo for the specifed device context. + /// + [SuppressUnmanagedCodeSecurity] + public static DeviceInfos GetInfos(IntPtr hdc) + { + DeviceInfos devInfo; + + devInfo.HorizontalSize = GetDeviceCaps(hdc, HORZSIZE); + devInfo.VerticalSize = GetDeviceCaps(hdc, VERTSIZE); + devInfo.HorizontalResolution = GetDeviceCaps(hdc, HORZRES); + devInfo.VerticalResolution = GetDeviceCaps(hdc, VERTRES); + devInfo.LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX); + devInfo.LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY); + devInfo.PhysicalDpiX = devInfo.HorizontalResolution * 25.4f / devInfo.HorizontalSize; + devInfo.PhysicalDpiY = devInfo.VerticalResolution * 25.4f / devInfo.VerticalSize; + devInfo.ScaleX = devInfo.LogicalDpiX / devInfo.PhysicalDpiX; + devInfo.ScaleY = devInfo.LogicalDpiY / devInfo.PhysicalDpiY; + + return devInfo; + } + + [DllImport("gdi32.dll")] + static extern int GetDeviceCaps(IntPtr hdc, int capability); + // ReSharper disable InconsistentNaming + const int HORZSIZE = 4; + const int VERTSIZE = 6; + const int HORZRES = 8; + const int VERTRES = 10; + const int LOGPIXELSX = 88; + const int LOGPIXELSY = 90; + // ReSharper restore InconsistentNaming + } +} +#endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreview.cs b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreview.cs new file mode 100644 index 00000000..ae9d8e2d --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreview.cs @@ -0,0 +1,1053 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +// Draw crosses to check layout calculation +#define DRAW_X_ + +#if DEBUG +// Test drawing in a bitmap. This is just a hack - don't use it! +#define DRAW_BMP_ +#endif + +using System; +using System.Diagnostics; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using PdfSharp.Drawing; + +#if !GDI +#error This file must only be included in GDI build. +#endif + +namespace PdfSharp.Forms +{ + /* TODOs + * + * o Call render event only once. -> introduce an UpdatePage() function + * + * Further stuff: set printable area; set text box (smallest rect that contains all content) + */ + /// + /// Represents a preview control for an XGraphics page. Can be used as an alternative to + /// System.Windows.Forms.PrintPreviewControl. + /// + public class PagePreview : UserControl + { + /// + /// A delegate for invoking the render function. + /// + public delegate void RenderEvent(XGraphics gfx); + + private Container components = null!; + + /// + /// Initializes a new instance of the class. + /// + public PagePreview() + { + _canvas = new PagePreviewCanvas(this); + Controls.Add(_canvas); + + _hScrollBar = new HScrollBar(); + _hScrollBar.Visible = _showScrollbars; + _hScrollBar.Scroll += OnScroll; + _hScrollBar.ValueChanged += OnValueChanged; + Controls.Add(_hScrollBar); + + _vScrollBar = new VScrollBar(); + _vScrollBar.Visible = _showScrollbars; + _vScrollBar.Scroll += OnScroll; + _vScrollBar.ValueChanged += OnValueChanged; + Controls.Add(_vScrollBar); + + InitializeComponent(); + //OnLayout(); + + _zoom = Zoom.FullPage; + //_printableArea = new RectangleF(); + //virtPageSize = new Size(); + //showNonPrintableArea = false; + //virtualPrintableArea = new Rectangle(); + + //_printableArea.GetType(); + //showNonPrintableArea.GetType(); + //virtualPrintableArea.GetType(); + + // Prevent bogus compiler warnings + _posOffset = new Point(); + _virtualPage = new Rectangle(); + } + + readonly PagePreviewCanvas _canvas; + readonly HScrollBar _hScrollBar; + readonly VScrollBar _vScrollBar; + + /// + /// Clean up any resources being used. + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (components != null!) + components.Dispose(); + } + base.Dispose(disposing); + } + + /// + /// Gets or sets the border style of the control. + /// + /// + [DefaultValue((int)BorderStyle.Fixed3D), Description("Determines the style of the border."), Category("Preview Properties")] + public new BorderStyle BorderStyle + { + get { return _borderStyle; } + set + { + if (!Enum.IsDefined(typeof(BorderStyle), value)) + throw new InvalidEnumArgumentException("value", (int)value, typeof(BorderStyle)); + + if (value != _borderStyle) + { + _borderStyle = value; + LayoutChildren(); + } + } + } + BorderStyle _borderStyle = BorderStyle.Fixed3D; + + // [DefaultValue(2), Description("TODO..."), Category("Preview Properties")] + // public PageSize PageSize + // { + // get { return pageSize2; } + // set + // { + // if (!Enum.IsDefined(typeof(PageSize), value)) + // throw new InvalidEnumArgumentException("value", (int)value, typeof(PageSize)); + // + // if (value != pageSize2) + // { + // pageSize2 = value; + // // base.RecreateHandle(); + // // integralHeightAdjust = true; + // // try + // // { + // // base.Height = requestedHeight; + // // } + // // finally + // // { + // // integralHeightAdjust = false; + // // } + // } + // } + // } + // PageSize pageSize2; + + /// + /// Gets or sets the XGraphicsUnit of the page. + /// The default value is XGraphicsUnit.Point. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public XGraphicsUnit PageGraphicsUnit { get; set; } = XGraphicsUnit.Point; + +#if !NET9_0_OR_GREATER + /// + /// This property was renamed. Use new property PageGraphicsUnit. + /// + [Obsolete("Property renamed, use PageGraphicsUnit")] + public XGraphicsUnit PageUnit + { + get => PageGraphicsUnit; + set => PageGraphicsUnit = value; + } +#endif + + /// + /// Gets or sets a predefined zoom factor. + /// + [DefaultValue((int)Zoom.FullPage), Description("Determines the zoom of the page."), Category("Preview Properties")] + public Zoom Zoom + { + get { return _zoom; } + set + { + if ((int)value < (int)Zoom.Minimum || (int)value > (int)Zoom.Maximum) + { + if (!Enum.IsDefined(typeof(Zoom), value)) + throw new InvalidEnumArgumentException("value", (int)value, typeof(Zoom)); + } + if (value != _zoom) + { + _zoom = value; + CalculatePreviewDimension(); + SetScrollBarRange(); + _canvas.Invalidate(); + } + } + } + Zoom _zoom; + + /// + /// Gets or sets an arbitrary zoom factor. The range is from 10 to 800. + /// + //[DefaultValue((int)Zoom.FullPage), Description("Determines the zoom of the page."), Category("Preview Properties")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public int ZoomPercent + { + get { return _zoomPercent; } + set + { + if (value < (int)Zoom.Minimum || value > (int)Zoom.Maximum) + throw new ArgumentOutOfRangeException("value", value, + String.Format("Value must between {0} and {1}.", (int)Zoom.Minimum, (int)Zoom.Maximum)); + + if (value != _zoomPercent) + { + _zoom = (Zoom)value; + _zoomPercent = value; + CalculatePreviewDimension(); + SetScrollBarRange(); + _canvas.Invalidate(); + } + } + } + int _zoomPercent; + + /// + /// Gets or sets the color of the page. + /// + [Description("The background color of the page."), Category("Preview Properties")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Color PageColor + { + get { return _pageColor; } + set + { + if (value != _pageColor) + { + _pageColor = value; + Invalidate(); + } + } + } + Color _pageColor = Color.GhostWhite; + + /// + /// Gets or sets the color of the desktop. + /// + [Description("The color of the desktop."), Category("Preview Properties")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Color DesktopColor + { + get { return _desktopColor; } + set + { + if (value != _desktopColor) + { + _desktopColor = value; + Invalidate(); + } + } + } + internal Color _desktopColor = SystemColors.ControlDark; + + /// + /// Gets or sets a value indicating whether the scrollbars are visible. + /// + [DefaultValue(true), Description("Determines whether the scrollbars are visible."), Category("Preview Properties")] + public bool ShowScrollbars + { + get { return _showScrollbars; } + set + { + if (value != _showScrollbars) + { + _showScrollbars = value; + _hScrollBar.Visible = value; + _vScrollBar.Visible = value; + LayoutChildren(); + } + } + } + bool _showScrollbars = true; + + /// + /// Gets or sets a value indicating whether the page is visible. + /// + [DefaultValue(true), Description("Determines whether the page visible."), Category("Preview Properties")] + public bool ShowPage + { + get { return _showPage; } + set + { + if (value != _showPage) + { + _showPage = value; + _canvas.Invalidate(); + } + } + } + internal bool _showPage = true; + + /// + /// Gets or sets the page size in point. + /// + [Description("Determines the size (in points) of the page."), Category("Preview Properties")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public XSize PageSize + { + get { return new XSize((int)_pageSize.Width, (int)_pageSize.Height); } + set + { + _pageSize = new SizeF((float)value.Width, (float)value.Height); + CalculatePreviewDimension(); + Invalidate(); + } + } + + /// + /// This is a hack for Visual Studio 2008. The designer uses reflection for setting the PageSize property. + /// This fails, even an implicit operator that converts Size to XSize exits. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public Size PageSizeF + { + get { return new Size(Convert.ToInt32(_pageSize.Width), Convert.ToInt32(_pageSize.Height)); } + set + { + _pageSize = value; + CalculatePreviewDimension(); + Invalidate(); + } + } + + /// + /// Sets a delegate that is invoked when the preview wants to be painted. + /// + public void SetRenderFunction(Action renderEvent) + { + _renderAction = renderEvent; + Invalidate(); + } + Action _renderAction = null!; + + /// + /// Sets a delegate that is invoked when the preview wants to be painted. + /// + [Obsolete("Use SetRenderFunction")] + public void SetRenderEvent(RenderEvent renderEvent) + { + _renderAction = new Action(renderEvent); + Invalidate(); + } + + #region Component Designer generated code + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + Name = "PagePreview"; + Size = new System.Drawing.Size(228, 252); + } + #endregion + + /// + /// Raises the ZoomChanged event when the zoom factor changed. + /// + protected virtual void OnZoomChanged(EventArgs e) + { + if (ZoomChanged != null!) + ZoomChanged(this, e); + } + + /// + /// Occurs when the zoom factor changed. + /// + public event EventHandler ZoomChanged = null!; + + /// + /// Paints the background with the sheet of paper. + /// + protected override void OnPaintBackground(PaintEventArgs e) + { + // Accurate drawing prevents flickering + Graphics gfx = e.Graphics; + Rectangle clientRect = ClientRectangle; + int d = 0; + switch (_borderStyle) + { + case BorderStyle.FixedSingle: + gfx.DrawRectangle(SystemPens.WindowFrame, clientRect.X, clientRect.Y, clientRect.Width - 1, clientRect.Height - 1); + d = 1; + break; + + case BorderStyle.Fixed3D: + ControlPaint.DrawBorder3D(gfx, clientRect, Border3DStyle.Sunken); + d = 2; + break; + } + if (_showScrollbars) + { + int cxScrollbar = SystemInformation.VerticalScrollBarWidth; + int cyScrollbar = SystemInformation.HorizontalScrollBarHeight; + + gfx.FillRectangle(new SolidBrush(BackColor), + clientRect.Width - cxScrollbar - d, clientRect.Height - cyScrollbar - d, cxScrollbar, cyScrollbar); + } + } + + /// + /// Recalculates the preview dimension. + /// + protected override void OnSizeChanged(EventArgs e) + { + base.OnSizeChanged(e); + CalculatePreviewDimension(); + SetScrollBarRange(); + } + + /// + /// Invalidates the canvas. + /// + protected override void OnInvalidated(InvalidateEventArgs e) + { + base.OnInvalidated(e); + _canvas.Invalidate(); + } + + /// + /// Layouts the child controls. + /// + protected override void OnLayout(LayoutEventArgs levent) + { + LayoutChildren(); + } + + void OnScroll(object? obj, ScrollEventArgs e) + { + ScrollBar? sc = obj as ScrollBar; + if (sc != null) + { + //Debug.WriteLine(String.Format("OnScroll: {0}, {1}", sc.Value, e.NewValue)); + } + } + + void OnValueChanged(object? obj, EventArgs e) + { + ScrollBar? sc = obj as ScrollBar; + if (sc != null) + { + //Debug.WriteLine(String.Format("OnValueChanged: {0}", sc.Value)); + if (sc == _hScrollBar) + _posOffset.X = sc.Value; + + else if (sc == _vScrollBar) + _posOffset.Y = sc.Value; + } + _canvas.Invalidate(); + } + + void LayoutChildren() + { + Invalidate(); + Rectangle clientRect = ClientRectangle; + switch (_borderStyle) + { + case BorderStyle.FixedSingle: + clientRect.Inflate(-1, -1); + break; + + case BorderStyle.Fixed3D: + clientRect.Inflate(-2, -2); + break; + } + int x = clientRect.X; + int y = clientRect.Y; + int cx = clientRect.Width; + int cy = clientRect.Height; + int cxScrollbar = 0; + int cyScrollbar = 0; + if (_showScrollbars && _vScrollBar != null! && _hScrollBar != null!) + { + cxScrollbar = _vScrollBar.Width; + cyScrollbar = _hScrollBar.Height; + _vScrollBar.Location = new Point(x + cx - cxScrollbar, y); + _vScrollBar.Size = new Size(cxScrollbar, cy - cyScrollbar); + _hScrollBar.Location = new Point(x, y + cy - cyScrollbar); + _hScrollBar.Size = new Size(cx - cxScrollbar, cyScrollbar); + } + if (_canvas != null!) + { + _canvas.Location = new Point(x, y); + _canvas.Size = new Size(cx - cxScrollbar, cy - cyScrollbar); + } + } + + /// + /// Calculates all values for drawing the page preview. + /// + internal void CalculatePreviewDimension(out bool zoomChanged) + { + // User may change display resolution while preview is running + Graphics gfx = Graphics.FromHwnd(IntPtr.Zero); + IntPtr hdc = gfx.GetHdc(); + DeviceInfos devInfo = DeviceInfos.GetInfos(hdc); + gfx.ReleaseHdc(hdc); + gfx.Dispose(); + int xdpiScreen = devInfo.LogicalDpiX; + int ydpiScreen = devInfo.LogicalDpiY; + //int cxScrollbar = SystemInformation.VerticalScrollBarWidth; + //int cyScrollbar = SystemInformation.HorizontalScrollBarHeight; + Rectangle rcCanvas = _canvas.ClientRectangle; + + Zoom zoomOld = _zoom; + int zoomPercentOld = _zoomPercent; + + // Border around virtual page in pixel. + const int leftBorder = 2; + const int rightBorder = 4; // because of shadow + const int topBorder = 2; + const int bottomBorder = 4; // because of shadow + const int horzBorders = leftBorder + rightBorder; + const int vertBorders = topBorder + bottomBorder; + + // Calculate new zoom factor. + switch (_zoom) + { + case Zoom.BestFit: + BestFit: + //zoomPercent = Convert.ToInt32(25400.0 * (rcCanvas.Width - (leftBorder + rightBorder)) / (this.pageSize.Width * xdpiScreen)); + _zoomPercent = (int)(7200f * (rcCanvas.Width - horzBorders) / (_pageSize.Width * xdpiScreen)); + //--zoomPercent; // prevent round up errors + break; + + case Zoom.TextFit: + // TODO_OLD: 'public Rectangle TextBox' property + goto BestFit; + //zoomPercent = LongFromReal (25400.0 / (_cxUsedPage + 0) * + // (rcWnd.CX () - 2 * cxScrollbar) / xdpiScreen) - 3; + //break; + + case Zoom.FullPage: + { + //int zoomX = Convert.ToInt32(25400.0 / (pageSize.Width) * + // (rcCanvas.Width - (leftBorder + rightBorder)) / xdpiScreen); + //int zoomY = Convert.ToInt32(25400.0 / (pageSize.Height) * + // (rcCanvas.Height - (topBorder + bottomBorder)) / ydpiScreen); + int zoomX = (int)(7200f * (rcCanvas.Width - horzBorders) / (_pageSize.Width * xdpiScreen)); + int zoomY = (int)(7200f * (rcCanvas.Height - vertBorders) / (_pageSize.Height * ydpiScreen)); + _zoomPercent = Math.Min(zoomX, zoomY); + //--zoomPercent; // prevent round up errors + } + break; + + case Zoom.OriginalSize: + _zoomPercent = (int)(0.5 + 200f / (devInfo.ScaleX + devInfo.ScaleY)); + _zoomPercent = (int)(0.5 + 100f / devInfo.ScaleX); + break; + + default: + _zoomPercent = (int)_zoom; + break; + } + + // Bound to zoom limits + _zoomPercent = Math.Max(Math.Min(_zoomPercent, (int)Zoom.Maximum), (int)Zoom.Minimum); + if ((int)_zoom > 0) + _zoom = (Zoom)_zoomPercent; + + // Size of page in preview window in pixel + _virtualPage.X = leftBorder; + _virtualPage.Y = topBorder; + _virtualPage.Width = (int)(_pageSize.Width * xdpiScreen * _zoomPercent / 7200); + _virtualPage.Height = (int)(_pageSize.Height * ydpiScreen * _zoomPercent / 7200); + + //// 2540 := (25.4mm * 100%) / 1mm + //m_VirtualPrintableArea.X = (int)printableArea.X * this.zoomPercent * xdpiScreen / 2540; + //m_VirtualPrintableArea.Y = (int)printableArea.Y * this.zoomPercent * xdpiScreen / 2540; + //m_VirtualPrintableArea.Width = (int)printableArea.Width * this.zoomPercent * xdpiScreen / 2540; + //m_VirtualPrintableArea.Height = (int)printableArea.Height * this.zoomPercent * xdpiScreen / 2540; + + // Border do not depend on zoom anymore + _virtualCanvas = new Size(_virtualPage.Width + horzBorders, _virtualPage.Height + vertBorders); + + // Adjust virtual canvas to at least actual window size + if (_virtualCanvas.Width < rcCanvas.Width) + { + _virtualCanvas.Width = rcCanvas.Width; + _virtualPage.X = leftBorder + (rcCanvas.Width - horzBorders - _virtualPage.Width) / 2; + } + if (_virtualCanvas.Height < rcCanvas.Height) + { + _virtualCanvas.Height = rcCanvas.Height; + _virtualPage.Y = topBorder + (rcCanvas.Height - vertBorders - _virtualPage.Height) / 2; + } + + zoomChanged = zoomOld != _zoom || zoomPercentOld != _zoomPercent; + if (zoomChanged) + OnZoomChanged(EventArgs.Empty); + } + + internal void CalculatePreviewDimension() + { + CalculatePreviewDimension(out _); + } + + internal bool RenderPage(Graphics gfx) + { + //delete m_RenderContext; + //m_RenderContext = new HdcRenderContext(wdc.m_hdc); + + gfx.TranslateTransform(-_posOffset.X, -_posOffset.Y); + gfx.SetClip(new Rectangle(_virtualPage.X + 1, _virtualPage.Y + 1, _virtualPage.Width - 1, _virtualPage.Height - 1)); + + float scaleX = _virtualPage.Width / _pageSize.Width; + float scaleY = _virtualPage.Height / _pageSize.Height; + + //gfx.SetSmoothingMode(SmoothingModeAntiAlias); + //PaintBackground(gfx); + +#if DRAW_BMP + Matrix matrix = new Matrix(); + matrix.Translate(virtualPage.X, virtualPage.Y); + matrix.Translate(-posOffset.X, -this.posOffset.Y); + //matrix.Scale(scaleX, scaleY); + gfx.Transform = matrix; + +#if DRAW_X + gfx.DrawLine(Pens.Red, 0, 0, pageSize.Width, pageSize.Height); + gfx.DrawLine(Pens.Red, 0, pageSize.Height, pageSize.Width, 0); +#endif + if (renderEvent != null) + { + Bitmap bmp = new Bitmap(virtualPage.Width, this.virtualPage.Height, gfx); + Graphics gfx2 = Graphics.FromImage(bmp); + gfx2.Clear(pageColor); + gfx2.ScaleTransform(scaleX, scaleY); + gfx2.SmoothingMode = SmoothingMode.HighQuality; + XGraphics xgfx = XGraphics.FromGraphics(gfx2, new XSize(pageSize.Width, this.pageSize.Height)); + try + { + renderEvent(xgfx); + gfx.DrawImage(bmp, 0, 0); + } + finally + { + bmp.Dispose(); + } + } +#else + Matrix matrix = new Matrix(); + matrix.Translate(_virtualPage.X, _virtualPage.Y); + matrix.Translate(-_posOffset.X, -_posOffset.Y); + matrix.Scale(scaleX, scaleY); + gfx.Transform = matrix; + +#if DRAW_X + gfx.DrawLine(Pens.Red, 0, 0, pageSize.Width, pageSize.Height); + gfx.DrawLine(Pens.Red, 0, pageSize.Height, pageSize.Width, 0); +#endif + + if (_renderAction != null!) + { + gfx.SmoothingMode = SmoothingMode.HighQuality; + XGraphics xgfx = XGraphics.FromGraphics(gfx, new XSize(_pageSize.Width, _pageSize.Height), PageGraphicsUnit, null!); + try + { + _renderAction(xgfx); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Exception"); + } + } +#endif + + // Old C++ stuff, may be useful later... +#if false + switch (m_mode) + { + case RenderModeDirect: + { + delete m_PreviewMetafile; + m_PreviewMetafile = NULL; + + float cxPage = Metric::MillimetersToPoints(m_dimPage.cx / 10.0f); + float cyPage = Metric::MillimetersToPoints(m_dimPage.cy / 10.0f); + + float scaleX = virtualPage.Width / cxPage; + float scaleY = virtualPage.Height / cyPage; + + Graphics gfx(m_RenderContext); + gfx.SetSmoothingMode(SmoothingModeAntiAlias); + PaintBackground(gfx, &virtualPage); + + Matrix matrix; + matrix.Translate((float)virtualPage.X, (float)virtualPage.Y); + matrix.Translate((float) - m_posOffset.x, (float) -m_posOffset.y); + matrix.Scale(scaleX, scaleY); + + m_RenderContext->SetDefaultViewMatrix(&matrix); + gfx.ResetTransform(); + if (m_PreviewRenderer && m_PreviewRenderer->CanRender()) + m_PreviewRenderer->Render(&gfx, m_Page); + } + break; + + case RenderModeMetafile: + { + Graphics gfx(m_RenderContext); + if (m_PreviewMetafile == NULL) + { + float cxPage = Metric::MillimetersToPoints(m_dimPage.cx / 10.0f); + float cyPage = Metric::MillimetersToPoints(m_dimPage.cy / 10.0f); + + //float factor = 72.0f / 96.0f; + Rect rcLogicalPage(0, 0, (int)cxPage, (int)cyPage); + RectF rcFLogicalPage(0, 0, cxPage, cyPage); + + //DeviceName devname; + //DESKTOP::QueryDefaultPrinter(devname); //HACK DRUCKER MUSS DA SEIN! + //DeviceMode devmode(devname); + + //HDC hdc = ::CreateIC(devname.m_szDriver, devname.m_szDevice, devname.m_szOutput, devmode.m_pdm); + + //HDC hdc = m_Graphics->GetHDC(); + //HDC hdc = ::GetDC(NULL); + HDC hdc = ::CreateIC("DISPLAY", NULL, NULL, NULL); + + + float dpiX = gfx.GetDpiX(); + float dpiY = gfx.GetDpiY(); + + // Even Petzold would be surprised about that... + // Display | LaserJet + // DPI 96 : 120 | 300 + // physical device size in MM --------------------------------------------- + int horzSizeMM = ::GetDeviceCaps(hdc, HORZSIZE); // = 330 : 254 | 198 (not 210) + int vertSizeMM = ::GetDeviceCaps(hdc, VERTSIZE); // = 254 : 203 | 288 (hot 297) + + // device size in pixel + int horzSizePixel = ::GetDeviceCaps(hdc, HORZRES); // = 1280 : 1280 | 4676 + int vertSizePixel = ::GetDeviceCaps(hdc, VERTRES); // = 1024 : 1024 | 6814 + + // 'logical' device resolution in DPI + int logResX = ::GetDeviceCaps(hdc, LOGPIXELSX); // = 96 : 120 | 600 + int logResY = ::GetDeviceCaps(hdc, LOGPIXELSY); // = 96 : 120 | 600 + + // physical pixel size in .01 MM units + // accidentally(?) the result of GetPhysicalDimension! + //float X1 = 100.0f * horzSizeMM / horzSizePixel; // = 25.781250 : 19.843750 | 4.2343884 + //float Y1 = 100.0f * vertSizeMM / vertSizePixel; // = 24.804688 : 19.824219 | 4.2265925 + + // now we can get the 'physical' device resolution... + float phyResX = horzSizePixel / (horzSizeMM / 25.4f); // = 98.521210 : 128.00000 | 599.85052 + float phyResY = vertSizePixel / (vertSizeMM / 25.4f); // = 102.40000 : 128.12611 | 600.95691 + + // ...and rescale the size of the meta rectangle. + float magicX = logResX / phyResX; // = 0.97440946 : 0.93750000 | 1.0002491 + float magicY = logResY / phyResY; // = 0.93750000 : 0.93657720 | 0.99840766 + + // use A4 page in point + // adjust size of A4 page so that meta file fits with DrawImage... + RectF rcMagic(0, 0, magicX * cxPage, magicY * cyPage); + m_PreviewMetafile = new Metafile(hdc, rcMagic, MetafileFrameUnitPoint, + EmfTypeEmfPlusOnly, L"some description"); + + SizeF size; + float horzRes, vertRes; + float height, width; + MetafileHeader metafileHeader; + + // GetPhysicalDimension returns physical size of a pixel in .01 MM units!! + m_PreviewMetafile->GetPhysicalDimension(&size); + + horzRes = (float)m_PreviewMetafile->GetHorizontalResolution(); + vertRes = (float)m_PreviewMetafile->GetVerticalResolution(); + height = (float)m_PreviewMetafile->GetHeight(); + width = (float)m_PreviewMetafile->GetWidth(); + m_PreviewMetafile->GetMetafileHeader(&metafileHeader); + + Graphics gfxMf(m_PreviewMetafile); + dpiX = gfxMf.GetDpiX(); + dpiY = gfxMf.GetDpiY(); + + m_PreviewMetafile->GetPhysicalDimension(&size); + horzRes = (float)m_PreviewMetafile->GetHorizontalResolution(); + vertRes = (float)m_PreviewMetafile->GetVerticalResolution(); + height = (float)m_PreviewMetafile->GetHeight(); + width = (float)m_PreviewMetafile->GetWidth(); + m_PreviewMetafile->GetMetafileHeader(&metafileHeader); + + gfxMf.SetPageUnit(UnitPoint); + if (m_PreviewRenderer && m_PreviewRenderer->CanRender()) + m_PreviewRenderer->Render(&gfxMf, m_Page); + + ::DeleteDC(hdc); + } + if (m_PreviewMetafile) + { + gfx.SetSmoothingMode(SmoothingModeAntiAlias); + PaintBackground(gfx, &virtualPage); + //Matrix matrix(1, 0, 0, 1, (float) - m_posOffset.x, (float) - m_posOffset.y); + m_RenderContext->SetDefaultViewMatrix(&matrix); + gfx.ResetTransform(); + gfx.DrawImage(m_PreviewMetafile, virtualPage); + } + } + break; + + case RenderModeBitmap: + break; + } +#endif + return true; + } + + /// + /// Paints the background and the empty page. + /// + internal void PaintBackground(Graphics gfx) + { + // Draw sharp paper borders and shadow. + gfx.SmoothingMode = SmoothingMode.None; + //gfx.SetCompositingMode(CompositingModeSourceOver); // CompositingModeSourceCopy + //gfx.SetCompositingQuality(CompositingQualityHighQuality); + + gfx.TranslateTransform(-_posOffset.X, -_posOffset.Y); + + // Draw outer area. Use clipping to prevent flickering of page interior. + gfx.SetClip(new Rectangle(_virtualPage.X, _virtualPage.Y, _virtualPage.Width + 3, _virtualPage.Height + 3), CombineMode.Exclude); + gfx.SetClip(new Rectangle(_virtualPage.X + _virtualPage.Width + 1, _virtualPage.Y, 2, 2), CombineMode.Union); + gfx.SetClip(new Rectangle(_virtualPage.X, _virtualPage.Y + _virtualPage.Height + 1, 2, 2), CombineMode.Union); + gfx.Clear(_desktopColor); + +#if DRAW_X + gfx.DrawLine(Pens.Blue, 0, 0, virtualCanvas.Width, virtualCanvas.Height); + gfx.DrawLine(Pens.Blue, virtualCanvas.Width, 0, 0, virtualCanvas.Height); +#endif + gfx.ResetClip(); + +#if !DRAW_BMP + // Fill page interior. + SolidBrush brushPaper = new SolidBrush(_pageColor); + gfx.FillRectangle(brushPaper, _virtualPage.X + 1, _virtualPage.Y + 1, _virtualPage.Width - 1, _virtualPage.Height - 1); +#endif + + //// draw non printable area + //if (m_ShowNonPrintableArea) + //{ + //SolidBrush brushNPA(+DESKTOP::QuerySysColor((SYSCLR_3DLIGHT)) | 0xFF000000); + // + //gfx.FillRectangle(&brushNPA, virtualPage.X, virtualPage.Y, virtualPage.Width, rcPrintableArea.Y - virtualPage.Y); + //gfx.FillRectangle(&brushNPA, virtualPage.X, virtualPage.Y, rcPrintableArea.X - virtualPage.X, virtualPage.Height); + //gfx.FillRectangle(&brushNPA, rcPrintableArea.X + rcPrintableArea.Width, + //virtualPage.Y, virtualPage.X + virtualPage.Width - (rcPrintableArea.X + rcPrintableArea.Width), virtualPage.Height); + //gfx.FillRectangle(&brushNPA, virtualPage.X, rcPrintableArea.Y + rcPrintableArea.Height, + //virtualPage.Width, virtualPage.Y + virtualPage.Height - (rcPrintableArea.Y + rcPrintableArea.Height)); + //} + //DrawDash(gfx, virtualPage); + + // Draw page border and shadow. + Pen penPaperBorder = SystemPens.WindowText; + Brush brushShadow = SystemBrushes.ControlDarkDark; + gfx.DrawRectangle(penPaperBorder, _virtualPage); + gfx.FillRectangle(brushShadow, _virtualPage.X + _virtualPage.Width + 1, _virtualPage.Y + 2, 2, _virtualPage.Height + 1); + gfx.FillRectangle(brushShadow, _virtualPage.X + 2, _virtualPage.Y + _virtualPage.Height + 1, _virtualPage.Width + 1, 2); + } + + /// + /// Check clipping rectangle calculations. + /// + [Conditional("DEBUG")] + void DrawDash(Graphics gfx, Rectangle rect) + { + Pen pen = new Pen(Color.GreenYellow, 1); + pen.DashStyle = DashStyle.Dash; + gfx.DrawRectangle(pen, rect); + } + + /// + /// Adjusts scroll bars. + /// + void SetScrollBarRange() + { + // Windows 7 issue: Must invalidate scroll bars to ensure that + // the arrows are painted correctly. + + Rectangle clientRect = _canvas.ClientRectangle; + Size clientAreaSize = clientRect.Size; + + // Scroll range + int dx = _virtualCanvas.Width - clientAreaSize.Width; + int dy = _virtualCanvas.Height - clientAreaSize.Height; + + //bool extendX = clientAreaSize.Width < virtualCanvas.Width; + //bool extendY = clientAreaSize.Height < virtualCanvas.Height; + + if (ShowScrollbars && _hScrollBar != null!) + { + if (_posOffset.X > dx) + _hScrollBar.Value = _posOffset.X = dx; + + if (dx > 0) + { + _hScrollBar.Minimum = 0; + _hScrollBar.Maximum = _virtualCanvas.Width; + _hScrollBar.SmallChange = clientAreaSize.Width / 10; + _hScrollBar.LargeChange = clientAreaSize.Width; + _hScrollBar.Enabled = true; + } + else + { + _hScrollBar.Minimum = 0; + _hScrollBar.Maximum = 0; + _hScrollBar.Enabled = false; + } + _hScrollBar.Invalidate(); + } + + if (ShowScrollbars && _vScrollBar != null!) + { + if (_posOffset.Y > dy) + _vScrollBar.Value = _posOffset.Y = dy; + + if (dy > 0) + { + _vScrollBar.Minimum = 0; + _vScrollBar.Maximum = _virtualCanvas.Height; + _vScrollBar.SmallChange = clientAreaSize.Height / 10; + _vScrollBar.LargeChange = clientAreaSize.Height; + _vScrollBar.Enabled = true; + } + else + { + _vScrollBar.Minimum = 0; + _vScrollBar.Maximum = 0; + _vScrollBar.Enabled = false; + } + _vScrollBar.Invalidate(); + } + } + + ///// + ///// Calculates two interesting values... + ///// + //public static void GetMagicValues(IntPtr hdc, out float magicX, out float magicY) + //{ + // // Even Petzold would be surprised about that... + + // // Physical device size in MM + // int horzSizeMM = GetDeviceCaps(hdc, HORZSIZE); + // int vertSizeMM = GetDeviceCaps(hdc, VERTSIZE); + // // + // // Display size in pixels 1600 x 1200 1280 x 1024 + // // + // // My old Sony display with 96 DPI: --- 330 x 254 + // // My old Sony display with 120 DPI: --- 254 x 203 + // // My current Sony display with 96 DPI: 410 x 310 410 x 310 + // // My current Sony display with 120 DPI: 410 x 310 410 x 310 + // // My old Sony display with 96 DPI: --- 360 x 290 + // // My old Sony display with 120 DPI: --- 360 x 290 + // // My LaserJet 6L (300 DPI): 198 (not 210) x 288 (nscot 297) + + + // // Device size in pixel + // int horzSizePixel = GetDeviceCaps(hdc, HORZRES); + // int vertSizePixel = GetDeviceCaps(hdc, VERTRES); + // // + // // Display size in pixels 1600 x 1200 1280 x 1024 + // // + // // My old Sony display with 96 DPI: --- 1280 x 1024 + // // My old Sony display with 120 DPI: --- 1280 x 1024 + // // My current Sony display with 96 DPI: 1600 x 1200 1280 x 1024 + // // My current Sony display with 120 DPI: 1600 x 1200 1280 x 1024 + // // + // // My LaserJet 6L (600 DPI): 4676 x 6814 + + // // 'logical' device resolution in DPI + // int logResX = GetDeviceCaps(hdc, LOGPIXELSX); + // int logResY = GetDeviceCaps(hdc, LOGPIXELSY); + // // + // // Display size in pixels 1600 x 1200 1280 x 1024 + // // + // // My old Sony display with 96 DPI: --- 96 x 96 + // // My old Sony display with 120 DPI: --- 120 x 120 + // // My current Sony display with 96 DPI: 96 x 96 96 x 96 + // // My current Sony display with 120 DPI: 120 x 120 120 x 120 + // // + // // My LaserJet 6L (600 DPI): 600 x 600 + + // // physical pixel size in .01 MM units + // // accidentally(?) the result of GetPhysicalDimension! + // //float X1 = 100.0f * horzSizeMM / horzSizePixel; // = 25.781250 : 19.843750 | 4.2343884 + // //float Y1 = 100.0f * vertSizeMM / vertSizePixel; // = 24.804688 : 19.824219 | 4.2265925 + + // // Now we can get the 'physical' device resolution... + // float phyResX = horzSizePixel / (horzSizeMM / 25.4f); + // float phyResY = vertSizePixel / (vertSizeMM / 25.4f); + // // + // // Display size in pixels 1600 x 1200 1280 x 1024 + // // + // // My old Sony display with 96 DPI: --- 98.521210 x 102.40000 + // // My old Sony display with 120 DPI: --- 128.00000 x 128.12611 + // // My current Sony display with 96 DPI: 99.12195 x 98.32258 79.29756 x 83.90193 + // // My current Sony display with 120 DPI: 99.12195 x 98.32258 79.29756 x 83.90193 + // // + // // My LaserJet 6L (600 DPI): 599.85052 x 600.95691 + + // // ...and rescale the size of the meta rectangle. + // magicX = logResX / phyResX; + // magicY = logResY / phyResY; + // // + // // Display size in pixels 1600 x 1200 1280 x 1024 + // // + // // My old Sony display with 96 DPI: --- 0.97440946 x 0.93750000 + // // My old Sony display with 120 DPI: --- 0.93750000 x 0.93657720 + // // My current Sony display with 96 DPI: 0.968503952 x 0.976377964 1.21062994 x 1.14419293 + // // My current Sony display with 120 DPI: 1.21062994 x 1.22047246 1.51328743 x 1.43024123 + // // + // // My LaserJet 6L (600 DPI): 1.0002491 x 0.99840766 + //} + + //[DllImport("gdi32.dll")] + //static extern int GetDeviceCaps(IntPtr hdc, int capability); + //const int HORZSIZE = 4; + //const int VERTSIZE = 6; + //const int HORZRES = 8; + //const int VERTRES = 10; + //const int LOGPIXELSX = 88; + //const int LOGPIXELSY = 90; + + /// + /// Upper left corner of scroll area. + /// + Point _posOffset; + + /// + /// Real page size in point. + /// + SizeF _pageSize = PageSizeConverter.ToSize(PdfSharp.PageSize.A4).ToSizeF(); + + /// + /// Page in pixel relative to virtual canvas. + /// + Rectangle _virtualPage; + + /// + /// The size in pixels of an area that completely contains the virtual page and at least a small + /// border around it. If this area is larger than the canvas window, it is scrolled. + /// + Size _virtualCanvas; + + ///// + ///// Printable area in point. + ///// + //readonly RectangleF _printableArea; + } +} diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/MdPdfMsgs.de.resx b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreview.resx similarity index 53% rename from src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/MdPdfMsgs.de.resx rename to src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreview.resx index 1b7707d9..5d320b1a 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/MdPdfMsgs.de.resx +++ b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreview.resx @@ -1,9 +1,9 @@ - + - - - - - - - - - - - - - - - - - - - + - @@ -109,52 +89,42 @@ text/microsoft-resx - 2.0 + 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Ihre Benutzereingaben führten zu einem leeren Bildbereich. - - - Bild nicht gefunden. - - - Bild nicht eingelesen. - - - Die Zahl {0} ist zu groß für eine Darstellung in Buchstaben. + + True - - Lesezeichen '{0}' ist innerhalb des Dokuments nicht definiert. + + False - - Ungültiger Bildtyp: '{0}'. + + False - - Die Zahl {0} ist zu groß für eine Darstellung in römischen Ziffern. + + PagePreview - - Bild '{0}' nicht gefunden. + + False - - '{0}' muss vor dem Aufruf von '{1}' gesetzt werden. + + 80 - - Leerer Bildbereich. + + (Default) - - Ungültiger Bildtyp. + + False - - Nur Bilder, Textrahmen, Diagramme und Absätze können frei gerendert werden. + + Private - - Bild '{0}' konnte nicht eingelesen werden. Es trat eine Ausnahme mit der folgenden Meldung auf: -{1} + + 4, 4 \ No newline at end of file diff --git a/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreviewCanvas.cs b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreviewCanvas.cs new file mode 100644 index 00000000..8b17ed04 --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreviewCanvas.cs @@ -0,0 +1,61 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System; +using System.Collections; +using System.ComponentModel; +#if GDI +using System.Drawing; +using System.Windows.Forms; +#endif +#if Wpf +using System.Windows.Media; +#endif + +#if !GDI +#error This file must only be included in GDI build. +#endif + +namespace PdfSharp.Forms +{ + /// + /// Implements the control that previews the page. + /// + class PagePreviewCanvas : System.Windows.Forms.Control + { + public PagePreviewCanvas(PagePreview preview) + { + _preview = preview; + SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true); + } + PagePreview _preview; + + protected override void OnPaint(PaintEventArgs e) + { + if (!_preview._showPage) + return; + + Graphics gfx = e.Graphics; + bool zoomChanged; + _preview.CalculatePreviewDimension(out zoomChanged); + _preview.RenderPage(gfx); + } + + protected override void OnPaintBackground(PaintEventArgs e) + { + if (!_preview._showPage) + { + e.Graphics.Clear(_preview._desktopColor); + return; + } + bool zoomChanged; + _preview.CalculatePreviewDimension(out zoomChanged); + _preview.PaintBackground(e.Graphics); + } + + protected override void OnSizeChanged(EventArgs e) + { + Invalidate(); + } + } +} diff --git a/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreviewCanvas.resx b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreviewCanvas.resx new file mode 100644 index 00000000..3f337e08 --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/PagePreviewCanvas.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/enums/RenderMode.cs b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/enums/RenderMode.cs new file mode 100644 index 00000000..97adae46 --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/enums/RenderMode.cs @@ -0,0 +1,28 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +#if GDI +namespace PdfSharp.Forms +{ + /// + /// Specifies how to render the preview. + /// + public enum RenderMode + { + /// + /// Draw immediately. + /// + Direct = 0, + + /// + /// Draw using a metafile. + /// + Metafile = 1, + + /// + /// Draw using a bitmap image. + /// + Bitmap = 2 + } +} +#endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/enums/Zoom.cs b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/enums/Zoom.cs new file mode 100644 index 00000000..04a353c6 --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/Forms/enums/Zoom.cs @@ -0,0 +1,94 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +#if GDI +namespace PdfSharp.Forms +{ + /// + /// Defines a zoom factor used in the preview control. + /// + public enum Zoom + { + /// + /// The smallest possible zoom factor. + /// + Minimum = 10, + + /// + /// The largest possible zoom factor. + /// + Maximum = 800, + + /// + /// A pre-defined zoom factor. + /// + Percent800 = 800, + + /// + /// A pre-defined zoom factor. + /// + Percent600 = 600, + + /// + /// A pre-defined zoom factor. + /// + Percent400 = 400, + + /// + /// A pre-defined zoom factor. + /// + Percent200 = 200, + + /// + /// A pre-defined zoom factor. + /// + Percent150 = 150, + + /// + /// A pre-defined zoom factor. + /// + Percent100 = 100, + + /// + /// A pre-defined zoom factor. + /// + Percent75 = 75, + + /// + /// A pre-defined zoom factor. + /// + Percent50 = 50, + + /// + /// A pre-defined zoom factor. + /// + Percent25 = 25, + + /// + /// A pre-defined zoom factor. + /// + Percent10 = 10, + + /// + /// Sets the zoom factor so that the document fits horizontally into the window. + /// + BestFit = -1, + + /// + /// Sets the zoom factor so that the printable area of the document fits horizontally into the window. + /// Currently not yet implemented and the same as ZoomBestFit. + /// + TextFit = -2, + + /// + /// Sets the zoom factor so that the whole document fits completely into the window. + /// + FullPage = -3, + + /// + /// Sets the zoom factor so that the document is displayed in its real physical size (based on the DPI information returned from the OS for the current monitor). + /// + OriginalSize = -4, + } +} +#endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp-gdi/PdfSharp-gdi.csproj b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/PdfSharp-gdi.csproj index 7a0cb05a..9660d8cb 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp-gdi/PdfSharp-gdi.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp-gdi/PdfSharp-gdi.csproj @@ -2,7 +2,7 @@ library - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true PdfSharp true @@ -13,6 +13,8 @@ + true + true @@ -170,7 +172,7 @@ - + @@ -314,7 +316,7 @@ - + @@ -405,6 +407,9 @@ + + + diff --git a/src/foundation/src/PDFsharp/src/PdfSharp-wpf/PdfSharp-wpf.csproj b/src/foundation/src/PDFsharp/src/PdfSharp-wpf/PdfSharp-wpf.csproj index 9fc703b1..fe0ae4ed 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp-wpf/PdfSharp-wpf.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp-wpf/PdfSharp-wpf.csproj @@ -2,7 +2,7 @@ library - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true PdfSharp true @@ -169,7 +169,7 @@ - + @@ -313,7 +313,7 @@ - + diff --git a/src/foundation/src/PDFsharp/src/PdfSharp-wpf/Windows/PagePreview.xaml.cs b/src/foundation/src/PDFsharp/src/PdfSharp-wpf/Windows/PagePreview.xaml.cs index 9e68764e..75b9ce7b 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp-wpf/Windows/PagePreview.xaml.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp-wpf/Windows/PagePreview.xaml.cs @@ -75,7 +75,7 @@ public Canvas Canvas /// /// Sets the render function. /// - public void SetRenderFunction(Action renderFunction, RenderEvents renderEvents) + public void SetRenderFunction(Action renderFunction, RenderEvents? renderEvents = null) { if (canvas.Children.Count > 0) canvas.Children.Clear(); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes-gdi/PdfSharp.BarCodes-gdi.csproj b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes-gdi/PdfSharp.BarCodes-gdi.csproj index 1be8e542..7b4065d3 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes-gdi/PdfSharp.BarCodes-gdi.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes-gdi/PdfSharp.BarCodes-gdi.csproj @@ -2,13 +2,14 @@ library - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true PdfSharp true GDI True ..\..\..\..\..\StrongnameKey.snk + true @@ -39,7 +40,7 @@ - + diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes-wpf/PdfSharp.BarCodes-wpf.csproj b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes-wpf/PdfSharp.BarCodes-wpf.csproj index 852faa7b..acdcb75a 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes-wpf/PdfSharp.BarCodes-wpf.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes-wpf/PdfSharp.BarCodes-wpf.csproj @@ -2,7 +2,7 @@ library - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true PdfSharp true @@ -39,7 +39,7 @@ - + diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/Drawing.BarCodes/CodeDataMatrix.cs b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/Drawing.BarCodes/CodeDataMatrix.cs index de687c0f..5b45f2af 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/Drawing.BarCodes/CodeDataMatrix.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/Drawing.BarCodes/CodeDataMatrix.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. using System; @@ -119,7 +119,7 @@ static string CreateEncoding(DataMatrixEncoding dmEncoding, int length) } /// - /// Gets or sets the size of the Matrix Quiet Zone. + /// Gets or sets the size of the Matrix¹ Quiet Zone. /// public int QuietZone { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/Extensions.cs b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/Extensions.cs index 4bd65a76..6caa5a5a 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/Extensions.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/Extensions.cs @@ -1,4 +1,7 @@ -using System; +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/PdfSharp.BarCodes.csproj b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/PdfSharp.BarCodes.csproj index 0286935a..e1ebb1cd 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/PdfSharp.BarCodes.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp.BarCodes/PdfSharp.BarCodes.csproj @@ -2,7 +2,7 @@ library - net6.0;net8.0;netstandard2.0 + net8.0;net9.0;net10.0;netstandard2.0 PdfSharp CORE True @@ -18,7 +18,7 @@ - + diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.Charting-gdi/PdfSharp.Charting-gdi.csproj b/src/foundation/src/PDFsharp/src/PdfSharp.Charting-gdi/PdfSharp.Charting-gdi.csproj index 657d0d42..7ab21f61 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.Charting-gdi/PdfSharp.Charting-gdi.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp.Charting-gdi/PdfSharp.Charting-gdi.csproj @@ -2,12 +2,13 @@ library - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true PdfSharp.Charting true True ..\..\..\..\..\StrongnameKey.snk + true diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.Charting-gdi/PdfSharp.Charting-gdi.csproj - save b/src/foundation/src/PDFsharp/src/PdfSharp.Charting-gdi/PdfSharp.Charting-gdi.csproj - save index 303c62a8..f6de3245 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.Charting-gdi/PdfSharp.Charting-gdi.csproj - save +++ b/src/foundation/src/PDFsharp/src/PdfSharp.Charting-gdi/PdfSharp.Charting-gdi.csproj - save @@ -2,7 +2,7 @@ library - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true PdfSharp.Charting true diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.Charting-wpf/PdfSharp.Charting-wpf.csproj b/src/foundation/src/PDFsharp/src/PdfSharp.Charting-wpf/PdfSharp.Charting-wpf.csproj index f615f461..9ce77dc1 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.Charting-wpf/PdfSharp.Charting-wpf.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp.Charting-wpf/PdfSharp.Charting-wpf.csproj @@ -2,7 +2,7 @@ library - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true PdfSharp.Charting true diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.Charting/PdfSharp.Charting.csproj b/src/foundation/src/PDFsharp/src/PdfSharp.Charting/PdfSharp.Charting.csproj index 0cb4ed7b..2e5d3abf 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.Charting/PdfSharp.Charting.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp.Charting/PdfSharp.Charting.csproj @@ -2,7 +2,7 @@ library - net6.0;net8.0;netstandard2.0 + net8.0;net9.0;net10.0;netstandard2.0 PdfSharp True ..\..\..\..\..\StrongnameKey.snk diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.Cryptography/Pdf.Signatures/PdfSharpDefaultSigner.cs b/src/foundation/src/PDFsharp/src/PdfSharp.Cryptography/Pdf.Signatures/PdfSharpDefaultSigner.cs index 1a05f0d4..b9642363 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.Cryptography/Pdf.Signatures/PdfSharpDefaultSigner.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp.Cryptography/Pdf.Signatures/PdfSharpDefaultSigner.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. #if NET6_0_OR_GREATER @@ -34,7 +34,7 @@ public PdfSharpDefaultSigner(X509Certificate2 certificate, PdfMessageDigestType #if NET6_0_OR_GREATER TimeStampAuthorityUri = timeStampAuthorityUri; #else - // We dont know how to get a time stamp with .NET Standard. + // We don’t know how to get a time stamp with .NET Standard. // If you need it you must implement your own signer. if (timeStampAuthorityUri != null) throw new ArgumentException(nameof(timeStampAuthorityUri) + " must be null when using .NET Framework or .NET Standard."); @@ -60,7 +60,7 @@ public async Task GetSignatureSizeAsync() _signatureSize = (await GetSignatureAsync(new MemoryStream([0])).ConfigureAwait(false)).Length; if (MustAddTimeStamp) { - // Add arbitrary padding because TSA timestamp responses length seems to vary from one call to another by 1 byte. + // Add arbitrary padding because TSA timestamp response’s length seems to vary from one call to another by 1 byte. _signatureSize += 10; // 2 was found to be too small. Make it 10 to allow for some DSA variation. } else diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.Cryptography/PdfSharp.Cryptography.csproj b/src/foundation/src/PDFsharp/src/PdfSharp.Cryptography/PdfSharp.Cryptography.csproj index d0cfee0d..93a9cd84 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp.Cryptography/PdfSharp.Cryptography.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp.Cryptography/PdfSharp.Cryptography.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;netstandard2.0 + net8.0;net9.0;net10.0;netstandard2.0 PdfSharp True ..\..\..\..\..\StrongnameKey.snk @@ -16,7 +16,7 @@ - + diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/!internal/Directives.cs b/src/foundation/src/PDFsharp/src/PdfSharp/!internal/Directives.cs index 0ca45b67..5ad69353 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/!internal/Directives.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/!internal/Directives.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. // @@ -6,12 +6,20 @@ // Checks correct settings and obsolete conditional compilation symbols. // -#if !DEBUG && (TEST_CODE || TEST_CODE_) -// Ensure not to accidentally rename TEST_CODE to TEST_CODE_ -// This would compile code previously disabled with #if TEST_CODE_ -#warning ********************************************************* -#warning ***** TEST_CODE MUST BE UNDEFINED FOR FINAL RELEASE ***** -#warning ********************************************************* +#if !DEBUG && TEST_CODE +#warning *********************************************************** +#warning ***** ‘TEST_CODE’ MUST BE UNDEFINED FOR FINAL RELEASE ***** +#warning *********************************************************** +#endif + +#if TEST_CODE_ // ‘’ +// Ensure not to accidentally rename ‘TEST_CODE’ to ‘TEST_CODE_’. +// This would compile code previously disabled with ‘#if TEST_CODE_’. +// Rename ‘TEST_CODE’ always to ‘TEST_CODE_xxx’ in ‘Directory.Build.targets’. +#warning ***************************************************** +#warning ***** ‘TEST_CODE_’ MUST NEVER BE DEFINED ***** +#warning ***** THIS ACCIDENTALLY ACTIVATES EXCLUDED CODE ***** +#warning ***************************************************** #endif #if GDI && WPF diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/IImageImporter.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/IImageImporter.cs index a92c2298..9e1e7f9f 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/IImageImporter.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/IImageImporter.cs @@ -1,6 +1,8 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. +using Microsoft.Extensions.Logging; +using PdfSharp.Logging; using PdfSharp.Pdf; namespace PdfSharp.Drawing @@ -35,83 +37,110 @@ internal StreamReaderHelper(byte[] data) internal StreamReaderHelper(Stream stream, int streamLength) { - // TODO_OLD: Use the Stream as it is or ensure it is a MemoryStream? -#if CORE || GDI || WPF OriginalStream = stream; - // Only copy when necessary. - //MemoryStream ms; - if (stream is not MemoryStream ms) + + if (stream is MemoryStream ms) { - OwnedMemoryStream = ms = streamLength > -1 ? new MemoryStream(streamLength) : new(); -#if false - CopyStream(stream, ms); -#else - // For .NET 4: - stream.CopyTo(ms); -#endif + // If the given stream is a MemoryStream, work with it. + if (ms.TryGetBuffer(out var buffer)) + { + // Buffer is accessible - use it. + Data = buffer.Array ?? throw new ArgumentNullException(nameof(stream), "Stream has no content byte array."); + Length = (int)ms.Length; + // If buffer is larger than needed, create a new buffer with required size. + if (Data.Length > Length) + { + var tmp = new Byte[Length]; + Buffer.BlockCopy(Data, 0, tmp, 0, Length); + Data = tmp; + } + } + else + { + // Buffer of given stream is not accessible, so read stream into new buffer. + OwnedMemoryStream = new(streamLength); + stream.CopyTo(OwnedMemoryStream); + Data = OwnedMemoryStream.GetBuffer(); + Length = (int)OwnedMemoryStream.Length; + PdfSharpLogHost.Logger.LogWarning("LoadImage: MemoryStream with buffer that is not publicly visible was used. " + + "For better performance, set 'publiclyVisible' to true when creating the MemoryStream."); + } } - Data = ms.GetBuffer(); - Length = (int)ms.Length; - if (Data.Length > Length) + else { - var tmp = new Byte[Length]; - Buffer.BlockCopy(Data, 0, tmp, 0, Length); - Data = tmp; + // If the given stream is not a MemoryStream, copy the stream to a new MemoryStream. + if (streamLength > -1) + { + // Simple case: length of stream is known, create a MemoryStream with correct buffer size. + OwnedMemoryStream = new(streamLength); + stream.CopyTo(OwnedMemoryStream); + Data = OwnedMemoryStream.GetBuffer(); + Length = (int)OwnedMemoryStream.Length; + } + else + { + // Complex case: length of stream is not known. + // This only occurs with streams that do not support the Length property. + OwnedMemoryStream = new(); + stream.CopyTo(OwnedMemoryStream); + Data = OwnedMemoryStream.GetBuffer(); + Length = (int)OwnedMemoryStream.Length; + // If buffer is larger than needed, create a new buffer with required size. + if (Data.Length > Length) + { + var tmp = new Byte[Length]; + Buffer.BlockCopy(Data, 0, tmp, 0, Length); + Data = tmp; + } + } } -#else - // For Win_RT there is no GetBuffer() => alternative implementation for Win_RT. - // TODO_OLD: Are there advantages of GetBuffer()? It should reduce LOH fragmentation. - this.stream = stream; - this.stream.Position = 0; - if (this.stream.Length > Int32.MaxValue) - throw new ArgumentException("Stream is too large.", nameof(stream)); - Length = (int)this.stream.Length; - Data = new byte[Length]; - this.stream.Read(Data, 0, Length); -#endif } internal byte GetByte(int offset) { if (CurrentOffset + offset >= Length) - { - Debug.Assert(false); - return 0; - } + throw new InvalidOperationException("Index out of range."); + return Data[CurrentOffset + offset]; } internal ushort GetWord(int offset, bool bigEndian) { - return (ushort)(bigEndian ? - (GetByte(offset) << 8) + GetByte(offset + 1) : - GetByte(offset) + (GetByte(offset + 1) << 8)); + if (CurrentOffset + offset + 1 >= Length) + throw new InvalidOperationException("Index out of range."); + + return (ushort)(bigEndian + ? (Data[CurrentOffset + offset++] << 8) + Data[CurrentOffset + offset] + : Data[CurrentOffset + offset++] + (Data[CurrentOffset + offset] << 8)); } internal uint GetDWord(int offset, bool bigEndian) { - return (uint)(bigEndian ? - (GetWord(offset, true) << 16) + GetWord(offset + 2, true) : - GetWord(offset, false) + (GetWord(offset + 2, false) << 16)); + if (CurrentOffset + offset + 3 >= Length) + throw new InvalidOperationException("Index out of range."); + + // Are you a good developer? + // What’s wrong with this code? + //return (bigEndian + // ? ((uint)Data[CurrentOffset + offset++] << 24) + ((uint)Data[CurrentOffset + offset++] << 16) + // + ((uint)Data[CurrentOffset + offset++] << 8) + Data[CurrentOffset + offset] + // : Data[CurrentOffset + offset++] + ((uint)Data[CurrentOffset + offset++] << 8)) + // + ((uint)Data[CurrentOffset + offset++] << 16) + ((uint)Data[CurrentOffset + offset] << 24); + return (uint)(bigEndian + ? (Data[CurrentOffset + offset++] << 24) + + (Data[CurrentOffset + offset++] << 16) + + (Data[CurrentOffset + offset++] << 8) + + Data[CurrentOffset + offset] + : Data[CurrentOffset + offset++] + + (Data[CurrentOffset + offset++] << 8) + + (Data[CurrentOffset + offset++] << 16) + + (Data[CurrentOffset + offset] << 24)); } - //static void CopyStream(Stream input, Stream output) - //{ - // var buffer = new byte[65536]; - // int read; - // while ((read = input.Read(buffer, 0, buffer.Length)) > 0) - // { - // output.Write(buffer, 0, read); - // } - //} - /// /// Resets this instance. /// - public void Reset() - { - CurrentOffset = 0; - } + public void Reset() => CurrentOffset = 0; /// /// Gets the original stream. @@ -154,19 +183,18 @@ abstract class ImportedImage /// /// Initializes a new instance of the class. /// - protected ImportedImage(IImageImporter importer, ImagePrivateData? data) + protected ImportedImage(ImagePrivateData? data) { Data = data; if (data != null) data.Image = this; - //_importer = importer; } /// /// Initializes a new instance of the class. /// - protected ImportedImage(IImageImporter importer) - : this(importer, null) + protected ImportedImage() + : this(null) { } /// diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterBmp.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterBmp.cs index 27b689b5..a7e6c25b 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterBmp.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterBmp.cs @@ -19,7 +19,7 @@ class ImageImporterBmp : ImageImporterRoot, IImageImporter // Note: TestBitmapFileHeader updates stream.CurrentOffset on success. ImagePrivateDataBitmap ipd = new ImagePrivateDataBitmap(stream.Data, stream.Length); - ImportedImage ii = new ImportedImageBitmap(this, ipd); + ImportedImage ii = new ImportedImageBitmap(ipd); ii.Information.DefaultDPI = 96; // Assume 96 DPI if information not provided in the file. if (TestBitmapInfoHeader(stream, ii, offsetImageData)) @@ -174,8 +174,8 @@ class ImportedImageBitmap : ImportedImage /// /// Initializes a new instance of the class. /// - public ImportedImageBitmap(IImageImporter importer, ImagePrivateDataBitmap data) - : base(importer, data) + public ImportedImageBitmap(ImagePrivateDataBitmap data) + : base(data) { } internal override ImageData PrepareImageData(PdfDocumentOptions options) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterJpeg.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterJpeg.cs index 667baf67..c7096aed 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterJpeg.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterJpeg.cs @@ -26,7 +26,7 @@ class ImageImporterJpeg : ImageImporterRoot, IImageImporter stream.CurrentOffset += 2; var ipd = new ImagePrivateDataDct(stream.Data, stream.Length); - var ii = new ImportedImageJpeg(this, ipd); + var ii = new ImportedImageJpeg(ipd); ii.Information.DefaultDPI = 72; // Assume 72 DPI if information not provided in the file. if (TestJfifHeader(stream, ii)) { @@ -303,8 +303,12 @@ bool MoveToNextHeader(StreamReaderHelper stream) if (headerType == 0xd9) return false; - // Check for standalone markers. - if (headerType == 0x01 || headerType >= 0xd0 && headerType <= 0xd7) + // 0xff followed by 0x00 is not a valid JPEG tag. Skip this entry. + // If the value 0xFF is ever needed in a JPEG file, it must be escaped by immediately + // following it with 0x00. This is called "byte stuffing". + // Source: https://www.ccoderun.ca/programming/2017-01-31_jpeg/ + // Check for standalone markers 0x01 and 0xd0 through 0xd7. + if (headerType is 0x00 or 0x01 or >= 0xd0 and <= 0xd7) { stream.CurrentOffset += 2; return true; @@ -400,8 +404,8 @@ class ImportedImageJpeg : ImportedImage /// /// Initializes a new instance of the class. /// - public ImportedImageJpeg(IImageImporter importer, ImagePrivateDataDct data) - : base(importer, data) + public ImportedImageJpeg(ImagePrivateDataDct data) + : base(data) { } internal override ImageData PrepareImageData(PdfDocumentOptions options) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterPng.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterPng.cs index 3057e77a..d63d4f0a 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterPng.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Internal/ImageImporterPng.cs @@ -2,7 +2,7 @@ // See the LICENSE file in the solution root for more information. #if CORE -using PdfSharp.BigGustave; +using PdfSharp.Internal.Png.BigGustave; #endif using PdfSharp.Pdf; @@ -25,7 +25,7 @@ class ImageImporterPng : ImageImporterRoot, IImageImporter stream.CurrentOffset = 0; if (TestPngFileHeader(stream)) { - ImportedImage ii = new ImportedImagePng(this); + ImportedImage ii = new ImportedImagePng(); if (TestPngInfoHeader(stream, ii)) { return ii; @@ -551,8 +551,8 @@ class ImportedImagePng : ImportedImage /// /// Initializes a new instance of the class. /// - public ImportedImagePng(IImageImporter importer) - : base(importer) + public ImportedImagePng() + : base() { } internal override ImageData PrepareImageData(PdfDocumentOptions options) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Layout/XTextFormatter.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Layout/XTextFormatter.cs index b38c583f..bdb8b5f5 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Layout/XTextFormatter.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Layout/XTextFormatter.cs @@ -10,7 +10,7 @@ namespace PdfSharp.Drawing.Layout /// /// Represents a very simple text formatter. /// If this class does not satisfy your needs on formatting paragraphs, I recommend taking a look - /// at MigraDoc Foundation. Alternatively, you should copy this class in your own source code and modify it. + /// at MigraDoc. Alternatively, you should copy this class in your own source code and modify it. /// public class XTextFormatter { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/XGraphicsPdfRenderer.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/XGraphicsPdfRenderer.cs index 280f8ff3..32a856c6 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/XGraphicsPdfRenderer.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/XGraphicsPdfRenderer.cs @@ -46,7 +46,7 @@ public XGraphicsPdfRenderer(PdfPage page, XGraphics gfx, XGraphicsPdfPageOptions _options = options; _gfx = gfx; _content = new StringBuilder(); - page.RenderContent!._pdfRenderer = this; // NRT + page.RenderContent!.SetRenderer(this); _gfxState = new PdfGraphicsState(this); } @@ -78,17 +78,17 @@ public void Close() var content2 = _page.RenderContent!; // NRT content2.CreateStream(PdfEncoders.RawEncoding.GetBytes(GetContent())); - _gfx = default!; - _page.RenderContent!._pdfRenderer = default!; - _page.RenderContent = default!; - _page = default!; + _gfx = null!; + _page.RenderContent!.SetRenderer(null); + _page.RenderContent = null!; + _page = null!; } else if (_form != null!) { _form._pdfForm!.CreateStream(PdfEncoders.RawEncoding.GetBytes(GetContent())); // NRT - _gfx = default!; - _form.PdfRenderer = default!; - _form = default!; + _gfx = null!; + _form.PdfRenderer = null!; + _form = null!; } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapEncoder.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapEncoder.cs index b200bab5..92572bcb 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapEncoder.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapEncoder.cs @@ -68,10 +68,10 @@ public override void Save(Stream stream) } try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); Source._gdiImage.Save(stream, ImageFormat.Png); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF DiagnosticsHelper.ThrowNotImplementedException("Save..."); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapImage.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapImage.cs index ebd7a0ba..817e5a08 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapImage.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapImage.cs @@ -29,11 +29,11 @@ internal XBitmapImage(int width, int height) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); // Create a default 24-bit ARGB bitmap. _gdiImage = new Bitmap(width, height); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF DiagnosticsHelper.ThrowNotImplementedException("CreateBitmap"); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapSource.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapSource.cs index 78eb9bc9..b4c7b117 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapSource.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XBitmapSource.cs @@ -36,10 +36,10 @@ public override int PixelWidth #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.Width; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF int gdiWidth = _gdiImage.Width; @@ -71,10 +71,10 @@ public override int PixelHeight #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.Height; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF int gdiHeight = _gdiImage.Height; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XColor.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XColor.cs index 79886098..7f162c37 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XColor.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XColor.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. using System.ComponentModel; @@ -291,8 +291,8 @@ public static XColor FromName(string name) { #if GDI // The implementation in System.Drawing.dll is interesting. It uses a ColorConverter - // with hash tables, locking mechanisms etc. Im not sure what problems that solves. - // So I dont use the source, but the reflection. + // with hash tables, locking mechanisms etc. I’m not sure what problems that solves. + // So I don’t use the source, but the reflection. try { return new XColor((KnownColor)Enum.Parse(typeof(KnownColor), name, true)); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XFont.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XFont.cs index 329474fa..ab342412 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XFont.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XFont.cs @@ -374,7 +374,7 @@ void InitializeFromGdi() { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (GdiFontFamily != null!) { // Create font based on its family. @@ -401,7 +401,7 @@ void InitializeFromGdi() CreateDescriptorAndInitializeFontMetrics(); } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } #endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGlyphTypeface.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGlyphTypeface.cs index 45a7df93..d7b6c902 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGlyphTypeface.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGlyphTypeface.cs @@ -141,7 +141,7 @@ internal static XGlyphTypeface GetOrCreateFrom(string familyName, FontResolvingO try { // Lock around TryGetGlyphTypeface and AddGlyphTypeface. - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (GlyphTypefaceCache.TryGetGlyphTypeface(typefaceKey, out glyphTypeface)) { // Just return existing one. @@ -262,7 +262,7 @@ void LogErrorBecauseFontResolverThrowsException(string name, Exception ex) #endif GlyphTypefaceCache.AddGlyphTypeface(glyphTypeface); } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } return glyphTypeface; } @@ -277,7 +277,7 @@ public static XGlyphTypeface GetOrCreateFromGdi(GdiFont gdiFont) try { // Lock around TryGetGlyphTypeface and AddGlyphTypeface. - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); string typefaceKey = ComputeGtfKey(gdiFont); if (GlyphTypefaceCache.TryGetGlyphTypeface(typefaceKey, out glyphTypeface)) { @@ -300,7 +300,7 @@ public static XGlyphTypeface GetOrCreateFromGdi(GdiFont gdiFont) glyphTypeface = new XGlyphTypeface(typefaceKey, fontFamily, fontSource, styleSimulations, gdiFont); GlyphTypefaceCache.AddGlyphTypeface(glyphTypeface); } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } return glyphTypeface; } @@ -324,7 +324,7 @@ public static XGlyphTypeface GetOrCreateFromGdi(GdiFont gdiFont) // Lock around TryGetGlyphTypeface and AddGlyphTypeface. try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); // Create WPF glyph typeface. if (!wpfTypeface.TryGetGlyphTypeface(out var wpfGlyphTypeface)) @@ -359,7 +359,7 @@ public static XGlyphTypeface GetOrCreateFromGdi(GdiFont gdiFont) return glyphTypeface; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } #endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGraphics.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGraphics.cs index 595fbae8..a867471d 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGraphics.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGraphics.cs @@ -92,10 +92,10 @@ public sealed class XGraphics : IDisposable // MigraDoc comes here when creating a MeasureContext. try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); gfx = Graphics.FromHwnd(IntPtr.Zero); // BUG_OLD: Use measure image } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } _gsStack = new GraphicsStateStack(this); @@ -185,7 +185,7 @@ public sealed class XGraphics : IDisposable /// The page unit. /// The page direction. /// The render events. - XGraphics(Canvas canvas, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection, RenderEvents renderEvents) + XGraphics(Canvas canvas, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection, RenderEvents? renderEvents = null) { //throw new ArgumentNullException("canvas"); if (canvas == null!) @@ -412,7 +412,7 @@ public sealed class XGraphics : IDisposable /// /// Initializes a new instance of the XGraphics class used for drawing on a form. /// - XGraphics(XForm form, RenderEvents renderEvents) + XGraphics(XForm form, RenderEvents? renderEvents = null) { if (form == null!) throw new ArgumentNullException(nameof(form)); @@ -434,7 +434,7 @@ public sealed class XGraphics : IDisposable #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); TargetContext = XGraphicTargetContext.GDI; // If form.Owner is null create a meta file. if (form.Owner == null!) @@ -505,7 +505,7 @@ public sealed class XGraphics : IDisposable _renderer = new PdfSharp.Drawing.Pdf.XGraphicsPdfRenderer(form, this); _pageSize = form.Size; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } Initialize(); #endif #if WPF && !GDI @@ -571,7 +571,7 @@ public static XGraphics CreateMeasureContext(XSize size, XGraphicsUnit pageUnit, /// /// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object. /// - public static XGraphics FromGraphics(Graphics graphics, XSize size, RenderEvents renderEvents) + public static XGraphics FromGraphics(Graphics graphics, XSize size, RenderEvents? renderEvents = null) { // Creating a new instance is by design. var gfx = new XGraphics(graphics, size, XGraphicsUnit.Point, XPageDirection.Downwards, renderEvents); @@ -584,7 +584,7 @@ public static XGraphics FromGraphics(Graphics graphics, XSize size, RenderEvents /// /// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object. /// - public static XGraphics FromGraphics(Graphics graphics, XSize size, XGraphicsUnit unit, RenderEvents renderEvents) + public static XGraphics FromGraphics(Graphics graphics, XSize size, XGraphicsUnit unit, RenderEvents? renderEvents = null) { // Creating a new instance is by design. var gfx = new XGraphics(graphics, size, unit, XPageDirection.Downwards, renderEvents); @@ -618,7 +618,7 @@ public static XGraphics FromGraphics(Graphics graphics, XSize size, XGraphicsUni /// /// Creates a new instance of the XGraphics class from a System.Windows.Media.DrawingContext object. /// - public static XGraphics FromDrawingContext(DrawingContext drawingContext, XSize size, XGraphicsUnit unit, RenderEvents renderEvents) + public static XGraphics FromDrawingContext(DrawingContext drawingContext, XSize size, XGraphicsUnit unit, RenderEvents? renderEvents = null) { var gfx = new XGraphics(drawingContext, size, unit, XPageDirection.Downwards, renderEvents); @@ -632,7 +632,7 @@ public static XGraphics FromDrawingContext(DrawingContext drawingContext, XSize /// /// Creates a new instance of the XGraphics class from a System.Windows.Media.DrawingContext object. /// - public static XGraphics FromCanvas(Canvas canvas, XSize size, XGraphicsUnit unit, RenderEvents renderEvents) + public static XGraphics FromCanvas(Canvas canvas, XSize size, XGraphicsUnit unit, RenderEvents? renderEvents = null) { var gfx = new XGraphics(canvas, size, unit, XPageDirection.Downwards, renderEvents); @@ -791,13 +791,13 @@ public static XGraphics FromForm(XForm form) /// /// Creates a new instance of the XGraphics class from a PdfSharp.Drawing.XForm object. /// - public static XGraphics? FromImage(XImage image, RenderEvents renderEvents) + public static XGraphics? FromImage(XImage image, RenderEvents? renderEvents = null) => FromImage(image, XGraphicsUnit.Point, renderEvents); /// /// Creates a new instance of the XGraphics class from a PdfSharp.Drawing.XImage object. /// - public static XGraphics? FromImage(XImage image, XGraphicsUnit unit, RenderEvents renderEvents) + public static XGraphics? FromImage(XImage image, XGraphicsUnit unit, RenderEvents? renderEvents = null) { if (image == null) throw new ArgumentNullException(nameof(image)); @@ -854,7 +854,7 @@ void Initialize() { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (_gfx != null) matrix = _gfx.Transform; @@ -882,7 +882,7 @@ void Initialize() _gfx.Transform = (GdiMatrix)matrix; } } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } #endif #if WPF @@ -953,14 +953,14 @@ void Dispose(bool disposing) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); // GDI+ requires this to disassociate it from metafiles. if (_gfx != default!) _gfx.Dispose(); _gfx = null!; Metafile = null; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -1115,10 +1115,10 @@ public void DrawLine(XPen pen, double x1, double y1, double x2, double y2) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawLine(pen.RealizeGdiPen(), (float)x1, (float)y1, (float)x2, (float)y2); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -1170,10 +1170,10 @@ public void DrawLines(XPen pen, GdiPointF[] points) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawLines(pen.RealizeGdiPen(), points); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } _renderer?.DrawLines(pen, MakeXPointArray(points, 0, points.Length)); @@ -1199,10 +1199,10 @@ public void DrawLines(XPen pen, XPoint[] points) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawLines(pen.RealizeGdiPen(), XGraphics.MakePointFArray(points)); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -1323,10 +1323,10 @@ public void DrawBezier(XPen pen, double x1, double y1, double x2, double y2, { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawBezier(pen.RealizeGdiPen(), (float)x1, (float)y1, (float)x2, (float)y2, (float)x3, (float)y3, (float)x4, (float)y4); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -1403,10 +1403,10 @@ public void DrawBeziers(XPen pen, XPoint[] points) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawBeziers(pen.RealizeGdiPen(), MakePointFArray(points)!); // points is checked. } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -1588,10 +1588,10 @@ public void DrawCurve(XPen pen, XPoint[] points, double tension) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawCurve(pen.RealizeGdiPen(), MakePointFArray(points)!, (float)tension); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -1674,10 +1674,10 @@ public void DrawArc(XPen pen, double x, double y, double width, double height, d { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawArc(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -1747,10 +1747,10 @@ public void DrawRectangle(XPen pen, double x, double y, double width, double hei { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawRectangle(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -1816,10 +1816,10 @@ public void DrawRectangle(XBrush brush, double x, double y, double width, double { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.FillRectangle(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -1886,13 +1886,13 @@ public void DrawRectangle(XPen? pen, XBrush? brush, double x, double y, double w { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (brush != null) _gfx.FillRectangle(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height); if (pen != null) _gfx.DrawRectangle(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2016,13 +2016,13 @@ public void DrawRectangles(XPen? pen, XBrush? brush, Rectangle[] rectangles) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (brush != null) _gfx.FillRectangles(brush.RealizeGdiBrush(), rectangles); if (pen != null) _gfx.DrawRectangles(pen.RealizeGdiPen(), rectangles); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } if (_renderer != null) { @@ -2051,13 +2051,13 @@ public void DrawRectangles(XPen? pen, XBrush? brush, GdiRectF[] rectangles) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (brush != null) _gfx.FillRectangles(brush.RealizeGdiBrush(), rectangles); if (pen != null) _gfx.DrawRectangles(pen.RealizeGdiPen(), rectangles); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } if (_renderer != null) { @@ -2093,13 +2093,13 @@ public void DrawRectangles(XPen? pen, XBrush? brush, XRect[] rectangles) GdiRectF[] rects = MakeRectangleFArray(rectangles, 0, rectangles.Length); try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (brush != null) _gfx.FillRectangles(brush.RealizeGdiBrush(), rects); if (pen != null) _gfx.DrawRectangles(pen.RealizeGdiPen(), rects); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2292,12 +2292,12 @@ public void DrawRoundedRectangle(XPen? pen, XBrush? brush, double x, double y, d { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); XGraphicsPath path = new XGraphicsPath(); path.AddRoundedRectangle(x, y, width, height, ellipseWidth, ellipseHeight); DrawPath(pen, brush, path); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2362,10 +2362,10 @@ public void DrawEllipse(XPen pen, double x, double y, double width, double heigh { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawArc(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, 0, 360); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2426,10 +2426,10 @@ public void DrawEllipse(XBrush brush, double x, double y, double width, double h { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.FillEllipse(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2493,13 +2493,13 @@ public void DrawEllipse(XPen? pen, XBrush? brush, double x, double y, double wid { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (brush != null) _gfx.FillEllipse(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height); if (pen != null) _gfx.DrawArc(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, 0, 360); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2588,10 +2588,10 @@ public void DrawPolygon(XPen pen, XPoint[] points) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawPolygon(pen.RealizeGdiPen(), MakePointFArray(points)!); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2656,10 +2656,10 @@ public void DrawPolygon(XBrush brush, XPoint[] points, XFillMode fillMode) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.FillPolygon(brush.RealizeGdiBrush(), MakePointFArray(points), (FillMode)fillMode); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2727,13 +2727,13 @@ public void DrawPolygon(XPen? pen, XBrush? brush, XPoint[] points, XFillMode fil GdiPointF[] pts = MakePointFArray(points)!; try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (brush != null) _gfx.FillPolygon(brush.RealizeGdiBrush(), pts, (FillMode)fillMode); if (pen != null) _gfx.DrawPolygon(pen.RealizeGdiPen(), pts); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2800,10 +2800,10 @@ public void DrawPie(XPen pen, double x, double y, double width, double height, d { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawPie(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2861,10 +2861,10 @@ public void DrawPie(XBrush brush, double x, double y, double width, double heigh { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.FillPie(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -2921,13 +2921,13 @@ public void DrawPie(XPen? pen, XBrush? brush, double x, double y, double width, { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (brush != null) _gfx.FillPie(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); if (pen != null) _gfx.DrawPie(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -3287,7 +3287,7 @@ public void DrawClosedCurve(XPen? pen, XBrush? brush, XPoint[] points, XFillMode { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (brush != null) _gfx.FillClosedCurve(brush.RealizeGdiBrush(), MakePointFArray(points)!, (FillMode)fillMode, (float)tension); if (pen != null) @@ -3296,7 +3296,7 @@ public void DrawClosedCurve(XPen? pen, XBrush? brush, XPoint[] points, XFillMode _gfx.DrawClosedCurve(pen.RealizeGdiPen(), MakePointFArray(points)!, (float)tension, (FillMode)fillMode); } } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -3353,10 +3353,10 @@ public void DrawPath(XPen pen, XGraphicsPath path) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.DrawPath(pen.RealizeGdiPen(), path.GdipPath); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -3387,10 +3387,10 @@ public void DrawPath(XBrush brush, XGraphicsPath path) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.FillPath(brush.RealizeGdiBrush(), path.GdipPath); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -3424,13 +3424,13 @@ public void DrawPath(XPen? pen, XBrush? brush, XGraphicsPath path) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (brush != null) _gfx.FillPath(brush.RealizeGdiBrush(), path.GdipPath); if (pen != null) _gfx.DrawPath(pen.RealizeGdiPen(), path.GdipPath); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -3561,7 +3561,7 @@ public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectan try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdiRectF rect = layoutRectangle.ToRectangleF(); if (format.LineAlignment == XLineAlignment.BaseLine) { @@ -3578,7 +3578,7 @@ public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectan _gfx.DrawString(text, font.GdiFont, brush.RealizeGdiBrush(), rect, format.RealizeGdiStringFormat()); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -3943,7 +3943,7 @@ public void DrawImage(XImage image, double x, double y) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (image._gdiImage != null) { InterpolationMode interpolationMode = InterpolationMode.Invalid; @@ -3966,7 +3966,7 @@ public void DrawImage(XImage image, double x, double y) //_gfx.DrawLine(Pens.Red, (float)(x + width), (float)y, (float)x, (float)(y + height)); } } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4036,7 +4036,7 @@ public void DrawImage(XImage image, double x, double y, double width, double hei { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (image._gdiImage != null) { InterpolationMode interpolationMode = InterpolationMode.Invalid; @@ -4069,7 +4069,7 @@ public void DrawImage(XImage image, double x, double y, double width, double hei } } } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4154,7 +4154,7 @@ public void DrawImage(XImage image, XRect destRect, XRect srcRect, XGraphicsUnit { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (image._gdiImage != null!) { InterpolationMode interpolationMode = InterpolationMode.Invalid; @@ -4178,7 +4178,7 @@ public void DrawImage(XImage image, XRect destRect, XRect srcRect, XGraphicsUnit DrawMissingImageRect(new XRect(destRect.X, destRect.Y, destRect.Width, destRect.Height)); } } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4223,7 +4223,7 @@ void DrawMissingImageRect(XRect rect) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); float x = (float)rect.X; float y = (float)rect.Y; float width = (float)rect.Width; @@ -4232,7 +4232,7 @@ void DrawMissingImageRect(XRect rect) _gfx.DrawLine(Pens.Red, x, y, x + width, y + height); _gfx.DrawLine(Pens.Red, x + width, y, x, y + height); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4358,13 +4358,13 @@ public XGraphicsState Save() { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); xState = new XGraphicsState(_gfx != null! ? _gfx.Save() : null); InternalGraphicsState iState = new InternalGraphicsState(this, xState); iState.Transform = _transform; _gsStack.Push(iState); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4402,13 +4402,13 @@ public void Restore(XGraphicsState state) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gsStack.Restore(state.InternalState); if (_gfx != null!) _gfx.Restore(state.GdiState!); // BUG_OLD NRT _transform = state.InternalState.Transform; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4494,13 +4494,13 @@ public XGraphicsContainer BeginContainer(XRect dstRect, XRect srcRect, XGraphics { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GraphicsState? graphicsState = null; if (_gfx != null!) graphicsState = _gfx.Save(); xContainer = new XGraphicsContainer(graphicsState); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4549,11 +4549,11 @@ public void EndContainer(XGraphicsContainer container) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); // GdiState cannot be null if _gfx is not null. _gfx.Restore(container.GdiState!); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4596,10 +4596,10 @@ public XSmoothingMode SmoothingMode { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return (XSmoothingMode)_gfx.SmoothingMode; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4619,10 +4619,10 @@ public XSmoothingMode SmoothingMode { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.SmoothingMode = (SmoothingMode)value; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -4870,10 +4870,10 @@ void AddTransform(XMatrix transform, XMatrixOrder order) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.Transform = (GdiMatrix)matrix; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } } #endif @@ -4961,10 +4961,10 @@ public void IntersectClip(XGraphicsPath path) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.SetClip(path.GdipPath, CombineMode.Intersect); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF && !GDI @@ -4976,10 +4976,10 @@ public void IntersectClip(XGraphicsPath path) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gfx.SetClip(path._gdipPath, CombineMode.Intersect); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } else { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGraphicsPath.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGraphicsPath.cs index 1d28e5f7..6f566d09 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGraphicsPath.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XGraphicsPath.cs @@ -39,10 +39,10 @@ public XGraphicsPath() #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath = new GraphicsPath(); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathGeometry = new PathGeometry(); @@ -58,10 +58,10 @@ public XGraphicsPath(PointF[] points, byte[] types, XFillMode fillMode) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath = new GraphicsPath(points, types, (FillMode)fillMode); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF // Is true only in Hybrid build. _pathGeometry = new PathGeometry(); @@ -143,10 +143,10 @@ public XGraphicsPath Clone() #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); path.GdipPath = (GraphicsPath)GdipPath.Clone(); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI path.PathGeometry = PathGeometry.Clone(); @@ -224,10 +224,10 @@ public void AddLine(double x1, double y1, double x2, double y2) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddLine((float)x1, (float)y1, (float)x2, (float)y2); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF PathFigure figure = CurrentPathFigure; @@ -307,10 +307,10 @@ public void AddLines(XPoint[] points) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddLines(XGraphics.MakePointFArray(points)); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF PathFigure figure = CurrentPathFigure; @@ -397,10 +397,10 @@ public void AddBezier(double x1, double y1, double x2, double y2, double x3, dou #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddBezier((float)x1, (float)y1, (float)x2, (float)y2, (float)x3, (float)y3, (float)x4, (float)y4); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF PathFigure figure = CurrentPathFigure; @@ -495,10 +495,10 @@ public void AddBeziers(XPoint[] points) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddBeziers(XGraphics.MakePointFArray(points)); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF PathFigure figure = CurrentPathFigure; @@ -621,10 +621,10 @@ public void AddCurve(XPoint[] points, double tension) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddCurve(XGraphics.MakePointFArray(points), (float)tension); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF tension /= 3; @@ -699,10 +699,10 @@ public void AddCurve(XPoint[] points, int offset, int numberOfSegments, double t #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddCurve(XGraphics.MakePointFArray(points), offset, numberOfSegments, (float)tension); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF throw new NotImplementedException("AddCurve not yet implemented."); @@ -750,10 +750,10 @@ public void AddArc(double x, double y, double width, double height, double start #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddArc((float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF PathFigure figure = CurrentPathFigure; @@ -866,7 +866,7 @@ public void AddRectangle(XRect rect) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); // If rect is empty GDI+ removes the rect from the path. // This is not intended if the path is used for clipping. // See http://forum.pdfsharp.net/viewtopic.php?p=9433#p9433 @@ -877,7 +877,7 @@ public void AddRectangle(XRect rect) GdipPath.AddLines([rect.TopLeft.ToPointF(), rect.TopRight.ToPointF(), rect.BottomRight.ToPointF(), rect.BottomLeft.ToPointF()]); GdipPath.CloseFigure(); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF StartFigure(); @@ -928,10 +928,10 @@ public void AddRectangles(Rectangle[] rects) try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddRectangles(rects); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif @@ -947,10 +947,10 @@ public void AddRectangles(RectangleF[] rects) try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddRectangles(rects); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif @@ -968,10 +968,10 @@ public void AddRectangles(XRect[] rects) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddRectangle(rects[idx].ToRectangleF()); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF StartFigure(); @@ -1095,7 +1095,7 @@ public void AddRoundedRectangle(double x, double y, double width, double height, #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.StartFigure(); GdipPath.AddArc((float)(x + width - ellipseWidth), (float)y, (float)ellipseWidth, (float)ellipseHeight, -90, 90); GdipPath.AddArc((float)(x + width - ellipseWidth), (float)(y + height - ellipseHeight), (float)ellipseWidth, (float)ellipseHeight, 0, 90); @@ -1103,7 +1103,7 @@ public void AddRoundedRectangle(double x, double y, double width, double height, GdipPath.AddArc((float)x, (float)y, (float)ellipseWidth, (float)ellipseHeight, 180, 90); GdipPath.CloseFigure(); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI double ex = ellipseWidth / 2; @@ -1253,10 +1253,10 @@ public void AddEllipse(double x, double y, double width, double height) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddEllipse((float)x, (float)y, (float)width, (float)height); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI #if true @@ -1300,10 +1300,10 @@ public void AddPolygon(System.Drawing.Point[] points) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddPolygon(points); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif @@ -1331,10 +1331,10 @@ public void AddPolygon(PointF[] points) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddPolygon(points); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif @@ -1357,10 +1357,10 @@ public void AddPolygon(XPoint[] points) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddPolygon(XGraphics.MakePointFArray(points)); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI #if true @@ -1394,10 +1394,10 @@ public void AddPie(Rectangle rect, double startAngle, double sweepAngle) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddPie(rect, (float)startAngle, (float)sweepAngle); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif @@ -1431,10 +1431,10 @@ public void AddPie(double x, double y, double width, double height, double start #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddPie((float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI const string message = "AddPie: This operation is not yet implemented in WPF build."; @@ -1532,10 +1532,10 @@ public void AddClosedCurve(XPoint[] points, double tension) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddClosedCurve(XGraphics.MakePointFArray(points), (float)tension); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI tension /= 3; @@ -1573,10 +1573,10 @@ public void AddPath(XGraphicsPath path, bool connect) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddPath(path.GdipPath, connect); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathGeometry.AddGeometry(path.PathGeometry); @@ -1646,10 +1646,10 @@ public void AddString(string s, XFontFamily family, XFontStyleEx style, double e try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddString(s, family.GdiFamily, (int)style, (float)emSize, p, format.RealizeGdiStringFormat()); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF if (family.WpfFamily == null) @@ -1726,10 +1726,10 @@ public void AddString(string s, XFontFamily family, XFontStyleEx style, double e try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddString(s, family.GdiFamily, (int)style, (float)emSize, rect, format.RealizeGdiStringFormat()); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } /// @@ -1745,10 +1745,10 @@ public void AddString(string s, XFontFamily family, XFontStyleEx style, double e try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddString(s, family.GdiFamily, (int)style, (float)emSize, layoutRect, format.RealizeGdiStringFormat()); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } /// @@ -1828,10 +1828,10 @@ public void AddString(string s, XFontFamily family, XFontStyleEx style, double e try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.AddString(s, family.GdiFamily, (int)style, (float)emSize, rect, format.RealizeGdiStringFormat()); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF && !GDI if (family.WpfFamily == null) @@ -1972,10 +1972,10 @@ public void CloseFigure() #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.CloseFigure(); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathFigure figure = PeekCurrentFigure; @@ -1995,10 +1995,10 @@ public void StartFigure() #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.StartFigure(); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathFigure figure = CurrentPathFigure; @@ -2027,10 +2027,10 @@ public XFillMode FillMode #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.FillMode = (FillMode)value; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathGeometry.FillRule = value == XFillMode.Winding ? FillRule.Nonzero : FillRule.EvenOdd; @@ -2054,10 +2054,10 @@ public void Flatten() #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.Flatten(); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathGeometry = PathGeometry.GetFlattenedPathGeometry(); @@ -2076,10 +2076,10 @@ public void Flatten(XMatrix matrix) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.Flatten(matrix.ToGdiMatrix()); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathGeometry = PathGeometry.GetFlattenedPathGeometry(); @@ -2099,10 +2099,10 @@ public void Flatten(XMatrix matrix, double flatness) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.Flatten(matrix.ToGdiMatrix(), (float)flatness); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathGeometry = PathGeometry.GetFlattenedPathGeometry(); @@ -2127,10 +2127,10 @@ public void Widen(XPen pen) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.Widen(pen.RealizeGdiPen()); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathGeometry = PathGeometry.GetWidenedPathGeometry(pen.RealizeWpfPen()); @@ -2152,10 +2152,10 @@ public void Widen(XPen pen, XMatrix matrix) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.Widen(pen.RealizeGdiPen(), matrix.ToGdiMatrix()); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathGeometry = PathGeometry.GetWidenedPathGeometry(pen.RealizeWpfPen()); @@ -2174,10 +2174,10 @@ public void Widen(XPen pen, XMatrix matrix, double flatness) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); GdipPath.Widen(pen.RealizeGdiPen(), matrix.ToGdiMatrix(), (float)flatness); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF || WUI PathGeometry = PathGeometry.GetWidenedPathGeometry(pen.RealizeWpfPen()); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XImage.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XImage.cs index ea2ddbdd..48146f31 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XImage.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XImage.cs @@ -163,10 +163,10 @@ public static BitmapImage BitmapFromUri(Uri uri) #if GDI try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gdiImage = Image.FromFile(path); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF _wpfImage = BitmapFromUri(new Uri(path)); @@ -195,10 +195,10 @@ public static BitmapImage BitmapFromUri(Uri uri) // Create a GDI+ image. try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gdiImage = Image.FromStream(stream); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if WPF // Create a WPF BitmapImage. @@ -487,10 +487,10 @@ internal void Initialize() string guid; try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); guid = _gdiImage.RawFormat.Guid.ToString("B").ToUpper(); } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } switch (guid) { @@ -804,11 +804,11 @@ protected virtual void Dispose(bool disposing) { try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); _gdiImage.Dispose(); _gdiImage = null!; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } } #endif #if WPF @@ -836,10 +836,10 @@ public virtual double Width #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.Width; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF double gdiWidth = _gdiImage.Width; @@ -878,10 +878,10 @@ public virtual double Height #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.Height; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF double gdiHeight = _gdiImage.Height; @@ -939,10 +939,10 @@ public virtual double PointWidth #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.Width * 72 / _gdiImage.HorizontalResolution; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF double gdiWidth = _gdiImage.Width * 72 / _gdiImage.HorizontalResolution; @@ -990,10 +990,10 @@ public virtual double PointHeight #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.Height * 72 / _gdiImage.HorizontalResolution; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF double gdiHeight = _gdiImage.Height * 72 / _gdiImage.HorizontalResolution; @@ -1031,10 +1031,10 @@ public virtual int PixelWidth #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.Width; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF int gdiWidth = _gdiImage.Width; @@ -1071,10 +1071,10 @@ public virtual int PixelHeight #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.Height; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF int gdiHeight = _gdiImage.Height; @@ -1124,10 +1124,10 @@ public virtual double HorizontalResolution #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.HorizontalResolution; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF double gdiResolution = _gdiImage.HorizontalResolution; @@ -1172,10 +1172,10 @@ public virtual double VerticalResolution #if GDI && !WPF try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); return _gdiImage.VerticalResolution; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } #endif #if GDI && WPF double gdiResolution = _gdiImage.VerticalResolution; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XLinearGradientBrush.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XLinearGradientBrush.cs index ef43ab38..2adbb397 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XLinearGradientBrush.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XLinearGradientBrush.cs @@ -238,7 +238,7 @@ internal override System.Drawing.Brush RealizeGdiBrush() GdiLinearGradientBrush brush; try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (_useRect) { brush = new GdiLinearGradientBrush(_rect.ToRectangleF(), @@ -254,7 +254,7 @@ internal override System.Drawing.Brush RealizeGdiBrush() brush.Transform = _matrix.ToGdiMatrix(); //brush.WrapMode = WrapMode.Clamp; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } return brush; } #endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XMatrix.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XMatrix.cs index 5685bb27..f03a5f43 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XMatrix.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XMatrix.cs @@ -181,9 +181,7 @@ public void Multiply(XMatrix matrix, XMatrixOrder order) /// /// Appends a translation of the specified offsets to this matrix. /// - [Obsolete( - "Use TranslateAppend or TranslatePrepend explicitly, because in GDI+ and WPF the defaults are contrary.", - true)] + [Obsolete("Use TranslateAppend or TranslatePrepend explicitly, because in GDI+ and WPF the defaults are contrary.", true)] public void Translate(double offsetX, double offsetY) { throw new InvalidOperationException("Temporarily out of order."); @@ -261,8 +259,7 @@ public void Translate(double offsetX, double offsetY, XMatrixOrder order) /// /// Appends the specified scale vector to this matrix. /// - [Obsolete("Use ScaleAppend or ScalePrepend explicitly, because in GDI+ and WPF the defaults are contrary.", - true)] + [Obsolete("Use ScaleAppend or ScalePrepend explicitly, because in GDI+ and WPF the defaults are contrary.", true)] public void Scale(double scaleX, double scaleY) { this = CreateScaling(scaleX, scaleY) * this; @@ -315,8 +312,7 @@ public void Scale(double scaleX, double scaleY, XMatrixOrder order) /// /// Scales the matrix with the specified scalar. /// - [Obsolete("Use ScaleAppend or ScalePrepend explicitly, because in GDI+ and WPF the defaults are contrary.", - true)] + [Obsolete("Use ScaleAppend or ScalePrepend explicitly, because in GDI+ and WPF the defaults are contrary.", true)] // ReSharper disable InconsistentNaming public void Scale(double scaleXY) // ReSharper restore InconsistentNaming @@ -358,8 +354,7 @@ public void Scale(double scaleXY, XMatrixOrder order) /// /// Function is obsolete. /// - [Obsolete("Use ScaleAtAppend or ScaleAtPrepend explicitly, because in GDI+ and WPF the defaults are contrary.", - true)] + [Obsolete("Use ScaleAtAppend or ScaleAtPrepend explicitly, because in GDI+ and WPF the defaults are contrary.", true)] public void ScaleAt(double scaleX, double scaleY, double centerX, double centerY) { throw new InvalidOperationException("Temporarily out of order."); @@ -386,8 +381,7 @@ public void ScaleAtPrepend(double scaleX, double scaleY, double centerX, double /// /// Function is obsolete. /// - [Obsolete("Use RotateAppend or RotatePrepend explicitly, because in GDI+ and WPF the defaults are contrary.", - true)] + [Obsolete("Use RotateAppend or RotatePrepend explicitly, because in GDI+ and WPF the defaults are contrary.", true)] public void Rotate(double angle) { throw new InvalidOperationException("Temporarily out of order."); @@ -457,9 +451,7 @@ public void Rotate(double angle, XMatrixOrder order) /// /// Function is obsolete. /// - [Obsolete( - "Use RotateAtAppend or RotateAtPrepend explicitly, because in GDI+ and WPF the defaults are contrary.", - true)] + [Obsolete("Use RotateAtAppend or RotateAtPrepend explicitly, because in GDI+ and WPF the defaults are contrary.", true)] public void RotateAt(double angle, double centerX, double centerY) { throw new InvalidOperationException("Temporarily out of order."); @@ -488,9 +480,7 @@ public void RotateAtPrepend(double angle, double centerX, double centerY) /// /// Rotates the matrix with the specified angle at the specified point. /// - [Obsolete( - "Use RotateAtAppend or RotateAtPrepend explicitly, because in GDI+ and WPF the defaults are contrary.", - true)] + [Obsolete("Use RotateAtAppend or RotateAtPrepend explicitly, because in GDI+ and WPF the defaults are contrary.", true)] public void RotateAt(double angle, XPoint point) { throw new InvalidOperationException("Temporarily out of order."); @@ -539,8 +529,7 @@ public void RotateAt(double angle, XPoint point, XMatrixOrder order) /// /// Function is obsolete. /// - [Obsolete("Use ShearAppend or ShearPrepend explicitly, because in GDI+ and WPF the defaults are contrary.", - true)] + [Obsolete("Use ShearAppend or ShearPrepend explicitly, because in GDI+ and WPF the defaults are contrary.", true)] public void Shear(double shearX, double shearY) { throw new InvalidOperationException("Temporarily out of order."); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPen.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPen.cs index fd950c21..db29ce1e 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPen.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPen.cs @@ -241,7 +241,7 @@ public static implicit operator XPen(Pen pen) XPen xpen; try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); xpen = pen.PenType switch { PenType.SolidColor => new(pen.Color, pen.Width) @@ -263,7 +263,7 @@ public static implicit operator XPen(Pen pen) xpen._dashOffset = pen.DashOffset; } } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } return xpen; } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPoint.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPoint.cs index e3e67b5b..b80d06a6 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPoint.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPoint.cs @@ -109,18 +109,12 @@ public override bool Equals(object? o) /// /// Indicates whether this instance and a specified point are equal. /// - public bool Equals(XPoint value) - { - return Equals(this, value); - } + public bool Equals(XPoint value) => Equals(this, value); /// /// Returns the hash code for this instance. /// - public override int GetHashCode() - { - return X.GetHashCode() ^ Y.GetHashCode(); - } + public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode(); /// /// Parses the point from a string. @@ -177,45 +171,30 @@ public double Y /// /// Converts this XPoint to a System.Drawing.Point. /// - public PointF ToPointF() - { - return new PointF((float)_x, (float)_y); - } + public PointF ToPointF() => new((float)_x, (float)_y); #endif #if WPF || WUI /// /// Converts this XPoint to a System.Windows.Point. /// - public SysPoint ToPoint() - { - return new SysPoint(_x, _y); - } + public SysPoint ToPoint() => new(_x, _y); #endif /// - /// Converts this XPoint to a human readable string. + /// Converts this XPoint to a human-readable string. /// - public override string ToString() - { - return ConvertToString(null, null); - } + public override string ToString() => ConvertToString(null, null); /// - /// Converts this XPoint to a human readable string. + /// Converts this XPoint to a human-readable string. /// - public string ToString(IFormatProvider provider) - { - return ConvertToString(null, provider); - } + public string ToString(IFormatProvider provider) => ConvertToString(null, provider); /// - /// Converts this XPoint to a human readable string. + /// Converts this XPoint to a human-readable string. /// - string IFormattable.ToString(string? format, IFormatProvider? provider) - { - return ConvertToString(format, provider); - } + string IFormattable.ToString(string? format, IFormatProvider? provider) => ConvertToString(format, provider); /// /// Implements ToString. @@ -242,132 +221,96 @@ public void Offset(double offsetX, double offsetY) /// /// Adds a point and a vector. /// - public static XPoint operator +(XPoint point, XVector vector) - { - return new XPoint(point._x + vector.X, point._y + vector.Y); - } + public static XPoint operator +(XPoint point, XVector vector) => new(point._x + vector.X, point._y + vector.Y); /// /// Adds a point and a size. /// public static XPoint operator +(XPoint point, XSize size) // TODO_OLD: make obsolete - { - return new XPoint(point._x + size.Width, point._y + size.Height); - } + => new(point._x + size.Width, point._y + size.Height); /// /// Adds a point and a vector. /// public static XPoint Add(XPoint point, XVector vector) - { - return new XPoint(point._x + vector.X, point._y + vector.Y); - } + => new(point._x + vector.X, point._y + vector.Y); /// /// Subtracts a vector from a point. /// - public static XPoint operator -(XPoint point, XVector vector) - { - return new XPoint(point._x - vector.X, point._y - vector.Y); - } + public static XPoint operator -(XPoint point, XVector vector) + => new(point._x - vector.X, point._y - vector.Y); /// /// Subtracts a vector from a point. /// - public static XPoint Subtract(XPoint point, XVector vector) - { - return new XPoint(point._x - vector.X, point._y - vector.Y); - } + public static XPoint Subtract(XPoint point, XVector vector) + => new(point._x - vector.X, point._y - vector.Y); /// /// Subtracts a point from a point. /// - public static XVector operator -(XPoint point1, XPoint point2) - { - return new XVector(point1._x - point2._x, point1._y - point2._y); - } + public static XVector operator -(XPoint point1, XPoint point2) + => new(point1._x - point2._x, point1._y - point2._y); /// /// Subtracts a size from a point. /// [Obsolete("Use XVector instead of XSize as second parameter.")] - public static XPoint operator -(XPoint point, XSize size) - { - return new XPoint(point._x - size.Width, point._y - size.Height); - } + public static XPoint operator -(XPoint point, XSize size) + => new(point._x - size.Width, point._y - size.Height); /// /// Subtracts a point from a point. /// - public static XVector Subtract(XPoint point1, XPoint point2) - { - return new XVector(point1._x - point2._x, point1._y - point2._y); - } + public static XVector Subtract(XPoint point1, XPoint point2) + => new(point1._x - point2._x, point1._y - point2._y); /// /// Multiplies a point with a matrix. /// - public static XPoint operator *(XPoint point, XMatrix matrix) - { - return matrix.Transform(point); - } + public static XPoint operator *(XPoint point, XMatrix matrix) + => matrix.Transform(point); /// /// Multiplies a point with a matrix. /// - public static XPoint Multiply(XPoint point, XMatrix matrix) - { - return matrix.Transform(point); - } + public static XPoint Multiply(XPoint point, XMatrix matrix) + => matrix.Transform(point); /// /// Multiplies a point with a scalar value. /// - public static XPoint operator *(XPoint point, double value) - { - return new XPoint(point._x * value, point._y * value); - } + public static XPoint operator *(XPoint point, double value) + => new(point._x * value, point._y * value); /// /// Multiplies a point with a scalar value. /// - public static XPoint operator *(double value, XPoint point) - { - return new XPoint(value * point._x, value * point._y); - } + public static XPoint operator *(double value, XPoint point) + => new(value * point._x, value * point._y); /// /// Performs an explicit conversion from XPoint to XSize. /// - public static explicit operator XSize(XPoint point) - { - return new XSize(Math.Abs(point._x), Math.Abs(point._y)); - } + public static explicit operator XSize(XPoint point) + => new(Math.Abs(point._x), Math.Abs(point._y)); /// /// Performs an explicit conversion from XPoint to XVector. /// - public static explicit operator XVector(XPoint point) - { - return new XVector(point._x, point._y); - } + public static explicit operator XVector(XPoint point) => new(point._x, point._y); #if WPF || WUI /// /// Performs an implicit conversion from XPoint to Point. /// - public static implicit operator SysPoint(XPoint point) - { - return new SysPoint(point.X, point.Y); - } + public static implicit operator SysPoint(XPoint point) => new(point.X, point.Y); /// /// Performs an implicit conversion from Point to XPoint. /// - public static implicit operator XPoint(SysPoint point) - { - return new XPoint(point.X, point.Y); - } + public static implicit operator XPoint(SysPoint point) => new(point.X, point.Y); #endif /// diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPrivateFontCollection.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPrivateFontCollection.cs index b83b1b0c..09e3a0c1 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPrivateFontCollection.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XPrivateFontCollection.cs @@ -1,6 +1,7 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. +#if false // DELETE 2025-12-31 #if GDI using System.Runtime.InteropServices; using PdfSharp.Logging; @@ -28,3 +29,4 @@ namespace PdfSharp.Drawing public sealed class XPrivateFontCollection { } } +#endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XRadialGradientBrush.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XRadialGradientBrush.cs index dcbde7ea..a7ff5c0a 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XRadialGradientBrush.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XRadialGradientBrush.cs @@ -198,7 +198,7 @@ internal override System.Drawing.Brush RealizeGdiBrush() GdiLinearGradientBrush brush; try { - Lock.EnterGdiPlus(); + Locks.EnterGdiPlus(); if (_useRect) { brush = new GdiLinearGradientBrush(_rect.ToRectangleF(), @@ -214,7 +214,7 @@ internal override System.Drawing.Brush RealizeGdiBrush() brush.Transform = _matrix.ToGdiMatrix(); //brush.WrapMode = WrapMode.Clamp; } - finally { Lock.ExitGdiPlus(); } + finally { Locks.ExitGdiPlus(); } return brush; #else return null!; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XRect.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XRect.cs index 07379df5..10f1641a 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XRect.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XRect.cs @@ -136,27 +136,20 @@ public XRect(SysRect rect) // ReSharper disable once IdentifierTypo public static XRect FromLTRB(double left, double top, double right, double bottom) // ReSharper restore InconsistentNaming - { - return new XRect(left, top, right - left, bottom - top); - } + => new(left, top, right - left, bottom - top); /// /// Determines whether the two rectangles are equal. /// - public static bool operator ==(XRect rect1, XRect rect2) - { // ReSharper disable CompareOfFloatsByEqualityOperator - return rect1.X == rect2.X && rect1.Y == rect2.Y && rect1.Width == rect2.Width && rect1.Height == rect2.Height; - // ReSharper restore CompareOfFloatsByEqualityOperator - } + public static bool operator ==(XRect rect1, XRect rect2) => + rect1.X == rect2.X && rect1.Y == rect2.Y && rect1.Width == rect2.Width && rect1.Height == rect2.Height; + // ReSharper restore CompareOfFloatsByEqualityOperator /// /// Determines whether the two rectangles are not equal. /// - public static bool operator !=(XRect rect1, XRect rect2) - { - return !(rect1 == rect2); - } + public static bool operator !=(XRect rect1, XRect rect2) => !(rect1 == rect2); /// /// Determines whether the two rectangles are equal. @@ -181,10 +174,7 @@ public override bool Equals(object? o) /// /// Determines whether this instance and the specified rect are equal. /// - public bool Equals(XRect value) - { - return Equals(this, value); - } + public bool Equals(XRect value) => Equals(this, value); /// /// Returns the hash code for this instance. @@ -214,28 +204,19 @@ public static XRect Parse(string source) } /// - /// Converts this XRect to a human readable string. + /// Converts this XRect to a human-readable string. /// - public override string ToString() - { - return ConvertToString(null, null); - } + public override string ToString() => ConvertToString(null, null); /// - /// Converts this XRect to a human readable string. + /// Converts this XRect to a human-readable string. /// - public string ToString(IFormatProvider provider) - { - return ConvertToString(null, provider); - } + public string ToString(IFormatProvider provider) => ConvertToString(null, provider); /// - /// Converts this XRect to a human readable string. + /// Converts this XRect to a human-readable string. /// - string IFormattable.ToString(string? format, IFormatProvider? provider) - { - return ConvertToString(format, provider); - } + string IFormattable.ToString(string? format, IFormatProvider? provider) => ConvertToString(format, provider); internal string ConvertToString(string? format, IFormatProvider? provider) { @@ -277,7 +258,6 @@ public XPoint Location /// /// Gets or sets the size of the rectangle. /// - //[Browsable(false)] public XSize Size { get @@ -313,7 +293,6 @@ public double X _x = value; } } - double _x; /// @@ -329,7 +308,6 @@ public double Y _y = value; } } - double _y; /// @@ -348,7 +326,6 @@ public double Width _width = value; } } - double _width; /// @@ -366,7 +343,6 @@ public double Height _height = value; } } - double _height; /// @@ -434,10 +410,7 @@ public double Bottom /// /// Indicates whether the rectangle contains the specified point. /// - public bool Contains(XPoint point) - { - return Contains(point.X, point.Y); - } + public bool Contains(XPoint point) => Contains(point.X, point.Y); /// /// Indicates whether the rectangle contains the specified point. @@ -541,10 +514,7 @@ public static XRect Union(XRect rect1, XRect rect2) /// /// Sets current rectangle to the union of the current rectangle and the specified point. /// - public void Union(XPoint point) - { - Union(new XRect(point, point)); - } + public void Union(XPoint point) => Union(new XRect(point, point)); /// /// Returns the union of a rectangle and a point. @@ -598,28 +568,19 @@ public static XRect Offset(XRect rect, double offsetX, double offsetY) /// /// Translates the rectangle by adding the specified point. /// - //[Obsolete("Use Offset.")] public static XRect operator +(XRect rect, XPoint point) - { - return new XRect(rect._x + point.X, rect.Y + point.Y, rect._width, rect._height); - } + => new(rect._x + point.X, rect.Y + point.Y, rect._width, rect._height); /// /// Translates the rectangle by subtracting the specified point. /// - //[Obsolete("Use Offset.")] public static XRect operator -(XRect rect, XPoint point) - { - return new XRect(rect._x - point.X, rect.Y - point.Y, rect._width, rect._height); - } + => new(rect._x - point.X, rect.Y - point.Y, rect._width, rect._height); /// /// Expands the rectangle by using the specified Size, in all directions. /// - public void Inflate(XSize size) - { - Inflate(size.Width, size.Height); - } + public void Inflate(XSize size) => Inflate(size.Width, size.Height); /// /// Expands or shrinks the rectangle by using the specified width and height amounts, in all directions. @@ -669,9 +630,7 @@ public static XRect Transform(XRect rect, XMatrix matrix) /// Transforms the rectangle by applying the specified matrix. /// public void Transform(XMatrix matrix) - { - XMatrix.MatrixHelper.TransformRect(ref this, ref matrix); - } + => XMatrix.MatrixHelper.TransformRect(ref this, ref matrix); /// /// Multiplies the size of the current rectangle by the specified x and y values. @@ -701,57 +660,42 @@ public void Scale(double scaleX, double scaleY) /// /// Converts this instance to a System.Drawing.RectangleF. /// - public RectangleF ToRectangleF() - { - return new RectangleF((float)_x, (float)_y, (float)_width, (float)_height); - } + public RectangleF ToRectangleF() + => new((float)_x, (float)_y, (float)_width, (float)_height); #endif #if GDI /// /// Performs an implicit conversion from a System.Drawing.Rectangle to an XRect. /// - public static implicit operator XRect(Rectangle rect) - { - return new XRect(rect.X, rect.Y, rect.Width, rect.Height); - } + public static implicit operator XRect(Rectangle rect) + => new(rect.X, rect.Y, rect.Width, rect.Height); /// /// Performs an implicit conversion from a System.Drawing.RectangleF to an XRect. /// - public static implicit operator XRect(RectangleF rect) - { - return new XRect(rect.X, rect.Y, rect.Width, rect.Height); - } + public static implicit operator XRect(RectangleF rect) + => new(rect.X, rect.Y, rect.Width, rect.Height); #endif #if WPF || WUI /// /// Performs an implicit conversion from System.Windows.Rect to XRect. /// - public static implicit operator XRect(SysRect rect) - { - return new XRect(rect.X, rect.Y, rect.Width, rect.Height); - } + public static implicit operator XRect(SysRect rect) + => new(rect.X, rect.Y, rect.Width, rect.Height); #endif bool ContainsInternal(double x, double y) - { - return x >= _x && x - _width <= _x && y >= _y && y - _height <= _y; - } + => x >= _x && x - _width <= _x && y >= _y && y - _height <= _y; - static XRect CreateEmptyRect() + static readonly XRect s_empty = new() { - return new() - { - _x = double.PositiveInfinity, - _y = double.PositiveInfinity, - _width = double.NegativeInfinity, - _height = double.NegativeInfinity - }; - } - - static readonly XRect s_empty = CreateEmptyRect(); + _x = Double.PositiveInfinity, + _y = Double.PositiveInfinity, + _width = Double.NegativeInfinity, + _height = Double.NegativeInfinity + }; /// /// Gets the DebuggerDisplayAttribute text. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XSize.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XSize.cs index 17fb61cc..86d851eb 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XSize.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XSize.cs @@ -50,10 +50,7 @@ public XSize(double width, double height) /// /// Determines whether two size objects are not equal. /// - public static bool operator !=(XSize size1, XSize size2) - { - return !(size1 == size2); - } + public static bool operator !=(XSize size1, XSize size2) => !(size1 == size2); /// /// Indicates whether these two instances are equal. @@ -78,10 +75,7 @@ public override bool Equals(object? o) /// /// Indicates whether this instance and a specified size are equal. /// - public bool Equals(XSize value) - { - return Equals(this, value); - } + public bool Equals(XSize value) => Equals(this, value); /// /// Returns the hash code for this instance. @@ -123,56 +117,38 @@ public PointF ToPointF() /// /// Converts this XSize to an XPoint. /// - public XPoint ToXPoint() - { - return new XPoint(_width, _height); - } + public XPoint ToXPoint() => new(_width, _height); /// /// Converts this XSize to an XVector. /// - public XVector ToXVector() - { - return new XVector(_width, _height); - } + public XVector ToXVector() => new(_width, _height); #if GDI /// /// Converts this XSize to a SizeF. /// - public SizeF ToSizeF() - { - return new SizeF((float)_width, (float)_height); - } + public SizeF ToSizeF() => new((float)_width, (float)_height); #endif #if WPF || WUI /// /// Converts this XSize to a System.Windows.Size. /// - public SysSize ToSize() - { - return new SysSize(_width, _height); - } + public SysSize ToSize() => new(_width, _height); #endif #if GDI /// /// Creates an XSize from a System.Drawing.Size. /// - public static XSize FromSize(Size size) - { - return new XSize(size.Width, size.Height); - } + public static XSize FromSize(Size size) => new(size.Width, size.Height); /// /// Implicit conversion from XSize to System.Drawing.Size. The conversion must be implicit because the /// WinForms designer uses it. /// - public static implicit operator XSize(Size size) - { - return new XSize(size.Width, size.Height); - } + public static implicit operator XSize(Size size) => new(size.Width, size.Height); #endif #if WPF || WUI @@ -189,35 +165,24 @@ public static XSize FromSize(SysSize size) /// /// Creates an XSize from a System.Drawing.Size. /// - public static XSize FromSizeF(SizeF size) - { - return new XSize(size.Width, size.Height); - } + public static XSize FromSizeF(SizeF size) => new(size.Width, size.Height); #endif /// - /// Converts this XSize to a human readable string. + /// Converts this XSize to a human-readable string. /// - public override string ToString() - { - return ConvertToString(null, null); - } + public override string ToString() => ConvertToString(null, null); /// - /// Converts this XSize to a human readable string. + /// Converts this XSize to a human-readable string. /// - public string ToString(IFormatProvider provider) - { - return ConvertToString(null, provider); - } + public string ToString(IFormatProvider provider) => ConvertToString(null, provider); /// - /// Converts this XSize to a human readable string. + /// Converts this XSize to a human-readable string. /// - string IFormattable.ToString(string? format, IFormatProvider? provider) - { - return ConvertToString(format, provider); - } + string IFormattable.ToString(string? format, IFormatProvider? provider) + => ConvertToString(format, provider); internal string ConvertToString(string? format, IFormatProvider? provider) { @@ -285,27 +250,18 @@ public double Height /// /// Performs an explicit conversion from XSize to XVector. /// - public static explicit operator XVector(XSize size) - { - return new XVector(size._width, size._height); - } + public static explicit operator XVector(XSize size) => new(size._width, size._height); /// /// Performs an explicit conversion from XSize to XPoint. /// - public static explicit operator XPoint(XSize size) - { - return new XPoint(size._width, size._height); - } + public static explicit operator XPoint(XSize size) => new(size._width, size._height); #if WPF || WUI /// /// Performs an explicit conversion from Size to XSize. /// - public static explicit operator XSize(SysSize size) - { - return new XSize(size.Width, size.Height); - } + public static explicit operator XSize(SysSize size) => new(size.Width, size.Height); #endif /// diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XStringFormat.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XStringFormat.cs index 0addd457..4e1292aa 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XStringFormat.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XStringFormat.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. using System; @@ -161,7 +161,7 @@ internal StringFormat RealizeGdiStringFormat() //_stringFormat.FormatFlags = (StringFormatFlags)_formatFlags; // Bugfix: Set MeasureTrailingSpaces to get the correct width with Graphics.MeasureString(). - // Before, MeasureString() didnt include blanks in width calculation, which could result in text overflowing table or page border before wrapping. $MaOs + // Before, MeasureString() didn’t include blanks in width calculation, which could result in text overflowing table or page border before wrapping. $MaOs _stringFormat.FormatFlags = _stringFormat.FormatFlags | StringFormatFlags.MeasureTrailingSpaces; } return _stringFormat; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XUnit.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XUnit.cs index 46c57ff0..ea9a35df 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XUnit.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XUnit.cs @@ -273,16 +273,12 @@ string GetSuffix() /// public static implicit operator XUnit(string value) { - XUnit unit = default; value = value.Trim(); - // #DELETE 2024-12-31 - Replace this special treatment for German numbers with an exception. + // No commas allowed anymore. ',' as decimal separator was a special hack for German numbers. if (value.Contains(',')) - { - PdfSharpLogHost.Logger.LogError("A number string contains an illegal ','. It is replaced by '.'. Will throw exception in the future."); - value = value.Replace(',', '.'); - } + throw new FormatException($"value '{value}' must not contain a comma as decimal or thousands separator."); int count = value.Length; int valLen = 0; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XVector.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XVector.cs index ae81cfee..c3f94ebb 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XVector.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing/XVector.cs @@ -49,12 +49,10 @@ public XVector(double x, double y) /// /// The first vector to compare. /// The second vector to compare. - public static bool operator !=(XVector vector1, XVector vector2) - { - // ReSharper disable CompareOfFloatsByEqualityOperator - return vector1._x != vector2._x || vector1._y != vector2._y; - // ReSharper restore CompareOfFloatsByEqualityOperator - } + // ReSharper disable CompareOfFloatsByEqualityOperator + public static bool operator !=(XVector vector1, XVector vector2) => + vector1._x != vector2._x || vector1._y != vector2._y; + // ReSharper restore CompareOfFloatsByEqualityOperator /// /// Compares two vectors for equality. @@ -84,20 +82,15 @@ public override bool Equals(object? o) /// Compares two vectors for equality. /// /// The vector to compare with this vector. - public bool Equals(XVector value) - { - return Equals(this, value); - } + public bool Equals(XVector value) => Equals(this, value); /// /// Returns the hash code for this instance. /// - public override int GetHashCode() - { // ReSharper disable NonReadonlyFieldInGetHashCode - return _x.GetHashCode() ^ _y.GetHashCode(); - // ReSharper restore NonReadonlyFieldInGetHashCode - } + public override int GetHashCode() => + _x.GetHashCode() ^ _y.GetHashCode(); + // ReSharper restore NonReadonlyFieldInGetHashCode /// /// Converts a string representation of a vector into the equivalent Vector structure. @@ -135,19 +128,16 @@ public double Y /// /// Returns the string representation of this Vector structure. /// - public override string ToString() - { - return ConvertToString(null, null); - } + public override string ToString() => ConvertToString(null, null); /// /// Returns the string representation of this Vector structure with the specified formatting information. /// /// The culture-specific formatting information. - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider provider) => ConvertToString(null, provider); - string IFormattable.ToString(string? format, IFormatProvider? provider) + string IFormattable.ToString(string? format, IFormatProvider? provider) => ConvertToString(format, provider); internal string ConvertToString(string? format, IFormatProvider? provider) @@ -163,22 +153,20 @@ internal string ConvertToString(string? format, IFormatProvider? provider) /// /// Gets the length of this vector. /// - public double Length - => Math.Sqrt(_x * _x + _y * _y); + public double Length => Math.Sqrt(_x * _x + _y * _y); /// /// Gets the square of the length of this vector. /// - public double LengthSquared - => _x * _x + _y * _y; + public double LengthSquared => _x * _x + _y * _y; /// /// Normalizes this vector. /// public void Normalize() { - this = this / Math.Max(Math.Abs(_x), Math.Abs(_y)); - this = this / Length; + this /= Math.Max(Math.Abs(_x), Math.Abs(_y)); + this /= Length; } /// @@ -238,7 +226,7 @@ public static XVector Add(XVector vector1, XVector vector2) /// /// The vector from which vector2 is subtracted. /// The vector to subtract from vector1. - public static XVector operator -(XVector vector1, XVector vector2) + public static XVector operator -(XVector vector1, XVector vector2) => new(vector1._x - vector2._x, vector1._y - vector2._y); /// @@ -254,7 +242,7 @@ public static XVector Subtract(XVector vector1, XVector vector2) /// /// The vector used to translate point. /// The point to translate. - public static XPoint operator +(XVector vector, XPoint point) + public static XPoint operator +(XVector vector, XPoint point) => new(point.X + vector._x, point.Y + vector._y); /// @@ -262,7 +250,7 @@ public static XVector Subtract(XVector vector1, XVector vector2) /// /// The vector used to translate point. /// The point to translate. - public static XPoint Add(XVector vector, XPoint point) + public static XPoint Add(XVector vector, XPoint point) => new(point.X + vector._x, point.Y + vector._y); /// @@ -270,7 +258,7 @@ public static XPoint Add(XVector vector, XPoint point) /// /// The vector to multiply. /// The scalar to multiply. - public static XVector operator *(XVector vector, double scalar) + public static XVector operator *(XVector vector, double scalar) => new(vector._x * scalar, vector._y * scalar); /// @@ -278,7 +266,7 @@ public static XPoint Add(XVector vector, XPoint point) /// /// The vector to multiply. /// The scalar to multiply. - public static XVector Multiply(XVector vector, double scalar) + public static XVector Multiply(XVector vector, double scalar) => new(vector._x * scalar, vector._y * scalar); /// @@ -286,7 +274,7 @@ public static XVector Multiply(XVector vector, double scalar) /// /// The scalar to multiply. /// The vector to multiply. - public static XVector operator *(double scalar, XVector vector) + public static XVector operator *(double scalar, XVector vector) => new(vector._x * scalar, vector._y * scalar); /// @@ -294,7 +282,7 @@ public static XVector Multiply(XVector vector, double scalar) /// /// The scalar to multiply. /// The vector to multiply. - public static XVector Multiply(double scalar, XVector vector) + public static XVector Multiply(double scalar, XVector vector) => new(vector._x * scalar, vector._y * scalar); /// @@ -302,7 +290,7 @@ public static XVector Multiply(double scalar, XVector vector) /// /// The vector to divide. /// The scalar by which vector will be divided. - public static XVector operator /(XVector vector, double scalar) + public static XVector operator /(XVector vector, double scalar) => vector * (1.0 / scalar); /// @@ -310,7 +298,7 @@ public static XVector Multiply(double scalar, XVector vector) /// /// The vector structure to divide. /// The amount by which vector is divided. - public static XVector Divide(XVector vector, double scalar) + public static XVector Divide(XVector vector, double scalar) => vector * (1.0 / scalar); /// @@ -318,7 +306,7 @@ public static XVector Divide(XVector vector, double scalar) /// /// The vector to transform. /// The transformation to apply to vector. - public static XVector operator *(XVector vector, XMatrix matrix) + public static XVector operator *(XVector vector, XMatrix matrix) => matrix.Transform(vector); /// @@ -326,7 +314,7 @@ public static XVector Divide(XVector vector, double scalar) /// /// The vector to transform. /// The transformation to apply to vector. - public static XVector Multiply(XVector vector, XMatrix matrix) + public static XVector Multiply(XVector vector, XMatrix matrix) => matrix.Transform(vector); /// @@ -334,7 +322,7 @@ public static XVector Multiply(XVector vector, XMatrix matrix) /// /// The first vector to multiply. /// The second vector to multiply. - public static double operator *(XVector vector1, XVector vector2) + public static double operator *(XVector vector1, XVector vector2) => vector1._x * vector2._x + vector1._y * vector2._y; /// @@ -342,7 +330,7 @@ public static XVector Multiply(XVector vector, XMatrix matrix) /// /// The first vector to multiply. /// The second vector structure to multiply. - public static double Multiply(XVector vector1, XVector vector2) + public static double Multiply(XVector vector1, XVector vector2) => vector1._x * vector2._x + vector1._y * vector2._y; /// @@ -350,21 +338,21 @@ public static double Multiply(XVector vector1, XVector vector2) /// /// The first vector to evaluate. /// The second vector to evaluate. - public static double Determinant(XVector vector1, XVector vector2) + public static double Determinant(XVector vector1, XVector vector2) => vector1._x * vector2._y - vector1._y * vector2._x; /// /// Creates a Size from the offsets of this vector. /// /// The vector to convert. - public static explicit operator XSize(XVector vector) + public static explicit operator XSize(XVector vector) => new(Math.Abs(vector._x), Math.Abs(vector._y)); /// /// Creates a Point with the X and Y values of this vector. /// /// The vector to convert. - public static explicit operator XPoint(XVector vector) + public static explicit operator XPoint(XVector vector) => new(vector._x, vector._y); /// diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.Internal/FontHelper.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.Internal/FontHelper.cs index 767cd125..1114e3ba 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.Internal/FontHelper.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.Internal/FontHelper.cs @@ -39,7 +39,7 @@ namespace PdfSharp.Fonts.Internal /// static class FontHelper { -#if true_ // #DELETE 24-12-31 +#if true_ // #DELETE 25-12-31 /// /// Measure string directly from font data. /// @@ -65,7 +65,7 @@ public static XSize MeasureString(string text, XFont font) //codePoints = codeRun.Items; return MeasureString(codePoints, font); -#if true_ // Keep until 2024-12-31 for reference +#if true_ // Keep until 2025-12-31 for reference var size = new XSize(); var descriptor = FontDescriptorCache.GetOrCreateDescriptorFor(font) as OpenTypeDescriptor; if (descriptor != null) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/GlyphDataTable.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/GlyphDataTable.cs index a161de9d..48d99ecc 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/GlyphDataTable.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/GlyphDataTable.cs @@ -100,11 +100,11 @@ public void CompleteGlyphClosure(Dictionary glyphs) // see https://forum.pdfsharp.net/viewtopic.php?f=2&t=2248#p10378 try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); for (int idx = 0; idx < count; idx++) AddCompositeGlyphs(glyphs, glyphArray[idx]); } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } /// diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/GlyphTypefaceCache.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/GlyphTypefaceCache.cs index 06265755..13e04a2c 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/GlyphTypefaceCache.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/GlyphTypefaceCache.cs @@ -17,22 +17,22 @@ public static bool TryGetGlyphTypeface(string key, [MaybeNullWhen(false)] out XG { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); bool result = Globals.Global.Fonts.GlyphTypefacesByKey.TryGetValue(key, out glyphTypeface); return result; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } public static void AddGlyphTypeface(XGlyphTypeface glyphTypeface) { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); Debug.Assert(!Globals.Global.Fonts.GlyphTypefacesByKey.ContainsKey(glyphTypeface.Key)); Globals.Global.Fonts.GlyphTypefacesByKey.Add(glyphTypeface.Key, glyphTypeface); } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } internal static void Reset() diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/OpenTypeFontTables.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/OpenTypeFontTables.cs index 0b2db0cc..7cbc780f 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/OpenTypeFontTables.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/OpenTypeFontTables.cs @@ -2,7 +2,6 @@ // See the LICENSE file in the solution root for more information. using System.Text; -using PdfSharp.Internal; using PdfSharp.Drawing; using Fixed = System.Int32; @@ -604,7 +603,7 @@ public void Read() } } - // UNDONE + // Not used in PDFsharp. class VerticalHeaderTable : OpenTypeFontTable { public const string Tag = TableTagNames.VHea; @@ -697,9 +696,9 @@ public void Read() /// information (the advance heights and top sidebearings) for the vertical layout of each /// of the glyphs in the font. /// + // Not used in PDFsharp. class VerticalMetricsTable : OpenTypeFontTable { - // UNDONE public const string Tag = TableTagNames.VMtx; // Code comes from HorizontalMetricsTable. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/OpenTypeFontfaceCache.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/OpenTypeFontfaceCache.cs index 91c809e6..99ad3332 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/OpenTypeFontfaceCache.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/OpenTypeFontfaceCache.cs @@ -23,11 +23,11 @@ public static bool TryGetFontFace(string key, { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); var result = Globals.Global.Fonts.FontFaceCache.TryGetValue(key, out fontFace); return result; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } /// @@ -39,18 +39,18 @@ public static bool TryGetFontFace(ulong checkSum, { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); var result = Globals.Global.Fonts.FontFacesByCheckSum.TryGetValue(checkSum, out fontFace); return result; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } public static OpenTypeFontFace AddFontFace(OpenTypeFontFace fontFace) { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (TryGetFontFace(fontFace.FullFaceName, out var fontFaceCheck)) { if (fontFaceCheck.CheckSum != fontFace.CheckSum) @@ -61,7 +61,7 @@ public static OpenTypeFontFace AddFontFace(OpenTypeFontFace fontFace) Globals.Global.Fonts.FontFacesByCheckSum.Add(fontFace.CheckSum, fontFace); return fontFace; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } internal static void Reset() diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCache.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCache.cs index 9cbe0263..19007492 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCache.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCache.cs @@ -28,7 +28,7 @@ public static FontDescriptor GetOrCreateDescriptorFor(XFont font) try { var cache = Globals.Global.Fonts.FontDescriptorCache; - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (cache.TryGetValue(fontDescriptorKey, out var descriptor)) return descriptor; @@ -36,7 +36,7 @@ public static FontDescriptor GetOrCreateDescriptorFor(XFont font) cache.Add(fontDescriptorKey, descriptor); return descriptor; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } public static FontDescriptor GetOrCreateDescriptorFor(XGlyphTypeface glyphTypeface) @@ -47,7 +47,7 @@ public static FontDescriptor GetOrCreateDescriptorFor(XGlyphTypeface glyphTypefa try { var cache = Globals.Global.Fonts.FontDescriptorCache; - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (cache.TryGetValue(fontDescriptorKey, out var descriptor)) return descriptor; @@ -55,7 +55,7 @@ public static FontDescriptor GetOrCreateDescriptorFor(XGlyphTypeface glyphTypefa cache.Add(fontDescriptorKey, descriptor); return descriptor; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } /// @@ -72,7 +72,7 @@ public static FontDescriptor GetOrCreateDescriptor(string fontFamilyName, XFontS try { var cache = Globals.Global.Fonts.FontDescriptorCache; - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (!cache.TryGetValue(fontDescriptorKey, out var descriptor)) { var font = new XFont(fontFamilyName, 10, style); @@ -85,7 +85,7 @@ public static FontDescriptor GetOrCreateDescriptor(string fontFamilyName, XFontS } return descriptor; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } internal static void Reset() diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFactory.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFactory.cs index f03d31bc..78257168 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFactory.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFactory.cs @@ -52,7 +52,7 @@ static class FontFactory var fontResolverInfosByName = Globals.Global.Fonts.FontResolverInfosByName; var fontSourcesByName = Globals.Global.Fonts.FontSourcesByName; - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); // Was this typeface requested before? if (fontResolverInfosByName.TryGetValue(typefaceKey, out var fontResolverInfo)) return fontResolverInfo; @@ -111,7 +111,7 @@ static class FontFactory finally { _fallbackFontResolverInvoked = false; - Lock.ExitFontFactory(); + Locks.ExitFontFactory(); } } static bool _fallbackFontResolverInvoked; @@ -141,7 +141,7 @@ internal static void RegisterResolverResult(IFontResolver fontResolver, string f var fontResolverInfosByName = Globals.Global.Fonts.FontResolverInfosByName; var fontSourcesByName = Globals.Global.Fonts.FontSourcesByName; - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); // OverrideStyleSimulations is true only for internal quality tests. // With this code we can simulate bold and/or italic for a font face even if @@ -217,7 +217,7 @@ internal static void RegisterResolverResult(IFontResolver fontResolver, string f } } } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } #if GDI /// @@ -231,7 +231,7 @@ public static XFontSource RegisterFontFace_unused(byte[] fontBytes) var fontSourcesByName = Globals.Global.Fonts.FontSourcesByName; var fontSourcesByKey = Globals.Global.Fonts.FontSourcesByKey; - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); ulong key = FontHelper.CalcChecksum(fontBytes); if (fontSourcesByKey.TryGetValue(key, out var fontSource)) { @@ -250,7 +250,7 @@ public static XFontSource RegisterFontFace_unused(byte[] fontBytes) GlyphTypefaceCache.AddGlyphTypeface(glyphTypeface); return fontSource; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } #endif @@ -329,7 +329,7 @@ public static XFontSource CacheFontSource(XFontSource fontSource) { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); // Check whether an identical font source with a different face name already exists. if (Globals.Global.Fonts.FontSourcesByKey.TryGetValue(fontSource.Key, out var existingFontSource)) { @@ -366,7 +366,7 @@ public static XFontSource CacheFontSource(XFontSource fontSource) Globals.Global.Fonts.FontSourcesByName.Add(fontSource.FontName, fontSource); return fontSource; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } /// @@ -420,15 +420,15 @@ public static void CacheExistingFontSourceWithNewTypefaceKey(string typefaceKey, { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); Globals.Global.Fonts.FontSourcesByName.Add(typefaceKey, fontSource); } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } public static void CheckInvocationOfPlatformFontResolver() { - if (!Lock.IsFontFactoryLookTaken()) + if (!Locks.IsFontFactoryLookTaken()) throw new InvalidOperationException("You must not call PlatformFontResolver.ResolveTypeface if you are not calling from within a font resolver."); if (_fallbackFontResolverInvoked) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFamilyCache.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFamilyCache.cs index cf907943..de77d6a5 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFamilyCache.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFamilyCache.cs @@ -24,11 +24,11 @@ static class FontFamilyCache { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); Globals.Global.Fonts.FontFamiliesByName.TryGetValue(familyName, out var family); return family; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } /// @@ -38,7 +38,7 @@ public static FontFamilyInternal CacheOrGetFontFamily(FontFamilyInternal fontFam { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); // Recall that a font family is uniquely identified by its case-insensitive name. if (Globals.Global.Fonts.FontFamiliesByName.TryGetValue(fontFamily.Name, out var existingFontFamily)) { @@ -51,7 +51,7 @@ public static FontFamilyInternal CacheOrGetFontFamily(FontFamilyInternal fontFam Globals.Global.Fonts.FontFamiliesByName.Add(fontFamily.Name, fontFamily); return fontFamily; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } internal static void Reset() diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFamilyInternal.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFamilyInternal.cs index 7f0fb8f1..821a202c 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFamilyInternal.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontFamilyInternal.cs @@ -93,7 +93,7 @@ internal static FontFamilyInternal GetOrCreateFromName(string familyName, bool c { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); var family = FontFamilyCache.GetFamilyByName(familyName); if (family == null) { @@ -102,7 +102,7 @@ internal static FontFamilyInternal GetOrCreateFromName(string familyName, bool c } return family; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } #if GDI @@ -110,12 +110,12 @@ internal static FontFamilyInternal GetOrCreateFromGdi(GdiFontFamily gdiFontFamil { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); FontFamilyInternal fontFamily = new FontFamilyInternal(gdiFontFamily); fontFamily = FontFamilyCache.CacheOrGetFontFamily(fontFamily); return fontFamily; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } #endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/GlobalFontSettings.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/GlobalFontSettings.cs index 987e7bd5..36a2f5a8 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/GlobalFontSettings.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/GlobalFontSettings.cs @@ -39,10 +39,10 @@ public static IFontResolver? FontResolver ref var fontResolver = ref Globals.Global.Fonts.FontResolver; try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); SetFontResolver(value, ref fontResolver); } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } } @@ -64,10 +64,10 @@ public static IFontResolver? FallbackFontResolver ref var fontResolver = ref Globals.Global.Fonts.FallbackFontResolver; try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); SetFontResolver(value, ref fontResolver); } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } } @@ -170,7 +170,7 @@ public static PdfFontEncoding DefaultFontEncoding { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (Globals.Global.Fonts.FontEncodingInitialized) { // Ignore multiple setting e.g. in a web application. @@ -182,7 +182,7 @@ public static PdfFontEncoding DefaultFontEncoding Globals.Global.Fonts.FontEncoding = value; Globals.Global.Fonts.FontEncodingInitialized = true; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } } @@ -206,7 +206,7 @@ public static bool UseWindowsFontsUnderWindows { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (Globals.Global.Fonts.UseWindowsFontsUnderWindows.HasValue) { // Ignore multiple setting e.g. in a web application. @@ -217,7 +217,7 @@ public static bool UseWindowsFontsUnderWindows Globals.Global.Fonts.UseWindowsFontsUnderWindows = value; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } } @@ -240,7 +240,7 @@ public static bool UseWindowsFontsUnderWsl2 { try { - Lock.EnterFontFactory(); + Locks.EnterFontFactory(); if (Globals.Global.Fonts.UseWindowsFontsUnderWsl2.HasValue) { // Ignore multiple setting e.g. in a web application. @@ -251,7 +251,7 @@ public static bool UseWindowsFontsUnderWsl2 Globals.Global.Fonts.UseWindowsFontsUnderWsl2 = value; } - finally { Lock.ExitFontFactory(); } + finally { Locks.ExitFontFactory(); } } } #elif GDI || WPF diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Diagnostics.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Diagnostics.cs index cd9400df..61b62773 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Diagnostics.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Diagnostics.cs @@ -71,14 +71,16 @@ public static void HandleUnexpectedCharacter(char ch, string dump) // Hex formatting does not work with type Char. It must be cast to integer. string message = Invariant($"Unexpected character '0x{(uint)ch:x4}' in PDF stream. The file may be corrupted. ") + - "If you think this is a bug in PDFsharp, please send us your PDF file (issues (at) pdfsharp.net).\n" + dump; + Invariant($"If you think this is a bug in PDFsharp, please visit {UrlLiterals.LinkToCannotOpenPdfFile} for further information.\n") + + dump; ThrowParserException(message); } public static void HandleUnexpectedToken(string token, string dump) { string message = Invariant($"Unexpected token '{token}' in PDF stream. The file may be corrupted. ") + - "If you think this is a bug in PDFsharp, please send us your PDF file (issues (at) pdfsharp.net).\n" + dump; + Invariant($"If you think this is a bug in PDFsharp, please visit {UrlLiterals.LinkToCannotOpenPdfFile} for further information.\n") + + dump; ThrowParserException(message); } @@ -111,7 +113,7 @@ public static void HandleUnexpectedCharacter(char ch) { string message = String.Format(CultureInfo.InvariantCulture, "Unexpected character '0x{0:x4}' in content stream. The stream may be corrupted or the feature is not implemented. " + - "If you think this is a bug in PDFsharp, please send us your PDF file (issues (at) pdfsharp.net).", (int)ch); + $"If you think this is a bug in PDFsharp, please visit {UrlLiterals.LinkToCannotOpenPdfFile} for further information.\n", (int)ch); ThrowContentReaderException(message); } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/DotNetHelper.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/DotNetHelper.cs index e8d9f177..1763d63a 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/DotNetHelper.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/DotNetHelper.cs @@ -25,7 +25,7 @@ public static BigInteger CreateBigInteger(ReadOnlySpan value, bool isUnsig // Convert to little endian, which is expected by BigInteger constructor. if (isBigEndian) - bytes = bytes.Reverse().ToArray(); + bytes = ((IEnumerable)bytes).Reverse().ToArray(); // A leading bit of 1 defines a negative number. If the input should be interpreted as unsigned, prepend a new zero byte, if there’s a leading 1. // As bytes is in little endian order, check the most significant bit of the last byte. If it is 1, append the zero byte. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/ErrorHelpers.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/ErrorHelpers.cs index 12e0a06e..471812bd 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/ErrorHelpers.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/ErrorHelpers.cs @@ -12,12 +12,15 @@ namespace PdfSharp.Internal // ReSharper disable once InconsistentNaming static class TH { - private const string SendUsTheFile = "\nPDFsharp cannot read this PDF file. " + + const string SendUsTheFile = "\nPDFsharp cannot read this PDF file. " + "If you think your file is a valid PDF file please send it to us so that we can fix this bug in the PDF parser."; public static InvalidOperationException InvalidOperationException_CouldNotFindMetadataDictionary() => new("Could not find document’s metadata dictionary." + SendUsTheFile); + public static InvalidOperationException InvalidOperationException_ReferenceMustNotBeNull() => + new("The reference must not be null."); + #region Reader Messages public static ObjectNotAvailableException ObjectNotAvailableException_CannotRetrieveStreamLength(Exception? innerException = null) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Lock.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Locks.cs similarity index 98% rename from src/foundation/src/PDFsharp/src/PdfSharp/Internal/Lock.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Locks.cs index 8964d121..56f94938 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Lock.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Locks.cs @@ -10,7 +10,7 @@ namespace PdfSharp.Internal /// Static locking functions to make PDFsharp thread save. /// POSSIBLE BUG_OLD: Having more than one lock can lead to a deadlock. /// - static class Lock + static class Locks { public static void EnterGdiPlus() { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Adam7.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Adam7.cs similarity index 95% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Adam7.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Adam7.cs index f0320fb2..48af2e6f 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Adam7.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Adam7.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System.Collections.Generic; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Adler32Checksum.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Adler32Checksum.cs similarity index 84% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Adler32Checksum.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Adler32Checksum.cs index 6e7b9a19..f137043e 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Adler32Checksum.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Adler32Checksum.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System.Collections.Generic; @@ -13,7 +15,7 @@ namespace PdfSharp.BigGustave public static class Adler32Checksum { // Both sums (s1 and s2) are done modulo 65521. - private const int AdlerModulus = 65521; + const int AdlerModulus = 65521; /// /// Calculate the Adler-32 checksum for some data. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/ChunkHeader.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/ChunkHeader.cs similarity index 91% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/ChunkHeader.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/ChunkHeader.cs index 61e864d2..8e1ef7f0 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/ChunkHeader.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/ChunkHeader.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/ColorType.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/ColorType.cs similarity index 79% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/ColorType.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/ColorType.cs index f8a50d0d..f127ab93 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/ColorType.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/ColorType.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/CompressionMethod.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/CompressionMethod.cs similarity index 69% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/CompressionMethod.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/CompressionMethod.cs index 81dff90e..fe0701a5 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/CompressionMethod.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/CompressionMethod.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { /// /// The method used to compress the image data. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Crc32.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Crc32.cs similarity index 91% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Crc32.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Crc32.cs index 9b424654..fc69b5e8 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Crc32.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Crc32.cs @@ -1,15 +1,17 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { /// /// 32-bit Cyclic Redundancy Code used by the PNG for checking the data is intact. /// public static class Crc32 { - private const uint Polynomial = 0xEDB88320; + const uint Polynomial = 0xEDB88320; static readonly uint[] Lookup; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Decoder.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Decoder.cs similarity index 97% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Decoder.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Decoder.cs index 768a54b0..cf8cf98d 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Decoder.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Decoder.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/FilterMethod.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/FilterMethod.cs similarity index 69% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/FilterMethod.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/FilterMethod.cs index 6c7e78d2..1a6a25f7 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/FilterMethod.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/FilterMethod.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { /// /// Indicates the pre-processing method applied to the image data before compression. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/FilterType.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/FilterType.cs similarity index 79% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/FilterType.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/FilterType.cs index 326f49d0..608dce8b 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/FilterType.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/FilterType.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { internal enum FilterType { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/HeaderValidationResult.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/HeaderValidationResult.cs similarity index 88% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/HeaderValidationResult.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/HeaderValidationResult.cs index 3c4a2be4..fb8915b7 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/HeaderValidationResult.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/HeaderValidationResult.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { internal readonly struct HeaderValidationResult { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/IChunkVisitor.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/IChunkVisitor.cs similarity index 72% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/IChunkVisitor.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/IChunkVisitor.cs index 10c9257f..7c2cd606 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/IChunkVisitor.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/IChunkVisitor.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System.IO; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/ImageHeader.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/ImageHeader.cs similarity index 94% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/ImageHeader.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/ImageHeader.cs index 3a99313f..67e7c281 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/ImageHeader.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/ImageHeader.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System; using System.Collections.Generic; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/InterlaceMethod.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/InterlaceMethod.cs similarity index 70% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/InterlaceMethod.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/InterlaceMethod.cs index 01a63405..ab9dfc91 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/InterlaceMethod.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/InterlaceMethod.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { /// /// Indicates the transmission order of the image data. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/LICENSE b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/LICENSE similarity index 100% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/LICENSE rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/LICENSE diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Palette.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Palette.cs similarity index 89% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Palette.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Palette.cs index 3fb6e620..359c144e 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Palette.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Palette.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { /// /// The Palette class. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Pixel.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Pixel.cs similarity index 95% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Pixel.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Pixel.cs index ea9833de..a8e1b6af 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Pixel.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Pixel.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { /// /// A pixel in a image. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Png.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Png.cs similarity index 97% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Png.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Png.cs index 0eb19fde..90db658e 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/Png.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/Png.cs @@ -1,12 +1,11 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave -{ - using System; - using System.IO; +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. +namespace PdfSharp.Internal.Png.BigGustave +{ /// /// A PNG image. Call to open from file or bytes. /// diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngBuilder.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngBuilder.cs similarity index 99% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngBuilder.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngBuilder.cs index 752532a3..1d7f34cd 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngBuilder.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngBuilder.cs @@ -1,10 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -#nullable enable annotations +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +namespace PdfSharp.Internal.Png.BigGustave { using System; using System.Collections.Generic; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngOpener.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngOpener.cs similarity index 97% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngOpener.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngOpener.cs index eae2f528..6e0673b2 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngOpener.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngOpener.cs @@ -1,16 +1,14 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -#nullable enable annotations +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave -{ - using System; - using System.IO; - using System.IO.Compression; - using System.Text; +using System.IO.Compression; +using System.Text; +namespace PdfSharp.Internal.Png.BigGustave +{ internal static class PngOpener { public static Png Open(Stream stream, IChunkVisitor? chunkVisitor = null) => Open(stream, new PngOpenerSettings diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngOpenerSettings.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngOpenerSettings.cs similarity index 79% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngOpenerSettings.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngOpenerSettings.cs index 52bf0a91..c6d0187a 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngOpenerSettings.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngOpenerSettings.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { /// /// Settings to use when opening a PNG using diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngStreamWriteHelper.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngStreamWriteHelper.cs similarity index 90% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngStreamWriteHelper.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngStreamWriteHelper.cs index 88d4db5f..419dcb6e 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/PngStreamWriteHelper.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/PngStreamWriteHelper.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System; using System.Collections.Generic; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/RawPngData.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/RawPngData.cs similarity index 96% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/RawPngData.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/RawPngData.cs index b11d47ba..1f0940ad 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/RawPngData.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/RawPngData.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/StreamHelper.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/StreamHelper.cs similarity index 84% rename from src/foundation/src/PDFsharp/src/PdfSharp/PngLib/StreamHelper.cs rename to src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/StreamHelper.cs index bb8d18ab..d8a7f0e6 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PngLib/StreamHelper.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/Png/BigGustave/StreamHelper.cs @@ -1,8 +1,10 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -// ReSharper disable once CheckNamespace -namespace PdfSharp.BigGustave +// BigGustave is distributed with PDFsharp, but was published under a different license. +// See file LICENSE in the folder containing this file. + +namespace PdfSharp.Internal.Png.BigGustave { using System; using System.IO; @@ -17,8 +19,8 @@ public static int ReadBigEndianInt32(Stream stream) public static int ReadBigEndianInt32(byte[] bytes, int offset) { - return (bytes[0 + offset] << 24) + (bytes[1 + offset] << 16) - + (bytes[2 + offset] << 8) + bytes[3 + offset]; + return (bytes[0 + offset] << 24) + (bytes[1 + offset] << 16) + + (bytes[2 + offset] << 8) + bytes[3 + offset]; } public static void WriteBigEndianInt32(Stream stream, int value) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/PsMsgs.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/PsMsgs.cs index 759a6df0..266d0c37 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/PsMsgs.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/PsMsgs.cs @@ -127,7 +127,7 @@ public static string StreamMustBeWritable public static string MultiplePageInsert => "The page cannot be added to this document because the document already owned this page."; - public static string UnexpectedTokenInPdfFile => "Unexpected token in PDF file. The PDF file may be corrupt. If it is not, please send us the file for service (issues (at) pdfsharp.net)."; + public static string UnexpectedTokenInPdfFile => $"Unexpected token in PDF file. The PDF file may be corrupt. If you think this is a bug in PDFsharp, please visit {UrlLiterals.LinkToCannotOpenPdfFile} for further information."; public static string InappropriateColorSpace(PdfColorMode colorMode, XColorSpace colorSpace) { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/SuppressExceptions.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/SuppressExceptions.cs index 980c0090..7d0ada44 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Internal/SuppressExceptions.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Internal/SuppressExceptions.cs @@ -37,7 +37,6 @@ public static bool HasError(SuppressExceptions? suppressExceptions) } // Experimental - not yet in use. - #if true_ interface IErrorResult// TODO_OLD: Find final name diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Logging/LogMessages.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Logging/LogMessages.cs index d3572040..0e3d70e3 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Logging/LogMessages.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Logging/LogMessages.cs @@ -9,7 +9,7 @@ namespace PdfSharp.Logging { /// - /// Defines the logging event ids of PDFsharp. + /// Defines the logging event IDs of PDFsharp. /// public static class PdfSharpEventId // draft... { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfAcroField.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfAcroField.cs index 7f8223f6..f69b1cc8 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfAcroField.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfAcroField.cs @@ -117,8 +117,7 @@ public bool HasKids /// [Obsolete("Use GetDescendantNames")] public string[] DescendantNames // Properties should not return arrays. - => - GetDescendantNames(); + => GetDescendantNames(); /// /// Gets the names of all descendants of this field. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfButtonField.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfButtonField.cs index 1982cf1f..fb19b509 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfButtonField.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfButtonField.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. using System; @@ -34,7 +34,7 @@ protected string GetNonOffValue() { // Try to get the information from the appearance dictionary. // Just return the first key that is not /Off. - // Im not sure what is the right solution to get this value. + // I’m not sure what is the right solution to get this value. var ap = Elements[PdfAnnotation.Keys.AP] as PdfDictionary; if (ap != null) { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCatalog.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCatalog.cs index 1b500a58..7231ef8e 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCatalog.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCatalog.cs @@ -148,7 +148,7 @@ public PdfNameDictionary Names { _names = new PdfNameDictionary(Owner); Owner.Internals.AddObject(_names); - Elements.SetReference(Keys.Names, _names.Reference); + Elements.SetReference(Keys.Names, _names.Reference ?? throw TH.InvalidOperationException_ReferenceMustNotBeNull()); } } return _names; @@ -173,7 +173,7 @@ public PdfNamedDestinations Destinations _dests = new PdfNamedDestinations(); _dests = new PdfNamedDestinations(); Owner.Internals.AddObject(_dests); - Elements.SetReference(Keys.Dests, _dests.Reference); + Elements.SetReference(Keys.Dests, _dests.Reference ?? throw TH.InvalidOperationException_ReferenceMustNotBeNull()); } } return _dests; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContent.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContent.cs index dc022f0c..902f72b8 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContent.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContent.cs @@ -67,8 +67,7 @@ public bool Compressed /// void Decode() { - //if (Stream != null && Stream.Value != null) - if (Stream is { Value: { } }) // StL: Is this really more readable??? + if (Stream is { Value: not null }) { var item = Elements["/Filter"]; if (item != null) @@ -92,7 +91,7 @@ internal void PreserveGraphicsState() { // If a content stream is touched by PDFsharp it is typically because graphical operations are // prepended or appended. Some nasty PDF tools do not preserve the graphical state correctly. - // Therefore we try to relieve the problem by surrounding the content stream with push/restore + // Therefore, we try to relieve the problem by surrounding the content stream with push/restore // graphic state operation. if (Stream != null!) { @@ -128,7 +127,6 @@ internal override void WriteObject(PdfWriter writer) if (Stream != null!) { - //if (Owner.Options.CompressContentStreams) if (Owner.Options.CompressContentStreams && Elements.GetName("/Filter").Length == 0) { Stream.Value = Filtering.FlateDecode.Encode(Stream.Value, _document.Options.FlateEncodeMode); @@ -141,7 +139,8 @@ internal override void WriteObject(PdfWriter writer) base.WriteObject(writer); } - internal XGraphicsPdfRenderer? _pdfRenderer; + internal void SetRenderer(XGraphicsPdfRenderer? renderer) => _pdfRenderer = renderer; + XGraphicsPdfRenderer? _pdfRenderer; /// /// Predefined keys of this dictionary. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCrossReferenceTable.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCrossReferenceTable.cs index 37416217..327c212c 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCrossReferenceTable.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCrossReferenceTable.cs @@ -1,6 +1,13 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. +// Turn on all test code at one place and ensure, that it does not come accidentally to the release build. +#if true && TEST_CODE +#define TEST_CODE // The #define is redundant, but clarifies what it means. +#else +#undef TEST_CODE +#endif + using System.Collections; using Microsoft.Extensions.Logging; using PdfSharp.Logging; @@ -12,8 +19,19 @@ namespace PdfSharp.Pdf.Advanced /// Represents the cross-reference table of a PDF document. /// It contains all indirect objects of a document. /// + /// + /// New implementation:
+ /// * No deep nesting recursion anymore.
+ /// * Uses a Stack<PdfObject>.
+ ///
+ /// We use Dictionary<PdfReference, object?> instead of Set<PdfReference> because a dictionary + /// with an unused value is faster than a set. + ///
sealed class PdfCrossReferenceTable(PdfDocument document) // Must not be derived from PdfObject. { +#if TEST_CODE + readonly Stopwatch _stopwatch = new(); +#endif /// /// Gets or sets a value indicating whether this table is under construction. /// It is true while reading a PDF file. @@ -21,17 +39,21 @@ sealed class PdfCrossReferenceTable(PdfDocument document) // Must not be derived internal bool IsUnderConstruction { get; set; } /// - /// Gets the number of objects in the table. + /// Gets the current number of references in the table. /// public int Count => _objectTable.Count; /// - /// Adds a cross-reference entry to the table. Used when parsing the trailer. + /// Adds a cross-reference entry to the table. Used when parsing a trailer. /// public void Add(PdfReference iref) { if (iref.ObjectID.IsEmpty) + { + // When happens this? iref.ObjectID = new(GetNewObjectNumber()); + PdfSharpLogHost.DocumentProcessingLogger.LogWarning("iRef with empty object ID found."); + } // ReSharper disable once CanSimplifyDictionaryLookupWithTryAdd because it would not build with .NET Framework. if (_objectTable.ContainsKey(iref.ObjectID)) @@ -44,7 +66,7 @@ public void Add(PdfReference iref) // because releasing 6.1.0 had a higher priority. We will fix this in a later release. // However, using the last added object and logging an error is better than throwing an exception in all cases. PdfSharpLogHost.PdfReadingLogger.LogError("Object '{ObjectID}' already exists in xref table’s objects, referring to position {Position}. The latter one referring to position {Position} is used. " + - "This should not occur. If somebody came here, please send us your PDF file so that we can fix it (issues (at) pdfsharp.net.", oldIref.ObjectID, oldIref.Position, iref.Position); + $"This should not occur. If you think this is a bug in PDFsharp, please visit {UrlLiterals.LinkToCannotOpenPdfFile} for further information.", oldIref.ObjectID, oldIref.Position, iref.Position); _objectTable.Remove(iref.ObjectID); } @@ -59,16 +81,32 @@ public void Add(PdfReference iref) /// public void Add(PdfObject value) { + // ReSharper disable once NullableWarningSuppressionIsUsed if (value.Owner == null!) + { + PdfSharpLogHost.PdfReadingLogger.LogWarning("Object without owner gets owned by the document it was added to."); value.Document = document; + } else + { Debug.Assert(value.Owner == document); + if (value.Owner != document) + { + PdfSharpLogHost.PdfReadingLogger.LogError("Object not owned by the document it was added to."); + } + } if (value.ObjectID.IsEmpty) + { + // Create new object number. value.SetObjectID(GetNewObjectNumber(), 0); + } if (_objectTable.ContainsKey(value.ObjectID)) + { + // This must not happen. throw new InvalidOperationException("Object already in table."); + } _objectTable.Add(value.ObjectID, value.ReferenceNotNull); @@ -90,9 +128,14 @@ public bool TryAdd(PdfObject value) return false; } - public void Remove(PdfReference iref) + /// + /// Removes a PdfObject from the table. + /// + /// + public bool Remove(PdfReference iref) { - _objectTable.Remove(iref.ObjectID); + // Remove the reference by its ID. + return _objectTable.Remove(iref.ObjectID); } /// @@ -198,7 +241,7 @@ internal int Compact() int removed = _objectTable.Count; PdfReference[] irefs = TransitiveClosure(document.Trailer); -#if DEBUG +#if DEBUG_ // Turn on again // Have any two objects the same ID? Dictionary ids = []; foreach (PdfObjectID objID in _objectTable.Keys) @@ -248,7 +291,7 @@ internal int Compact() MaxObjectNumber = 0; _objectTable.Clear(); - foreach (PdfReference iref in irefs) + foreach (var iref in irefs) { // This if-statement is needed for corrupt PDF files from the wild. // Without the if-statement, an exception will be thrown if the file contains duplicate IDs ("An item with the same key has already been added to the dictionary."). @@ -277,7 +320,7 @@ internal void Renumber() int count = irefs.Length; for (int idx = 0; idx < count; idx++) { - PdfReference iref = irefs[idx]; + var iref = irefs[idx]; iref.ObjectID = new PdfObjectID(idx + 1); // Rehash with new number. _objectTable.Add(iref.ObjectID, iref); @@ -292,7 +335,7 @@ internal void Renumber() /// internal SizeType GetPositionOfObjectBehind(PdfObject obj, SizeType position) { -#if DEBUG +#if DEBUG_ if (obj.Reference == null) _ = typeof(int); #endif @@ -356,198 +399,308 @@ public void CheckConsistence() /// /// Calculates the transitive closure of the specified PdfObject with the specified depth, i.e. all indirect objects - /// recursively reachable from the specified object in up to maximally depth steps. + /// recursively reachable from the specified object. /// - public PdfReference[] TransitiveClosure(PdfObject pdfObject /*, int depth = Int16.MaxValue*/) + public PdfReference[] TransitiveClosure(PdfObject pdfObject) { + var logger = PdfSharpLogHost.DocumentProcessingLogger; + CheckConsistence(); - Dictionary objects = new(); - //_overflow = new(); -#if DEBUG - _nestingLevel = _maxNestingLevel = 0; +#if TEST_CODE + // ReSharper disable once InconsistentNaming because it is test-code. + Dictionary references_old = new(); + _stopwatch.Reset(); + _stopwatch.Start(); + TransitiveClosureImplementation_old(references_old, pdfObject); + _stopwatch.Stop(); + logger.LogInformation(nameof(TransitiveClosureImplementation_old) + " runs {MS}ms.", _stopwatch.ElapsedMilliseconds); + logger.LogInformation($"TC: {references_old.Count}"); + logger.LogInformation("--------------------"); #endif - TransitiveClosureImplementation(objects, pdfObject); -#if DEBUG - // TODO Check - PdfSharpLogHost.Logger.LogInformation("Transitive closure max nesting level is {NestingLevel}.", _maxNestingLevel); + +#if TEST_CODE + _stopwatch.Reset(); + _stopwatch.Start(); +#endif + Dictionary references = new(); + TransitiveClosureImplementation(references, pdfObject); +#if TEST_CODE + _stopwatch.Stop(); + logger.LogInformation(nameof(TransitiveClosureImplementation) + " runs {MS}ms.", _stopwatch.ElapsedMilliseconds); + logger.LogInformation($"TC: {references.Count}"); + logger.LogInformation("--------------------"); + + Debug.Assert(references.Count == references_old.Count); #endif -#if false - TryAgain: - if (_overflow.Count > 0) + +#if TEST_CODE + _stopwatch.Reset(); + _stopwatch.Start(); + foreach (var val in references_old) { - var array = new PdfObject[_overflow.Count]; - _overflow.Keys.CopyTo(array, 0); - _overflow = new(); - for (int idx = 0; idx < array.Length; idx++) - { - PdfObject obj = array[idx]; - TransitiveClosureImplementation(objects, obj); - } - goto TryAgain; + var valNew = references.ContainsKey((PdfReference)val.Key); + if (valNew == false) + _ = typeof(int); + Debug.Assert(valNew); } + _stopwatch.Stop(); + logger.LogInformation("references_old check runs {MS}ms.", _stopwatch.ElapsedMilliseconds); + #endif CheckConsistence(); - ICollection collection = objects.Keys; + ICollection collection = references.Keys; int count = collection.Count; PdfReference[] irefs = new PdfReference[count]; collection.CopyTo(irefs, 0); -#if true_ - for (int i = 0; i < count; i++) - for (int j = 0; j < count; j++) - if (i != j) - { - Debug.Assert(ReferenceEquals(irefs[i].Document, _document)); - Debug.Assert(irefs[i] != irefs[j]); - Debug.Assert(!ReferenceEquals(irefs[i], irefs[j])); - Debug.Assert(!ReferenceEquals(irefs[i].Value, irefs[j].Value)); - Debug.Assert(!Equals(irefs[i].ObjectID, irefs[j].Value.ObjectID)); - Debug.Assert(irefs[i].ObjectNumber != irefs[j].Value.ObjectNumber); - Debug.Assert(ReferenceEquals(irefs[i].Document, irefs[j].Document)); - _ = typeof(int); - } -#endif return irefs; } - //// TODO: Delete next two lines? - //int _nestingLevel; - //Dictionary _overflow_ = new(); -#if DEBUG - int _nestingLevel; - int _maxNestingLevel; -#endif - - // TODO: Write new non-recursive function and counter check with this implementation. - void TransitiveClosureImplementation(Dictionary objects, PdfObject pdfObject) +#if TEST_CODE + /// + /// This is the old implementation of the transitive closure. It is a recursive implementation. + /// We keep it some time to use it for counter-checking the new non-recursive implementation. + /// + /// + /// + void TransitiveClosureImplementation_old(Dictionary references, PdfObject pdfObject) { - try + IEnumerable? enumerable = null; + PdfDictionary? dict; + PdfArray? array; + if ((dict = pdfObject as PdfDictionary) != null) + enumerable = dict.Elements.Values; + else if ((array = pdfObject as PdfArray) != null) + enumerable = array.Elements; + else + Debug.Assert(false, "Should not come here."); + + if (enumerable != null!) { + foreach (PdfItem item in enumerable) + { + if (item is PdfReference iref) + { + // Is this an indirect reference to an object that does not exist? + //if (iref.Document == null) + //{ + // Deb/ug.WriteLine("Dead object detected: " + iref.ObjectID.ToString()); + // PdfReference dead = DeadObject; + // iref.ObjectID = dead.ObjectID; + // iref.Document = _document; + // iref.SetObject(dead.Value); + // PdfDictionary dict = (PdfDictionary)dead.Value; + + // dict.Elements["/DeadObjectCount"] = + // new PdfInteger(dict.Elements.GetInteger("/DeadObjectCount") + 1); + + // iref = dead; + //} + + if (!ReferenceEquals(iref.Document, document)) + { + //Debug.WriteLine($"Bad iref: {iref.ObjectID.ToString()}"); + PdfSharpLogHost.PdfReadingLogger.LogError($"Bad iref: {iref.ObjectID.ToString()}"); + } + Debug.Assert(ReferenceEquals(iref.Document, document) || iref.Document == null, "External object detected!"); + + if (references.ContainsKey(iref) is false) + { + PdfObject value = iref.Value; + + // Ignore unreachable objects. + if (iref.Document != null) + { + // ... from trailer hack + if (value == null!) // Can it be null? + { + iref = _objectTable[iref.ObjectID]; + Debug.Assert(iref.Value != null); + value = iref.Value; + } + Debug.Assert(ReferenceEquals(iref.Document, document)); + references.Add(iref, null); + //Debug.WriteLine(String.Format("objects.Add('{0}', null);", iref.ObjectID.ToString())); + if (value is PdfArray or PdfDictionary) + TransitiveClosureImplementation_old(references, value); + } #if DEBUG - _nestingLevel++; - _maxNestingLevel = Math.Max(_maxNestingLevel, _nestingLevel); + else + { + _ = typeof(int); + } #endif -#if false - if (_nestingLevel >= 1000) - { - // ReSharper disable once CanSimplifyDictionaryLookupWithTryAdd because it would not build with .NET Framework. - if (!_overflow.ContainsKey(pdfObject)) - _overflow.Add(pdfObject, null); - return; + } + } + else + { + if (item is PdfObject pdfObj and (PdfDictionary or PdfArray)) + TransitiveClosureImplementation_old(references, pdfObj); + } } + } + } #endif -#if DEBUG_ - //enterCount++; - if (enterCount == 5400) - _ = typeof(int); - //if (!Object.ReferenceEquals(pdfObject.Owner, _document)) - // _ = typeof(int); - //////Debug.Assert(Object.ReferenceEquals(pdfObject27.Document, _document)); - // if (item is PdfObject && ((PdfObject)item).ObjectID.ObjectNumber == 5) - // Deb/ug.WriteLine("items: " + ((PdfObject)item).ObjectID.ToString()); - //if (pdfObject.ObjectNumber == 5) - // _ = typeof(int); + /// + /// The new non-recursive implementation. + /// + /// + /// + void TransitiveClosureImplementation(Dictionary references, PdfObject pdfObject) + { + var logger = PdfSharpLogHost.DocumentProcessingLogger; +#if TEST_CODE + //Dictionary doubleCheckReferences = []; + //Dictionary pivots = []; + int loopCounter = 0; + int maxStackLength = 0; + int alreadyInTable = 0; + int elementsAdded = 0; #endif - IEnumerable? enumerable = null; + // Initialize the stack. + Stack stack = []; + FindReferencedItems(pdfObject); + + // Loop until no more new references are found. + while (stack.Count > 0) + { + var pivot = stack.Pop(); +#if TEST_CODE + maxStackLength = Math.Max(maxStackLength, stack.Count); + loopCounter++; + + //// ReSharper disable once CanSimplifyDictionaryLookupWithTryAdd because TryAdd does not exist in .NET Framework. + //if (!pivots.ContainsKey(pivot)) + //{ + // pivots.Add(pivot, null); + //} + //else + //{ + // _ = pivot.Equals(null); + // _ = typeof(int); + //} +#endif + FindReferencedItems(pivot); + } +#if TEST_CODE + logger.LogInformation( + "LoopCounter: {LoopCounter}, MaxStackLength: {MaxStackLength}, AlreadyInTable: {AlreadyInTable}, ElementsAdded: {ElementsAdded}", + loopCounter, maxStackLength, alreadyInTable, elementsAdded); + + //Dictionary test = []; + //foreach (var pivotsValue in pivots.Keys) + //{ + // if (pivotsValue.ObjectID.ObjectNumber == 0) + // continue; + + // test.Add(pivotsValue.ObjectID.ObjectNumber, null); + //} + //int ids = test.Count; +#endif + return; + + // Add all dictionaries and arrays referenced by the specified object + // that are not already in references to the stack. + void FindReferencedItems(PdfObject pdfObj) + { + Debug.Assert(pdfObj is PdfDictionary or PdfArray, "Call with dictionary or array only."); + + IEnumerable? items = null; PdfDictionary? dict; PdfArray? array; - if ((dict = pdfObject as PdfDictionary) != null) - enumerable = dict.Elements.Values; - else if ((array = pdfObject as PdfArray) != null) - enumerable = array.Elements; + if ((dict = pdfObj as PdfDictionary) is not null) + items = dict.Elements.Values; + else if ((array = pdfObj as PdfArray) is not null) + items = array.Elements; else Debug.Assert(false, "Should not come here."); - if (enumerable != null!) + foreach (PdfItem item in items) { - foreach (PdfItem item in enumerable) + if (item is PdfReference iref) { - if (item is PdfReference iref) + // Case: The item is an indirect object. + + // Check if the reference belongs to the current document. + if (!ReferenceEquals(iref.Document, document)) { - // Is this an indirect reference to an object that does not exist? - //if (iref.Document == null) - //{ - // Deb/ug.WriteLine("Dead object detected: " + iref.ObjectID.ToString()); - // PdfReference dead = DeadObject; - // iref.ObjectID = dead.ObjectID; - // iref.Document = _document; - // iref.SetObject(dead.Value); - // PdfDictionary dict = (PdfDictionary)dead.Value; - - // dict.Elements["/DeadObjectCount"] = - // new PdfInteger(dict.Elements.GetInteger("/DeadObjectCount") + 1); - - // iref = dead; - //} - - if (!ReferenceEquals(iref.Document, document)) + logger.LogError($"Bad iref: {iref.ObjectID.ToString()}"); + } + + Debug.Assert(ReferenceEquals(iref.Document, document) || iref.Document == null, + "External object detected!"); + + // Is the reference not yet in the collection of referenced objects? + if (references.ContainsKey(iref)) + { +#if TEST_CODE + alreadyInTable++; +#endif + continue; + } + + var newObject = iref.Value; + + // Ignore unreachable objects. + if (iref.Document != null) + { + // ... from trailer hack + if (newObject == null!) // Can it be null? { - //Debug.WriteLine($"Bad iref: {iref.ObjectID.ToString()}"); - PdfSharpLogHost.PdfReadingLogger.LogError($"Bad iref: {iref.ObjectID.ToString()}"); + logger.LogInformation("Value of a PdfReference is null."); + iref = _objectTable[iref.ObjectID]; + Debug.Assert(iref.Value != null); + newObject = iref.Value; } - Debug.Assert(ReferenceEquals(iref.Document, document) || iref.Document == null, "External object detected!"); -#if DEBUG_ - if (iref.ObjectID.ObjectNumber == 23) + + Debug.Assert(ReferenceEquals(iref.Document, document)); + if (newObject.ObjectID.ObjectNumber != 0) + references.Add(iref, null); +#if TEST_CODE__ + // ReSharper disable once CanSimplifyDictionaryLookupWithTryAdd because auf .NET Framework / Standard + if (!doubleCheckReferences.ContainsKey(value)) + doubleCheckReferences.Add(value, null); + else _ = typeof(int); #endif - if (objects.ContainsKey(iref) is false) - { - PdfObject value = iref.Value; - // Ignore unreachable objects. - if (iref.Document != null) - { - // ... from trailer hack - if (value == null!) // Can it be null? - { - iref = _objectTable[iref.ObjectID]; - Debug.Assert(iref.Value != null); - value = iref.Value; - } - Debug.Assert(ReferenceEquals(iref.Document, document)); - objects.Add(iref, null); - //Debug.WriteLine(String.Format("objects.Add('{0}', null);", iref.ObjectID.ToString())); - if (value is PdfArray or PdfDictionary) - TransitiveClosureImplementation(objects, value); - } -#if DEBUG - else - { - _ = typeof(int); - // objects2.Add(this[iref.ObjectID], null); - } + if (newObject is PdfDictionary or PdfArray) + { + stack.Push(newObject); +#if TEST_CODE + elementsAdded++; #endif - } } else { - //var pdfObject28 = item as PdfObject; - ////if (pdfObject28 != null) - //// Debug.Assert(Object.ReferenceEquals(pdfObject28.Document, _document)); - //if (pdfObject28 != null && (pdfObject28 is PdfDictionary || pdfObject28 is PdfArray)) - //if (pdfObject28 != null) - // Debug.Assert(Object.ReferenceEquals(pdfObject28.Document, _document)); - if (item is PdfObject pdfObj and (PdfDictionary or PdfArray)) - TransitiveClosureImplementation(objects, pdfObj); + // Can we come here? + logger.LogWarning("Document has no owner."); } } - } - } - finally - { -#if DEBUG - _nestingLevel--; + else + { + // Case: The item is a direct object. + + if (item is PdfObject pdfDictionaryOrArray and (PdfDictionary or PdfArray)) + { +#if TEST_CODE_ + // Not useful, is too slow. + if (stack.Contains(pdfDictionaryOrArray)) + _ = typeof(int); +#endif + stack.Push(pdfDictionaryOrArray); +#if TEST_CODE + elementsAdded++; #endif + } + } + } } } - void TransitiveClosureImplementationNew(Dictionary objects, PdfObject pdfObject) - { - // ... - } - +#if true_ // Not used. /// /// Gets the cross-reference to an object used for undefined indirect references. /// @@ -565,39 +718,10 @@ public PdfReference DeadObject } } PdfDictionary? _deadObject; - +#endif /// /// Represents the relation between PdfObjectID and PdfReference for a PdfDocument. /// readonly Dictionary _objectTable = []; } - - ///// - ///// Represents the cross-reference table of a PDF document. - ///// It contains all indirect objects of a document. - ///// - //internal sealed class PdfCrossReferenceStreamTable // Must not be derived from PdfObject. - //{ - // public PdfCrossReferenceStreamTable(PdfDocument document) - // { - // _document = document; - // } - // readonly PdfDocument _document; - - // public class Item - // { - // public PdfReference Reference; - - // public readonly List Entries = new List(); - // } - //} - - //struct CrossReferenceStreamEntry - //{ - // public int Type; - - // public int Field2; - - // public int Field3; - //} } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfEmbeddedFileStream.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfEmbeddedFileStream.cs index 9b403097..34fa0b8d 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfEmbeddedFileStream.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfEmbeddedFileStream.cs @@ -17,7 +17,7 @@ public PdfEmbeddedFileStream(PdfDocument document, Stream stream) : base(documen _data = new byte[stream.Length]; using (stream) { - stream.Read(_data, 0, (int)stream.Length); + _ = stream.Read(_data, 0, (int)stream.Length); } Initialize(); } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfFileSpecification.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfFileSpecification.cs index a197d86b..09da5b41 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfFileSpecification.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfFileSpecification.cs @@ -29,7 +29,7 @@ void Initialize() var embeddedFileDictionary = new PdfDictionary(Owner); Owner.Internals.AddObject(_embeddedFileStream); - embeddedFileDictionary.Elements.SetReference(Keys.F, _embeddedFileStream.Reference); + embeddedFileDictionary.Elements.SetReference(Keys.F, _embeddedFileStream.Reference ?? throw TH.InvalidOperationException_ReferenceMustNotBeNull()); embeddedFileDictionary.Elements.SetReference(Keys.UF, _embeddedFileStream.Reference); Elements.SetObject(Keys.EF, embeddedFileDictionary); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfImage.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfImage.cs index a12381ac..535bbb3d 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfImage.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfImage.cs @@ -258,7 +258,7 @@ void InitializeJpeg(PdfDocumentOptions options) else { // If we have a stream, copy data from the stream. - if (_image._stream != null && _image._stream.CanSeek) + if (_image._stream != null! && _image._stream.CanSeek) { memory = new MemoryStream(); ownMemory = true; @@ -273,18 +273,20 @@ void InitializeJpeg(PdfDocumentOptions options) } else { - // TODO_OLD Anything we can do here? - //#if CORE _WITH _GDI - // // No stream, no filename, get image data. - // // Save the image to a memory stream. - // _image._gdiImage.Save(memory, ImageFormat.Jpeg); - //#endif +#if GDI + // No stream, no filename, get image data from GDI image. + // Save the image to a memory stream. + memory = new MemoryStream(); + ownMemory = true; + _image._gdiImage.Save(memory, ImageFormat.Jpeg); +#endif } } if (memory is null || (int)memory.Length == 0) { Debug.Assert(false, "Internal error? JPEG image, but file not found!"); + throw new InvalidOperationException("JPEG image used, but cannot access image data!"); } #if GDI @@ -532,9 +534,9 @@ void InitializeNonJpeg(PdfDocumentOptions options) break; default: -//#if DEBUGxxx -// image.image.Save("$$$.bmp", ImageFormat.Bmp); -//#endif + //#if DEBUGxxx + // image.image.Save("$$$.bmp", ImageFormat.Bmp); + //#endif throw new NotImplementedException("Image format not supported."); } #endif @@ -842,7 +844,7 @@ void CreateTrueColorMemoryBitmap(int components, int bits, bool hasAlpha, PdfDoc // Anything needed for CMYK? Do we have sample images? Elements[Keys.ColorSpace] = new PdfName(components == 1 ? "/DeviceGray" : "/DeviceRGB"); if (_image.Interpolate) - { + { // #PDF-A if (_document.IsPdfA) { @@ -1059,7 +1061,7 @@ void ReadTrueColorMemoryBitmap(int components, int bits, bool hasAlpha) // Anything needed for CMYK? Do we have sample images? Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB"); if (_image.Interpolate) - { + { // #PDF-A if (_document.IsPdfA) { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfImageTable.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfImageTable.cs index fc1928f9..e9ef262e 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfImageTable.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfImageTable.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. using PdfSharp.Drawing; @@ -164,7 +164,7 @@ public ImageSelector(XImage image, PdfDocumentOptions options) } /// - /// Creates an instance of HashAlgorithm fr use in ImageSelector. + /// Creates an instance of HashAlgorithm für use in ImageSelector. /// private HashAlgorithm GetHashCreator() { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfInternals.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfInternals.cs index 2a447206..376520ee 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfInternals.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfInternals.cs @@ -162,7 +162,8 @@ public PdfObject[] GetAllObjects() /// Creates the indirect object of the specified type, adds it to the document, /// and returns the object. ///
- public T CreateIndirectObject<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T>() where T : PdfObject + public T CreateIndirectObject<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T>() + where T : PdfObject { #if true T obj = Activator.CreateInstance(); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfNameDictionary.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfNameDictionary.cs index 515f085a..760122f3 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfNameDictionary.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfNameDictionary.cs @@ -36,7 +36,7 @@ internal void AddNamedDestination(string destinationName, int destinationPage, P { _dests = new PdfNameTreeNode(); Owner.Internals.AddObject(_dests); - Elements.SetReference(Keys.Dests, _dests.Reference); + Elements.SetReference(Keys.Dests, _dests.Reference ?? throw TH.InvalidOperationException_ReferenceMustNotBeNull()); } // destIndex > Owner.PageCount can happen when rendering pages using PDFsharp directly. @@ -68,7 +68,7 @@ internal void AddEmbeddedFile(string name, Stream stream) { _embeddedFiles = new PdfNameTreeNode(); Owner.Internals.AddObject(_embeddedFiles); - Elements.SetReference(Keys.EmbeddedFiles, _embeddedFiles.Reference); + Elements.SetReference(Keys.EmbeddedFiles, _embeddedFiles.Reference ?? throw TH.InvalidOperationException_ReferenceMustNotBeNull()); } var embeddedFileStream = new PdfEmbeddedFileStream(Owner, stream); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfObjectStream.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfObjectStream.cs index 19fc8103..63ae5adb 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfObjectStream.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfObjectStream.cs @@ -1,6 +1,8 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. +using Microsoft.Extensions.Logging; +using PdfSharp.Logging; using PdfSharp.Pdf.IO; namespace PdfSharp.Pdf.Advanced @@ -37,7 +39,7 @@ internal PdfObjectStream(PdfDictionary dict, Parser documentParser) int first = Elements.GetInteger(Keys.First); Stream.TryUncompress(); - var parser = new Parser(_document, new MemoryStream(Stream.Value), documentParser); + var parser = new Parser(_document, new MemoryStream(Stream.UnfilteredValue), documentParser); _header = parser.ReadObjectStreamHeader(n, first); #if DEBUG_ && CORE @@ -49,57 +51,36 @@ internal PdfObjectStream(PdfDictionary dict, Parser documentParser) } /// - /// Reads all references inside the ObjectStream and returns all ObjectIDs and offsets for its objects. + /// Returns all ObjectIDs and read positions for the objects inside this ObjectStream. /// - internal ICollection> ReadReferencesAndOffsets(PdfCrossReferenceTable xrefTable) + internal ICollection> ReadObjectIDsWithOffsets() { var length = _header.Length; - _objectOffsets = []; - ////// Create parser for stream. - ////Parser parser = new Parser(_document, new MemoryStream(Stream.Value)); - for (var idx = 0; idx < length; idx++) + Dictionary objectOffsets = []; + + // For duplicate IDs the newest object should be read first, to ignore older objects with the same ID read later. + // Therefore, we read the offsets from high to low. + for (var idx = length - 1; idx >= 0; idx--) { int objectNumber = _header[idx][0]; int offset = _header[idx][1]; var objectID = new PdfObjectID(objectNumber); - // HACK_OLD: -1 indicates compressed object. - var iref = new PdfReference(objectID, -1); - ////iref.ObjectID = objectID; - ////iref.Value = xrefStream; - - _objectOffsets.Add(objectID, offset); - - if (!xrefTable.Contains(iref.ObjectID)) + // ReSharper disable once CanSimplifyDictionaryLookupWithTryAdd + if (!objectOffsets.ContainsKey(objectID)) { - xrefTable.Add(iref); + objectOffsets.Add(objectID, offset); } else { -#if DEBUG_ - _ = typeof(int); -#endif + // Ignore object with objectID already on the list. + PdfSharpLogHost.PdfReadingLogger.LogWarning("Ignoring object with ID {objectID} while reading offsets in object stream {objectStreamId} because an object with that ID was already read in that object stream.", objectID, ObjectID); } } - return _objectOffsets; - } - - /// - /// Tries to get the position of the PdfObject inside this ObjectStream. - /// - internal bool TryGetObjectOffset(PdfObjectID pdfObjectID, out SizeType offset, SuppressExceptions? suppressObjectOrderExceptions) - { - if (_objectOffsets == null) - { - SuppressExceptions.HandleError(suppressObjectOrderExceptions, () => throw TH.InvalidOperationException_ReferencesOfObjectStreamNotYetRead()); - offset = -1; - return false; - } - - return _objectOffsets.TryGetValue(pdfObjectID, out offset); + return objectOffsets; } /// @@ -110,11 +91,6 @@ internal bool TryGetObjectOffset(PdfObjectID pdfObjectID, out SizeType offset, S /// readonly int[][] _header = default!; // Reference: Page 102 - /// - /// Manages the read positions for all PdfObjects inside this ObjectStream. - /// - Dictionary? _objectOffsets; - /// /// Predefined keys common to all font dictionaries. /// diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfReference.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfReference.cs index 4422f748..7240a8b5 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfReference.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfReference.cs @@ -16,12 +16,12 @@ namespace PdfSharp.Pdf.Advanced [DebuggerDisplay("iref({ObjectNumber}, {GenerationNumber})")] public sealed class PdfReference : PdfItem { - // About PdfReference - // + // About PdfReference + // // * A PdfReference holds either the ObjectID or the PdfObject or both. - // + // // * Each PdfObject has a PdfReference if and only if it is an indirect object. Direct objects have - // no PdfReference, because they are embedded in a parent objects. + // no PdfReference, because they are embedded in a parent object. // // * PdfReference objects are used to reference PdfObject instances. A value in a PDF dictionary // or array that is a PdfReference represents an indirect reference. A value in a PDF dictionary @@ -37,13 +37,25 @@ public sealed class PdfReference : PdfItem /// /// Initializes a new PdfReference instance for the specified indirect object. + /// An indirect PDF object has one and only one reference. + /// You cannot create an instance of PdfReference. /// - public PdfReference(PdfObject pdfObject) + PdfReference(PdfObject pdfObject, PdfObjectID objectID, SizeType position) { if (pdfObject.Reference != null) throw new InvalidOperationException("Must not create iref for an object that already has one."); _value = pdfObject; pdfObject.Reference = this; + _objectID = objectID; + + if (position != 0) + _position = position; + //else + //{ + // // Can be 0 or -1. + // //_ = typeof(int); + // //PdfSharpLogHost.DocumentProcessingLogger.LogError("Position is 0."); + //} #if UNIQUE_IREF && DEBUG _uid = ++s_counter; #endif @@ -52,7 +64,7 @@ public PdfReference(PdfObject pdfObject) /// /// Initializes a new PdfReference instance from the specified object identifier and file position. /// - public PdfReference(PdfObjectID objectID, SizeType position) + PdfReference(PdfObjectID objectID, SizeType position) { _objectID = objectID; _position = position; @@ -61,6 +73,25 @@ public PdfReference(PdfObjectID objectID, SizeType position) #endif } + /// + /// Creates a PdfReference from a PdfObject. + /// + /// + /// + /// + /// + internal static PdfReference CreateFromObject(PdfObject pdfObject, PdfObjectID objectID, SizeType position) + => new(pdfObject, objectID, position); + + /// + /// Creates a PdfReference from a PdfObjectID. + /// + /// + /// + /// + internal static PdfReference CreateForObjectID(PdfObjectID objectID, SizeType position) + => new(objectID, position); + /// /// Writes the object in PDF iref table format. /// @@ -121,7 +152,7 @@ public PdfObjectID ObjectID public SizeType Position { get => _position; - set + internal set { Debug.Assert(value >= 0); _position = value; @@ -135,7 +166,7 @@ public SizeType Position public PdfObject Value { get => _value; - set + internal set { Debug.Assert(value != null, "The value of a PdfReference must never be null."); Debug.Assert(value.Reference == null || ReferenceEquals(value.Reference, this), "The reference of the value must be null or this."); @@ -144,7 +175,7 @@ public PdfObject Value value.Reference = this; } } - PdfObject _value = default!; + PdfObject _value = null!; /// /// Resets value to null. Used when reading object stream. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfTrailer.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfTrailer.cs index bab525f9..1c57bada 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfTrailer.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfTrailer.cs @@ -41,7 +41,7 @@ public PdfTrailer(PdfCrossReferenceStream trailer) if (iref != null) Elements.SetReference(Keys.Info, iref); - Elements.SetReference(Keys.Root, trailer.Elements.GetReference(Keys.Root)); + Elements.SetReference(Keys.Root, trailer.Elements.GetReference(Keys.Root) ?? throw TH.InvalidOperationException_ReferenceMustNotBeNull()); Elements.SetInteger(Keys.Size, trailer.Elements.GetInteger(Keys.Size)); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content.Objects/CObjects.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content.Objects/CObjects.cs index 22273bf1..068d8fc5 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content.Objects/CObjects.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content.Objects/CObjects.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. using System.Collections; @@ -102,6 +102,12 @@ protected override CObject Copy() /// The sequence. public void Add(CSequence sequence) { + if (sequence is CArray array) + { + _items.Add(array); + return; + } + int count = sequence.Count; for (int idx = 0; idx < count; idx++) _items.Add(sequence[idx]); @@ -205,7 +211,12 @@ public override string ToString() var s = new StringBuilder(); for (int idx = 0; idx < _items.Count; idx++) + { + // Add spaces except for first item. + if (s.Length > 0) + s.Append(' '); s.Append(_items[idx]); + } return s.ToString(); } @@ -686,7 +697,7 @@ internal override void WriteObject(ContentWriter writer) } #region Printing/Debugger display - /// Function returning string that will be used to display objects value in debugger for this type of objects. + /// Function returning string that will be used to display object’s value in debugger for this type of objects. public static Func debuggerDisplay { get; set; } = o => o.ToString(15); string DebuggerDisplay => debuggerDisplay(this); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/CLexer.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/CLexer.cs index e7d0f47f..232e5f12 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/CLexer.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/CLexer.cs @@ -3,23 +3,23 @@ using System.Text; using Microsoft.Extensions.Logging; -using PdfSharp.Internal; using PdfSharp.Logging; namespace PdfSharp.Pdf.Content { /// - /// Lexical analyzer for PDF content files. Adobe specifies no grammar, but it seems that it + /// Lexical analyzer for PDF content streams. Adobe specifies no grammar, but it seems that it /// is a simple post-fix notation. /// public class CLexer { /// - /// Initializes a new instance of the Lexer class. + /// Initializes a new instance of the CLexer class. /// public CLexer(byte[] content) { _content = content; + ContLength = _content.Length; _charIndex = 0; } @@ -28,7 +28,18 @@ public CLexer(byte[] content) /// public CLexer(MemoryStream content) { - _content = content.ToArray(); + if (content.TryGetBuffer(out var buffer)) + { + _content = buffer.Array ?? throw new InvalidOperationException("Array must not be null."); + // Memory streams are 32-bit byte arrays. + ContLength = (int)content.Length; + } + else + { + _content = content.ToArray(); + ContLength = _content.Length; + } + _charIndex = 0; } @@ -49,11 +60,11 @@ public CSymbol ScanNextToken() goto Again; case '/': - return Symbol = ScanName(); + return ScanName(); case '+': case '-': - return Symbol = ScanNumber(); + return ScanNumber(); case '[': ScanNextChar(); @@ -64,25 +75,25 @@ public CSymbol ScanNextToken() return Symbol = CSymbol.EndArray; case '(': - return Symbol = ScanLiteralString(); + return ScanLiteralString(); case '<': if (_nextChar == '<') - return Symbol = ScanDictionary(); - return Symbol = ScanHexadecimalString(); + return ScanDictionary(); + return ScanHexadecimalString(); case '.': - return Symbol = ScanNumber(); + return ScanNumber(); case '"': case '\'': - return Symbol = ScanOperator(); + return ScanOperator(); } if (Char.IsDigit(ch)) - return Symbol = ScanNumber(); + return ScanNumber(); if (Char.IsLetter(ch)) - return Symbol = ScanOperator(); + return ScanOperator(); if (ch == Chars.EOF) return Symbol = CSymbol.Eof; @@ -279,11 +290,7 @@ protected CSymbol ScanDictionary() else { ScanNextChar(); -#if true - return CSymbol.Dictionary; -#else - return CSymbol.String; -#endif + return Symbol = CSymbol.Dictionary; } } } @@ -298,86 +305,173 @@ protected CSymbol ScanDictionary() public CSymbol ScanNumber() { // Note: This is a copy of Lexer.ScanNumber with minimal changes. Keep both versions in sync as far as possible. - const int maxDigitsForLong = 18; - const int maxDecimalDigits = 10; - long value = 0; - int totalDigits = 0; - int decimalDigits = 0; - bool period = false; - bool negative = false; + + // Parsing Strategy: + // Most real life numbers in PDF files have less than 19 digits. So we try to parse all digits as 64-bit integers + // in the first place. All leading zeros are skipped and not counted. + // If we found a decimal point we later divide the result by the appropriate power of 10 and covert is to Double. + // For edge cases, which are numbers with 19 digits, the token is parsed again with 'Int64.TryParse()' and + // if this fails with 'Double.TryParse'. + // If 'testForObjectReference' is 'true' and the value has up to 7 digits, no decimal point and no sign, + // we look ahead whether it is an object reference having the form '{object-number} {generation-number} R'. + + const int maxDigitsForLong = 18; // Up to 18 digits values can safely fit into 64-bit integer. + const int maxDecimalDigits = 10; // Maximum number of decimal digits we process. + var value = 0L; // The 64-bit value we have parsed. + var canBeLeadingZero = true; // True if a '0' is a leading zero and gets skipped. + var leadingZeros = 0; // The number of scanned leading zeros. Used for optional warning. + var totalDigits = 0; // The total number of digits scanned. E.g. is 7 for '123.4567'. + var decimalDigits = 0; // The total number of decimal digits scanned. E.g. is 4 for '123.4567'. + //var allDecimalDigitsAreZero = true; // Not used anymore, because '123.000' is always treated as double, never as integer. + var period = false; // The decimal point '.' was scanned. + var negative = false; // The value is negative and the scanned value is negated. + + var ch = _currChar; + Debug.Assert(ch is '+' or '-' or '.' or (>= '0' and <= '9')); ClearToken(); - char ch = _currChar; if (ch is '+' or '-') { if (ch == '-') negative = true; _token.Append(ch); ch = ScanNextChar(); + + // Never saw this in any PDF file. + if (ch is not ('.' or >= '0' and <= '9')) + { + PdfSharpLogHost.Logger.LogError("+/- not followed by a number or decimal point."); + } } + + // Scan the number. while (true) { - if (Char.IsDigit(ch)) + if (ch is >= '0' and <= '9') { _token.Append(ch); - ++totalDigits; + + if (canBeLeadingZero) + { + if (ch == '0') + { + leadingZeros++; + } + else + { + canBeLeadingZero = false; + ++totalDigits; + } + } + else + { + ++totalDigits; + } + if (decimalDigits < maxDecimalDigits) { // Calculate the value if it still fits into long. + // Lexer only: The value gets later parsed again by .NET if the total number of digits exceeds 18 digits. if (totalDigits <= maxDigitsForLong) value = 10 * value + ch - '0'; } + if (period) + { ++decimalDigits; + // A number with a decimal point is always considered as Symbol.Real, + // even if it fits in Symbol.Integer or Symbol.LongInteger. + // KEEP for documental purposes. + //// E.g. '123.0000' is real, but fits in an integer. + //if (ch is not '0') + // allDecimalDigitsAreZero = false; + } } else if (ch == '.') { + _token.Append(ch); + + // More than one period? if (period) - ContentReaderDiagnostics.ThrowContentReaderException("More than one period in number."); + ContentReaderDiagnostics.ThrowContentReaderException("More than one decimal point in number."); period = true; - _token.Append(ch); + canBeLeadingZero = false; } else break; ch = ScanNextChar(); } - if (totalDigits > maxDigitsForLong || - decimalDigits > maxDecimalDigits) + if (leadingZeros > 1) +#pragma warning disable CA2254 // This is a rare case. Therefor we use string interpolation. + PdfSharpLogHost.PdfReadingLogger.LogWarning($"Token '{_token}' has more than one leading zero."); +#pragma warning restore CA2254 + + // CLexer does not support LongInteger. + if (totalDigits > maxDigitsForLong || decimalDigits > maxDecimalDigits) { - // The number is too big for long or has too many decimal digits for our own code, so we provide it as real only. - // Number will be parsed here. + //// Case: It is not guarantied that the number fits in a 64-bit integer. + //// It is not integer if there is a period. + //if (period is false && totalDigits == maxDigitsForLong + 1) + //{ + // // Case: We have exactly 19 digits and no decimal point, which might fit in a 64-bit integer, + // // depending on the value. + // // If the 19-digit numbers is + // // in the range [1,000,000,000,000,000,000 .. 9,223,372,036,854,775,807] + // // or + // // in the range [-9,223,372,036,854,775,808 .. -1,000,000,000,000,000,000] + // // it is a 64-bit integer. Otherwise, it is not. + // // Because this is a super rare case we make life easy and parse the scanned token again by .NET. + // if (Int64.TryParse(_token.ToString(), out var result)) + // { + // _tokenAsLong = result; + // _tokenAsReal = result; + // return Symbol = Symbol.LongInteger; + // } + //} + + // Case: The number is too big for long or has too many decimal digits for our own code, + // so we provide it as real only. + // Number will be parsed by .NET. _tokenAsReal = Double.Parse(_token.ToString(), CultureInfo.InvariantCulture); - return CSymbol.Real; + + return Symbol = CSymbol.Real; } + // Case: The number is in range [0 .. 999,999,999,999,999,999] and fits into a 64-bit integer. if (negative) - value = -value; + value = -value; // Flipping 64-bit integer sign is safe here. if (period) { + // Case: A number with a period is always considered to be real value. if (decimalDigits > 0) { _tokenAsReal = value / PowersOf10[decimalDigits]; - //_tokenAsLong = value / PowersOf10[decimalDigits]; + // KEEP for documental purposes. + //// It is not integer if there is a period. + //if (allDecimalDigitsAreZero) + // _tokenAsLong = (long)_tokenAsReal; } else { _tokenAsReal = value; - _tokenAsLong = value; + // KEEP for documental purposes. + //// It is not integer if there is a period. + // _tokenAsLong = value; } - return CSymbol.Real; + return Symbol = CSymbol.Real; } _tokenAsLong = value; _tokenAsReal = Convert.ToDouble(value); Debug.Assert(Int64.Parse(_token.ToString(), CultureInfo.InvariantCulture) == value); - if (value is >= Int32.MinValue and < Int32.MaxValue) - return CSymbol.Integer; + if (value is >= Int32.MinValue and <= Int32.MaxValue) + return Symbol = CSymbol.Integer; - return CSymbol.Real; + return Symbol = CSymbol.Real; // CLexer returns "Real" because there is no "LongInteger". } static readonly double[] PowersOf10 = [1, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000, 100_000_000, 1_000_000_000, 10_000_000_000]; @@ -588,6 +682,7 @@ public CSymbol ScanLiteralString() goto SkipChar; default: + // Sync with ScanStringLiteral. if (Char.IsDigit(ch)) { // Octal character code. @@ -689,7 +784,7 @@ static char LogError(char ch) ///
char ScanNextChar() { - if (ContLength <= _charIndex) + if (_charIndex >= ContLength) { _currChar = _nextChar; // The last character we are now dealing with. _nextChar = Chars.EOF; // Next character is EOF. @@ -702,7 +797,7 @@ char ScanNextChar() { if (_nextChar == Chars.LF) { - // Treat CR LF as LF + // Treat CR LF as LF. _currChar = _nextChar; if (ContLength <= _charIndex) _nextChar = Chars.EOF; @@ -733,7 +828,8 @@ void ClearToken() /// Appends current character to the token and /// reads next byte as a character. ///
- internal char AppendAndScanNextChar() + /*internal*/ + char AppendAndScanNextChar() { _token.Append(_currChar); return ScanNextChar(); @@ -856,7 +952,7 @@ internal static bool IsDelimiter(char ch) /// /// Gets the length of the content. /// - public int ContLength => _content.Length; + public int ContLength { get; } /// /// Gets or sets the position in the content. @@ -866,9 +962,10 @@ public int Position get => _charIndex; set { + Debug.Assert(value >= 0); _charIndex = value; - _currChar = (char)_content[_charIndex - 1]; - _nextChar = (char)_content[_charIndex - 1]; + _currChar = _charIndex < ContLength ? (char)_content[_charIndex] : Chars.EOF; + _nextChar = _charIndex + 1 < ContLength ? (char)_content[_charIndex + 1] : Chars.EOF; } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/enums/Symbol.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/enums/Symbol.cs index 4c615988..4ebbcd10 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/enums/Symbol.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/enums/Symbol.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. namespace PdfSharp.Pdf.Content @@ -23,7 +23,7 @@ public enum CSymbol BeginArray, EndArray, // IMPROVE - // Content dictionary << >> is scanned as string literal. + // Content dictionary << … >> is scanned as string literal. // Scan as an object tree. Dictionary, Eof, diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Filters/ASCII85Decode.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Filters/ASCII85Decode.cs index 27d712d3..92bab0ca 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Filters/ASCII85Decode.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Filters/ASCII85Decode.cs @@ -1,7 +1,9 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -using System; +using Microsoft.Extensions.Logging; +using PdfSharp.Logging; +using PdfSharp.Pdf.IO; namespace PdfSharp.Pdf.Filters { @@ -10,7 +12,14 @@ namespace PdfSharp.Pdf.Filters /// public class Ascii85Decode : Filter { - // Reference: 3.3.2 ASCII85Decode Filter / Page 69 + // Reference 1.7: 3.3.2 ASCII85Decode Filter / Page 69 + // Reference 2.0: 7.4.3 ASCII85Decode filter / Page 37 + // Wikipedia https://en.wikipedia.org/wiki/Ascii85 + // Padding the input data to a multiple of 4 bytes for encoding or + // 5 bytes for decoding respectively is well explained in the Wikipedia article. + // It may not be intuitively utterly clear why it works. + + // Rewritten March 2025. /// /// Encodes the specified data. @@ -20,93 +29,75 @@ public override byte[] Encode(byte[] data) if (data == null) throw new ArgumentNullException(nameof(data)); - int length = data.Length; // length == 0 is must not be treated as a special case. - int words = length / 4; - int rest = length - (words * 4); - byte[] result = new byte[words * 5 + (rest == 0 ? 0 : rest + 1) + 2]; + // Number of bytes in source data. + int sourceLength = data.Length; // length == 0 is not treated as a special case. + + // Number of 4 byte groups. + int words = sourceLength / 4; + + // Number of bytes modulo 4 (final padding group, if any). + int rest = sourceLength - 4 * words; + + // Number of four-byte groups including an optional padding group. + int wordsPadded = words + (rest == 0 ? 0 : 1); + + // If rest != 0, the last block is padded and must not + // be encoded as 'z' in case it is 0. + int lastBlock = rest == 0 ? wordsPadded + 1 : wordsPadded - 1; - int idxIn = 0, idxOut = 0; - int wCount = 0; - while (wCount < words) + // Allocate source bytes including padding. + byte[] source = new byte[4 * wordsPadded]; + Array.Copy(data, source, sourceLength); // 0..3 trailing zeros. + + // Max result length including suffix. + int resultLength = wordsPadded * 5 + 2; + + // Allocate result bytes. + byte[] result = new byte[resultLength]; + + int idxSrc = 0, idxRes = 0; + int wordCount = 0; + while (wordCount < wordsPadded) { - uint val = ((uint)data[idxIn++] << 24) + ((uint)data[idxIn++] << 16) + ((uint)data[idxIn++] << 8) + data[idxIn++]; - if (val == 0) + uint value = ((uint)source[idxSrc++] << 24) + + ((uint)source[idxSrc++] << 16) + + ((uint)source[idxSrc++] << 8) + + source[idxSrc++]; + if (value == 0 && wordCount != lastBlock) { - result[idxOut++] = (byte)'z'; + // Encode 0 as 'z' instead of '!!!!!' + result[idxRes++] = (byte)'z'; } else { - byte c5 = (byte)(val % 85 + '!'); - val /= 85; - byte c4 = (byte)(val % 85 + '!'); - val /= 85; - byte c3 = (byte)(val % 85 + '!'); - val /= 85; - byte c2 = (byte)(val % 85 + '!'); - val /= 85; - byte c1 = (byte)(val + '!'); - - result[idxOut++] = c1; - result[idxOut++] = c2; - result[idxOut++] = c3; - result[idxOut++] = c4; - result[idxOut++] = c5; - } - wCount++; - } - switch (rest) - { - case 1: - { - uint val = (uint)data[idxIn] << 24; - val /= 85 * 85 * 85; - byte c2 = (byte)(val % 85 + '!'); - val /= 85; - byte c1 = (byte)(val + '!'); - - result[idxOut++] = c1; - result[idxOut++] = c2; - break; - } - case 2: - { - uint val = ((uint)data[idxIn++] << 24) + ((uint)data[idxIn] << 16); - val /= 85 * 85; - byte c3 = (byte)(val % 85 + '!'); - val /= 85; - byte c2 = (byte)(val % 85 + '!'); - val /= 85; - byte c1 = (byte)(val + '!'); - - result[idxOut++] = c1; - result[idxOut++] = c2; - result[idxOut++] = c3; - break; - } - case 3: - { - uint val = ((uint)data[idxIn++] << 24) + ((uint)data[idxIn++] << 16) + ((uint)data[idxIn] << 8); - val /= 85; - byte c4 = (byte)(val % 85 + '!'); - val /= 85; - byte c3 = (byte)(val % 85 + '!'); - val /= 85; - byte c2 = (byte)(val % 85 + '!'); - val /= 85; - byte c1 = (byte)(val + '!'); - - result[idxOut++] = c1; - result[idxOut++] = c2; - result[idxOut++] = c3; - result[idxOut++] = c4; - break; + // Convert from radix-256 to radix-85. + byte ch5 = (byte)(value % 85 + '!'); + value /= 85; + byte ch4 = (byte)(value % 85 + '!'); + value /= 85; + byte ch3 = (byte)(value % 85 + '!'); + value /= 85; + byte ch2 = (byte)(value % 85 + '!'); + value /= 85; + byte ch1 = (byte)(value + '!'); + + result[idxRes++] = ch1; + result[idxRes++] = ch2; + result[idxRes++] = ch3; + result[idxRes++] = ch4; + result[idxRes++] = ch5; } + wordCount++; } - result[idxOut++] = (byte)'~'; - result[idxOut++] = (byte)'>'; - if (idxOut < result.Length) - Array.Resize(ref result, idxOut); + // Chop result if rest is not 0. + int effectiveResultLength = idxRes - (rest != 0 ? 4 - rest : 0) + 2; + if (effectiveResultLength < resultLength) + Array.Resize(ref result, effectiveResultLength); + + // Set suffix. + result[^2] = (byte)'~'; + result[^1] = (byte)'>'; return result; } @@ -114,160 +105,170 @@ public override byte[] Encode(byte[] data) /// /// Decodes the specified data. /// - public override byte[] Decode(byte[] data, FilterParms? parms) + public override byte[] Decode(byte[] data, FilterParms? _) { if (data == null) throw new ArgumentNullException(nameof(data)); - int idx; - int length = data.Length; + // Number of bytes in source data. + int sourceLength = data.Length; + + // Allocate max. source bytes including up to 3 'u' digits for padding. + byte[] source = new byte[sourceLength + 3]; + + // Number of z characters. int zCount = 0; - int idxOut = 0; - for (idx = 0; idx < length; idx++) + + // Digit index (0..4) in the 5 digit of the radix-85 number. + int digitIndex = 0; + + // Flag indicating '~' as first character of suffix was parsed. + // A PDFsharp user found a PDF file where '~>' was separated by + // a LF. So take that into account. + bool tilde = false; + + // Analyse, validate, and clean up input data. + int idx; + int idxSrc = 0; + for (idx = 0; idx < sourceLength; idx++) { char ch = (char)data[idx]; + + // According to Wikipedia the string can start with '<~'. + // PDF specs does not mention this case. + if (idx == 0 && sourceLength >= 2) + { + // Here we do not expect any white-space before or between + // '<' and '~'. + if (ch == '<' && (char)data[1] == '~') + { + idx++; + continue; + } + } + + // According to the specs skip white-space. + if (Lexer.IsWhiteSpace(ch)) + continue; + + // Check for start of postfix. + if (tilde) + { + if (ch != '>') + throw new ArgumentException($"'~' followed by illegal character '{ch}'.", nameof(data)); + + // Ensure that idx never gets the value of length. + // Also ignore any characters beyond suffix. + break; + } + if (ch is >= '!' and <= 'u') - data[idxOut++] = (byte)ch; + { + source[idxSrc++] = (byte)ch; + if (++digitIndex == 5) + digitIndex = 0; + } else if (ch == 'z') { - data[idxOut++] = (byte)ch; + if (digitIndex != 0) + throw new ArgumentException($"A 'z' appears illegally within a 5 digit radix-85 number.", nameof(data)); + source[idxSrc++] = (byte)ch; zCount++; } else if (ch == '~') { - if ((char)data[idx + 1] != '>') - throw new ArgumentException("Illegal character.", nameof(data)); - break; + // We cannot expect that the next character is a '>'. + // It can be some white-space. + tilde = true; + } + else + { + // Ignore unknown character, but log an error. + PdfSharpLogHost.PdfReadingLogger.LogError("Illegal char in ASCII85 string: '{ch}'.", ch); } - // ignore unknown character } + // Loop not ended with break? - if (idx == length) + if (idx == sourceLength) throw new ArgumentException("Illegal character.", nameof(data)); - length = idxOut; - int nonZero = length - zCount; - int byteCount = 4 * (zCount + (nonZero / 5)); // full 4 byte blocks + // Effective source length cleaned up by prefix, suffix, and white-space. + sourceLength = idxSrc; - int remainder = nonZero % 5; - if (remainder == 1) - throw new InvalidOperationException("Illegal character."); + // Number of radix-85 digits. + int nonZero = sourceLength - zCount; - if (remainder != 0) - byteCount += remainder - 1; + // Number of decoded bytes in case no padding was needed. + // Full 4 byte blocks. + int resultLength = 4 * (zCount + nonZero / 5); - byte[] output = new byte[byteCount]; + // Can be 2, 3, or 4 single radix-85 digits. + int rest = nonZero % 5; - idxOut = 0; + // The rest cannot be 1 as a result of the padding method. + if (rest == 1) + throw new ArgumentException("The ASCII-85 string has an illegal number of padding characters.", nameof(data)); + + // Number of 'u' digits to be padded for decoding (1, 2, or 3). + int padding = 0; + // It is not intuitively completely clear to me why the padding method works this way, but it does. + if (rest != 0) + { + padding = 5 - rest; // 1, 2, or 3 + resultLength += rest - 1; + + // Append 'u' digits to make length a multiple of 5. + for (idx = 0; idx < padding; idx++) + source[sourceLength++] = (byte)'u'; + } + + Debug.Assert((resultLength + padding) % 4 == 0); + + // Allocate result bytes with padding. + byte[] result = new byte[resultLength + padding]; + + int idxRes = 0; idx = 0; - while (idx + 4 < length) + while (idx + 5 <= sourceLength) { - char ch = (char)data[idx]; + char ch = (char)source[idx]; if (ch == 'z') { + // Add 4 zero bytes. idx++; - idxOut += 4; + idxRes += 4; } else { - // TODO_OLD: check - long value = - (long)(data[idx++] - '!') * (85 * 85 * 85 * 85) + - (uint)(data[idx++] - '!') * (85 * 85 * 85) + - (uint)(data[idx++] - '!') * (85 * 85) + - (uint)(data[idx++] - '!') * 85 + - (uint)(data[idx++] - '!'); + // We already ensured above that there is no 'z' and no white-space in the next 5 radix-85 digits. + // Using '!!!!!' instead of 'z' is not treated as an error. + var value = + (long)(source[idx++] - '!') * (85 * 85 * 85 * 85) + // Interesting: Without parentheses the compiler + (uint)(source[idx++] - '!') * (85 * 85 * 85) + // does not treat the powers of 85 as a constant + (uint)(source[idx++] - '!') * (85 * 85) + // expression, but multiplies all factors + (uint)(source[idx++] - '!') * 85 + // from left to right. + (uint)(source[idx++] - '!'); + // Because 85^5 > 256^4 there can be an overflow in a five digit radix-85 number. if (value > UInt32.MaxValue) - throw new InvalidOperationException("Value of group greater than 2^(32-1)."); - - output[idxOut++] = (byte)(value >> 24); - output[idxOut++] = (byte)(value >> 16); - output[idxOut++] = (byte)(value >> 8); - output[idxOut++] = (byte)value; - } - } - - // I have found no appropriate algorithm, so I write my own. In some rare cases the value must not - // be increased by one, but I cannot found a general formula or a proof. - // All possible cases are tested programmatically. - switch (remainder) - { - case 2: // one byte - { - uint value = - (uint)(data[idx++] - '!') * (85 * 85 * 85 * 85) + - (uint)(data[idx] - '!') * (85 * 85 * 85); - - // Always increase if not zero (tried out). - if (value != 0) - value += 0x01000000; - - output[idxOut] = (byte)(value >> 24); - break; - } - - case 3: // two bytes - { - int idxIn = idx; - uint value = - (uint)(data[idx++] - '!') * (85 * 85 * 85 * 85) + - (uint)(data[idx++] - '!') * (85 * 85 * 85) + - (uint)(data[idx] - '!') * (85 * 85); - - if (value != 0) { - value &= 0xFFFF0000; - uint val = value / (85 * 85); - byte c3 = (byte)(val % 85 + '!'); - val /= 85; - byte c2 = (byte)(val % 85 + '!'); - val /= 85; - byte c1 = (byte)(val + '!'); - if (c1 != data[idxIn] || c2 != data[idxIn + 1] || c3 != data[idxIn + 2]) - { - value += 0x00010000; - //Count2++; - } + // Note that padding cannot lead to an overflow. + // The largest possible value created during padding is 4278608874 / 0xff0663ea + throw new InvalidOperationException("The value of a 5 digit radix-85 number is greater than 2^32 - 1."); } - output[idxOut++] = (byte)(value >> 24); - output[idxOut] = (byte)(value >> 16); - break; - } - case 4: // three bytes - { - int idxIn = idx; - uint value = - (uint)(data[idx++] - '!') * (85 * 85 * 85 * 85) + - (uint)(data[idx++] - '!') * (85 * 85 * 85) + - (uint)(data[idx++] - '!') * (85 * 85) + - (uint)(data[idx] - '!') * 85; - - if (value != 0) - { - value &= 0xFFFFFF00; - uint val = value / 85; - byte c4 = (byte)(val % 85 + '!'); - val /= 85; - byte c3 = (byte)(val % 85 + '!'); - val /= 85; - byte c2 = (byte)(val % 85 + '!'); - val /= 85; - byte c1 = (byte)(val + '!'); - if (c1 != data[idxIn] || c2 != data[idxIn + 1] || c3 != data[idxIn + 2] || c4 != data[idxIn + 3]) - { - value += 0x00000100; - //Count3++; - } - } - output[idxOut++] = (byte)(value >> 24); - output[idxOut++] = (byte)(value >> 16); - output[idxOut] = (byte)(value >> 8); - break; + result[idxRes++] = (byte)(value >> 24); + result[idxRes++] = (byte)(value >> 16); + result[idxRes++] = (byte)(value >> 8); + result[idxRes++] = (byte)value; } } - return output; + + // Chop the padding bytes if rest is not 0. + if (rest != 0) + Array.Resize(ref result, resultLength); + + return result; } } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Filters/Filtering.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Filters/Filtering.cs index 3f76f57e..1f48f8f8 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Filters/Filtering.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Filters/Filtering.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. using PdfSharp.Pdf.Advanced; @@ -276,6 +276,9 @@ public static byte[] Decode(byte[] data, PdfItem filterItem, PdfItem? decodeParm } #endif + if (decodeParms is not null) + PdfReference.Dereference(ref decodeParms); + if (filterItem is PdfName && decodeParms is null or PdfDictionary) { var filter = GetFilter(filterItem.ToString()!); @@ -285,7 +288,7 @@ public static byte[] Decode(byte[] data, PdfItem filterItem, PdfItem? decodeParm else if (filterItem is PdfArray itemArray && decodeParms is null or PdfArray) { var decodeArray = decodeParms as PdfArray; - // Array length of filter and decode parms should match. If they dont, return data unmodified. + // Array length of filter and decode parms should match. If they don’t, return data unmodified. if (decodeArray != null && decodeArray.Elements.Count != itemArray.Elements.Count) return data; for (var i = 0; i < itemArray.Elements.Count; i++) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Lexer.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Lexer.cs index 2f23feba..1822b675 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Lexer.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Lexer.cs @@ -3,7 +3,6 @@ using System.Text; using Microsoft.Extensions.Logging; -using PdfSharp.Internal; using PdfSharp.Logging; using PdfSharp.Pdf.Internal; @@ -26,7 +25,7 @@ public Lexer(Stream pdfInputStream, ILogger? logger) _pdfStream = pdfInputStream; // ReSharper disable once RedundantCast because SizeType can be 32 bit depending on build. _pdfLength = (SizeType)_pdfStream.Length; - _idxChar = 0; + _charIndex = 0; Position = 0; _logger = logger ?? PdfSharpLogHost.PdfReadingLogger; } @@ -45,13 +44,13 @@ public SizeType Position { get { - Debug.Assert(_pdfStream.Position == _idxChar + 2); - return _idxChar; + Debug.Assert(_pdfStream.Position == _charIndex + 2); + return _charIndex; } set { Debug.Assert(value >= 0); - _idxChar = value; + _charIndex = value; _pdfStream.Position = value; // ReadByte return -1 (eof) at the end of the stream. @@ -83,15 +82,15 @@ public Symbol ScanNextToken(bool testForObjectReference) goto TryAgain; case '/': - return Symbol = ScanName(); + return ScanName(); case '+': case '-': // Cannot be an object reference if a sign was found. - return Symbol = ScanNumber(false); + return ScanNumber(false); case '(': - return Symbol = ScanStringLiteral(); + return ScanStringLiteral(); case '[': ScanNextChar(true); @@ -108,7 +107,7 @@ public Symbol ScanNextToken(bool testForObjectReference) ScanNextChar(true); return Symbol = Symbol.BeginDictionary; } - return Symbol = ScanHexadecimalString(); + return ScanHexadecimalString(); case '>': if (_nextChar == '>') @@ -122,19 +121,20 @@ public Symbol ScanNextToken(bool testForObjectReference) goto default; case >= '0' and <= '9': - Symbol = ScanNumber(testForObjectReference); + ScanNumber(testForObjectReference); Debug.Assert(Symbol is Symbol.Integer or Symbol.LongInteger or Symbol.Real or Symbol.ObjRef); return Symbol; case '.': // Cannot be an object reference if a decimal point was found. - Symbol = ScanNumber(false); + ScanNumber(false); Debug.Assert(Symbol == Symbol.Real); return Symbol; case >= 'a' and <= 'z': - return Symbol = ScanKeyword(); + return ScanKeyword(); +#if DEBUG case 'R': Debug.Assert(false, "'R' should not be parsed anymore."); // Note: "case 'R':" is not scanned, because it is only used in an object reference. @@ -142,6 +142,7 @@ public Symbol ScanNextToken(bool testForObjectReference) ScanNextChar(true); // The next line only exists for the 'UseOldCode' case in PdfReader. return Symbol = Symbol.R; +#endif case Chars.EOF: return Symbol = Symbol.Eof; @@ -178,9 +179,13 @@ public Symbol ScanComment() if (ch is Chars.LF or Chars.EOF) break; } - // TODO_OLD: not correct | StLa/24-01-23: Why? + // If someone writes '%%EOF' somewhere in the document this must not be + // interpreted as the end of the PDF file. if (_token.ToString().StartsWith("%%EOF", StringComparison.Ordinal)) - return Symbol.Eof; + { + //return Symbol.Eof; // This is wrong. + _logger.LogError("Unexpected '%%EOF' read."); + } return Symbol = Symbol.Comment; } @@ -252,14 +257,15 @@ static char LogError(char ch) /// Scans a number or an object reference. /// Returns one of the following symbols. /// Symbol.ObjRef if testForObjectReference is true and the pattern "nnn ggg R" can be found. - /// Symbol.Real if a decimal point exists or the number of digits is too large for 64-bit integer. + /// Symbol.Real if a decimal point exists or the number is too large for 64-bit integer. /// Symbol.Integer if the long value is in the range of 32-bit integer. /// Symbol.LongInteger otherwise. /// - public Symbol ScanNumber(bool testForObjectReference) + /*public */ + internal Symbol ScanNumber(bool testForObjectReference) { // We found a PDF file created with Acrobat 7 with this entry - // /Checksum 2996984786 # larger than 2.147.483.648 (2^31) + // /Checksum 2996984786 # larger than 2,147,483,648 (2^31) // // Also got an AutoCAD PDF file that contains // /C 264584027963392 # 15 digits @@ -269,38 +275,48 @@ public Symbol ScanNumber(bool testForObjectReference) // Note: This is a copy of CLexer.ScanNumber with minimal changes. Keep both versions in sync as far as possible. // Update StL: Function is revised for object reference look ahead. + // Parsing Strategy: + // Most real life numbers in PDF files have less than 19 digits. So we try to parse all digits as 64-bit integers + // in the first place. All leading zeros are skipped and not counted. + // If we found a decimal point we later divide the result by the appropriate power of 10 and covert is to Double. + // For edge cases, which are numbers with 19 digits, the token is parsed again with 'Int64.TryParse()' and + // if this fails with 'Double.TryParse'. + // If 'testForObjectReference' is 'true' and the value has up to 7 digits, no decimal point and no sign, + // we look ahead whether it is an object reference having the form '{object-number} {generation-number} R'. const int maxDigitsForObjectNumber = 7; // max: 8_388_608 / 0x_7F_FF_FF const int maxDigitsForGenerationNumber = 5; // max: 65_535 / 0x_FF_FF - const int maxDigitsForLong = 18; - const int maxDecimalDigits = 10; - var value = 0L; - var totalDigits = 0; - var decimalDigits = 0; - var period = false; - var negative = false; + const int maxDigitsForLong = 18; // Up to 18 digits values can safely fit into 64-bit integer. + const int maxDecimalDigits = 10; // Maximum number of decimal digits we process. + var value = 0L; // The 64-bit value we have parsed. + var canBeLeadingZero = true; // True if a '0' is a leading zero and gets skipped. + var leadingZeros = 0; // The number of scanned leading zeros. Used for optional warning. + var totalDigits = 0; // The total number of digits scanned. E.g. is 7 for '123.4567'. + var decimalDigits = 0; // The total number of decimal digits scanned. E.g. is 4 for '123.4567'. + //var allDecimalDigitsAreZero = true; // Not used anymore, because '123.000' is always treated as double, never as integer. + var period = false; // The decimal point '.' was scanned. + var negative = false; // The value is negative and the scanned value is negated. + var ch = _currChar; Debug.Assert(ch is '+' or '-' or '.' or (>= '0' and <= '9')); - // If first char is not a digit, it cannot be an object reference. + // If the first char is not a digit, it cannot be by definition an object reference. if (testForObjectReference && ch is not (>= '0' and <= '9')) testForObjectReference = false; -#if DEBUG_ - var pos = Position; - var neighborhood = GetNeighborhoodOfCurrentPosition(Position); - Console.W/riteLine(neighborhood); -#endif + ClearToken(); if (ch is '+' or '-') { + // 'testForObjectReference == false' is already ensured here. + if (ch == '-') negative = true; _token.Append(ch); ch = ScanNextChar(true); - // Never saw this in any PDF file, but possible. + // Never saw this in any PDF file. if (ch is not ('.' or >= '0' and <= '9')) { - PdfSharpLogHost.Logger.LogError("+/- not followed by a number."); + PdfSharpLogHost.Logger.LogError("+/- not followed by a number or decimal point."); } } @@ -310,83 +326,154 @@ public Symbol ScanNumber(bool testForObjectReference) if (ch is >= '0' and <= '9') { _token.Append(ch); - ++totalDigits; + + if (canBeLeadingZero) + { + if (ch == '0') + { + leadingZeros++; + } + else + { + canBeLeadingZero = false; + ++totalDigits; + } + } + else + { + ++totalDigits; + } + if (decimalDigits < maxDecimalDigits) { // Calculate the value if it still fits into long. + // The value gets later parsed again by .NET if the total number of digits exceeds 18 digits. if (totalDigits <= maxDigitsForLong) value = 10 * value + ch - '0'; } + if (period) + { ++decimalDigits; + // A number with a decimal point is always considered as Symbol.Real, + // even if it fits in Symbol.Integer or Symbol.LongInteger. + // KEEP for documental purposes. + //// E.g. '123.0000' is real, but fits in an integer. + //if (ch is not '0') + // allDecimalDigitsAreZero = false; + } } else if (ch == '.') { + _token.Append(ch); + // More than one period? if (period) - ContentReaderDiagnostics.ThrowContentReaderException("More than one period in number."); + ContentReaderDiagnostics.ThrowContentReaderException("More than one decimal point in number."); period = true; - _token.Append(ch); + canBeLeadingZero = false; } else break; ch = ScanNextChar(true); } +#if true_ // KEEP Maybe we warn in the future about leading zeros outside xref. + // xref has lots of leading zeros. + // Maybe we add a parameter 'warnAboutLeadingZeros', but not yet. + if (leadingZeros > 1) +#pragma warning disable CA2254 // This is a rare case outside xref. Therefor we use string interpolation. + PdfSharpLogHost.PdfReadingLogger.LogWarning($"Token '{_token}' has more than one leading zero."); +#pragma warning restore CA2254 +#endif // Can the scanned number be the first part of an object reference? if (testForObjectReference && period is false - && totalDigits <= maxDigitsForObjectNumber + && totalDigits <= maxDigitsForObjectNumber // Values in range [8_388_609..9_999_999] are checked in PdfObjectID. && IsWhiteSpace(_currChar)) { -#if DEBUG +#if DEBUG_ LexerHelper.TryCheckReferenceCount++; #endif int gen = TryReadReference(); if (gen >= 0) { -#if DEBUG +#if DEBUG_ LexerHelper.TryCheckReferenceSuccessCount++; #endif _tokenAsObjectID = ((int)value, gen); - return Symbol.ObjRef; + return Symbol = Symbol.ObjRef; } } if (totalDigits > maxDigitsForLong || decimalDigits > maxDecimalDigits) { - // The number is too big for long or has too many decimal digits for our own code, + // Case: It is not guarantied that the number fits in a 64-bit integer. + + // It is not integer if there is a period. + if (period is false && totalDigits == maxDigitsForLong + 1) + { + // Case: We have exactly 19 digits and no decimal point, which might fit in a 64-bit integer, + // depending on the value. + // If the 19-digit numbers is + // in the range [1,000,000,000,000,000,000 .. 9,223,372,036,854,775,807] + // or + // in the range [-9,223,372,036,854,775,808 .. -1,000,000,000,000,000,000] + // it is a 64-bit integer. Otherwise, it is not. + // Because this is a super rare case we make life easy and parse the scanned token again by .NET. + if (Int64.TryParse(_token.ToString(), out var result)) + { + _tokenAsLong = result; + _tokenAsReal = result; + return Symbol = Symbol.LongInteger; + } + } + + // Case: The number is too big for long or has too many decimal digits for our own code, // so we provide it as real only. // Number will be parsed by .NET. _tokenAsReal = Double.Parse(_token.ToString(), CultureInfo.InvariantCulture); - return Symbol.Real; + + return Symbol = Symbol.Real; } + // Case: The number is in range [0 .. 999,999,999,999,999,999] and fits into a 64-bit integer. if (negative) - value = -value; + value = -value; // Flipping 64-bit integer sign is safe here. if (period) { + // Case: A number with a period is always considered to be real value. if (decimalDigits > 0) { _tokenAsReal = value / PowersOf10[decimalDigits]; + // KEEP for documental purposes. + //// It is not integer if there is a period. + //if (allDecimalDigitsAreZero) + // _tokenAsLong = (long)_tokenAsReal; } else { _tokenAsReal = value; - _tokenAsLong = value; + // KEEP for documental purposes. + //// It is not integer if there is a period. + // _tokenAsLong = value; } - return Symbol.Real; + return Symbol = Symbol.Real; } _tokenAsLong = value; _tokenAsReal = Double.NaN; Debug.Assert(Int64.Parse(_token.ToString(), CultureInfo.InvariantCulture) == value); - if (value is >= Int32.MinValue and < Int32.MaxValue) - return Symbol.Integer; - return Symbol.LongInteger; + if (value is >= Int32.MinValue and <= Int32.MaxValue) + { + // Case: Fits in the range of a 32-bit integer. + return Symbol = Symbol.Integer; + } + + return Symbol = Symbol.LongInteger; // Try to read generation number followed by an 'R'. // Returns -1 if not an object reference. @@ -396,7 +483,7 @@ int TryReadReference() // A Reference has the form "nnn ggg R". The original implementation of the parser used a // reduce/shift algorithm in the first place. But this case is the only one we need to - // look ahead 3 tokens. + // look ahead 2 tokens. // This is a new implementation that checks whether a scanned integer is followed by // another integer and an 'R'. @@ -441,6 +528,7 @@ int TryReadReference() if (_currChar != 'R') goto NotAReference; + // Eat the 'R'. ScanNextChar(true); return generationNumber; @@ -453,6 +541,7 @@ int TryReadReference() return -1; } } + static readonly double[] PowersOf10 = [1, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000, 100_000_000, 1_000_000_000, 10_000_000_000]; /// @@ -481,7 +570,7 @@ public Symbol ScanKeyword() "null" => Symbol = Symbol.Null, "true" => Symbol = Symbol.Boolean, "false" => Symbol = Symbol.Boolean, - "R" => Symbol = Symbol.R, + "R" => Symbol = Symbol.R, // Not scanned anymore because it is handled in ScanNumber. "stream" => Symbol = Symbol.BeginStream, "endstream" => Symbol = Symbol.EndStream, "xref" => Symbol = Symbol.XRef, @@ -633,6 +722,106 @@ public Symbol ScanStringLiteral() return Symbol = Symbol.String; } +#if true + /// + /// Scans a hex encoded literal byte string, contained between "<" and ">". + /// + public Symbol ScanHexadecimalString() + { + Debug.Assert(_currChar == Chars.Less); + + // 25-09-16/StL + // Now we can handle Panose style codes that may look like this: + // < 0 0 2 b 6 6 3 8 4 2 2 4> + // This is technically an illegal format, but found by a user. + + ClearToken(); + ScanNextChar(true); + bool tryUsePanoseHack = false; + while (true) + { + MoveToNonWhiteSpace(); + + if (_currChar == '>') + { + ScanNextChar(true); + break; + } + + // TODO Handle EOF correctly. Check if other methods must also handle EOF. + + var hex = _currChar switch + { + >= '0' and <= '9' => _currChar - '0', + >= 'A' and <= 'F' => _currChar - ('A' - 10), // Not optimized in IL without parenthesis. + >= 'a' and <= 'f' => _currChar - ('a' - 10), + _ => LogError(_currChar) + }; + + ScanNextChar(true); + + // Does the string ends before the 2nd hex value? + if (_currChar == '>') + { + if (tryUsePanoseHack) + { + // Consider this: + // "< 0 0 2 b 6 6 3 8 4 2 2 4>" + // Ensure that the last "4" does not become a "40" but a "04". + + // Is it presumably a 12 byte Panose style code? + if (_token.Length == 11) + { + _token.Append((char)hex); + goto ScanNextChar; + } + } + // Second char is assumed to be '0' if not exists according to the PDF specs. + _token.Append((char)(hex << 4)); + + ScanNextChar: + ScanNextChar(true); + break; + } + + if (_currChar == ' ') // Explicitly not: "if (Lexer.IsDelimiter(_currChar))" + { + // Obviously a single hex character. + // Can occur for Panose style codes. + tryUsePanoseHack = true; + + _token.Append((char)hex); + + // Go on with next byte. + MoveToNonWhiteSpace(); + continue; + } + + // Some fool may add a line-break between the hex digits. + MoveToNonWhiteSpace(); + + // TODO Handle EOF correctly. + + hex = (hex << 4) + _currChar switch + { + >= '0' and <= '9' => _currChar - '0', + >= 'A' and <= 'F' => _currChar - ('A' - 10), + >= 'a' and <= 'f' => _currChar - ('a' - 10), + _ => LogError(_currChar) + }; + _token.Append((char)hex); + ScanNextChar(true); + } + return Symbol = Symbol.HexString; + + char LogError(char ch) + { + PdfSharpLogHost.Logger.LogError("Illegal character {char} in hex string.", ch); + DumpNeighborhoodOfPosition( /*SizeType position = -1, bool hex = false, int range = 25*/); + return '\0'; + } + } +#else /// /// Scans a hex encoded literal string, contained between "<" and ">". /// @@ -687,6 +876,7 @@ static char LogError(char ch) return '\0'; } } +#endif /// /// Tries to scan the specified literal from the current stream position. @@ -708,33 +898,10 @@ public bool TryScanLiterally(string literal) return true; } - ///// - ///// Tries to scan "\n", "\r" or "\r\n" and moves the Position to the next line. - ///// - //public bool TryScanEndOfLine() => TryScanEndOfLine(true, true, true); - - ///// - ///// Tries to scan the accepted end-of-line markers and moves the Position to the next line. - ///// - //public bool TryScanEndOfLine(bool acceptCR, bool acceptLF, bool acceptCRLF) - //{ - // if (acceptCRLF && _currChar == Chars.CR && _nextChar == Chars.LF) - // { - // Position += 2; - // return true; - // } - // if (acceptCR && _currChar == Chars.CR || acceptLF && _currChar == Chars.LF) - // { - // Position += 1; - // return true; - // } - // return false; - //} - /// /// Return the exact position where the content of the stream starts. /// The logical position is also set to this value when the function returns.
- /// Reference: 3.2.7 Stream Objects / Page 60 + /// Reference: 3.2.7 Stream Objects / Page 60
/// Reference 2.0: 7.3.8 Stream objects / Page 31 ///
public SizeType FindStreamStartPosition(PdfObjectID id) @@ -817,7 +984,7 @@ public byte[] ScanStream(SizeType position, int length, out int bytesRead) if (!ReadWholeStreamSequence(_pdfStream, length, out var bytes, out bytesRead)) { // EOF reached, so return what was read. - _logger.EndOfStreamReached(length,position,bytesRead); + _logger.EndOfStreamReached(length, position, bytesRead); Position = position + bytesRead; return bytes; @@ -853,7 +1020,7 @@ static bool ReadWholeStreamSequence(Stream stream, int length, out byte[] conten // use a MemoryStream to cache the original stream if necessary. // However, without this workaround the file would be regarded as corrupt instead of the stream not being compatible. do - { + { // Log error only for retries. ConditionalLogOnRetry(bytesRead, "Stream.Read did not return the whole requested sequence. As a workaround, reading the missing bytes is tried again."); @@ -954,18 +1121,18 @@ public string ScanRawString(SizeType position, int length) /// return it as a character with high byte always zero. ///
// ReSharper disable once InconsistentNaming - internal char ScanNextChar(bool handleCRLF) // ScanNextByteAsChar + internal char ScanNextChar(bool handleCRLF) { - if (_idxChar >= _pdfLength) + if (_charIndex >= _pdfLength) { - _currChar = Chars.EOF; - _nextChar = Chars.EOF; + _currChar = _nextChar; // The last character we are now dealing with. + _nextChar = Chars.EOF; // Next character is EOF. } else { _currChar = _nextChar; _nextChar = (char)_pdfStream.ReadByte(); - _idxChar++; + _charIndex++; if (handleCRLF && _currChar == Chars.CR) { if (_nextChar == Chars.LF) @@ -973,7 +1140,7 @@ internal char ScanNextChar(bool handleCRLF) // ScanNextByteAsChar // Treat CR LF as LF. _currChar = _nextChar; _nextChar = (char)_pdfStream.ReadByte(); - _idxChar++; + _charIndex++; } else { @@ -1154,8 +1321,21 @@ public int TokenToInteger { get { - Debug.Assert(_tokenAsLong == Int32.Parse(_token.ToString(), CultureInfo.InvariantCulture)); - return (int)_tokenAsLong; + return Symbol switch + { + Symbol.Integer => (int)_tokenAsLong, + + // Should always fail, because if token fits into integer the symbol type would not be LongInteger. + Symbol.LongInteger => _tokenAsLong is >= Int32.MinValue and <= Int32.MaxValue ? + (int)_tokenAsLong : Throw(), + + // All other types fail. + //Symbol.Real => 42, + //Symbol.ObjRef => 42, + _ => throw new InvalidOperationException("Symbol type is not 'Integer'.") + }; + + static int Throw() => throw new InvalidOperationException("64-bit value too large for 32-bit value."); } } @@ -1164,11 +1344,12 @@ public int TokenToInteger ///
public long TokenToLongInteger { - get + get => Symbol switch { - Debug.Assert(_tokenAsLong == Int64.Parse(_token.ToString(), CultureInfo.InvariantCulture)); - return _tokenAsLong; - } + Symbol.Integer => _tokenAsLong, + Symbol.LongInteger => _tokenAsLong, + _ => throw new InvalidOperationException("Symbol type is not 'Integer' or 'LongInteger'.") + }; } /// @@ -1207,6 +1388,7 @@ internal static bool IsWhiteSpace(char ch) { return ch switch { + // Reference 2.0: 7.1 Table 1 — White-space characters / Page 22 Chars.NUL => true, // 0 Null Chars.HT => true, // 9 Horizontal Tab Chars.LF => true, // 10 Line Feed @@ -1222,18 +1404,19 @@ internal static bool IsWhiteSpace(char ch) /// internal static bool IsDelimiter(char ch) { + // Reference 2.0: 7.1 Table 2 — Delimiter characters / Page 23 return ch switch { - '(' => true, - ')' => true, - '<' => true, - '>' => true, - '[' => true, - ']' => true, - '{' => true, - '}' => true, - '/' => true, - '%' => true, + '(' => true, // PDF string delimiter + ')' => true, // " + '<' => true, // PDF dictionary delimiter + '>' => true, // " + '[' => true, // PDF array delimiter + ']' => true, // " + '{' => true, // Type 4 PostScript calculator functions + '}' => true, // " + '/' => true, // PDF names delimiter + '%' => true, // PDF comments delimiter _ => false }; } @@ -1243,7 +1426,7 @@ internal static bool IsDelimiter(char ch) ///
public SizeType PdfLength => _pdfLength; readonly SizeType _pdfLength; - SizeType _idxChar; + SizeType _charIndex; char _currChar; char _nextChar; readonly StringBuilder _token = new(); @@ -1251,10 +1434,10 @@ internal static bool IsDelimiter(char ch) double _tokenAsReal; (int, int) _tokenAsObjectID; readonly Stream _pdfStream; - ILogger _logger; + readonly ILogger _logger; } -#if DEBUG +#if DEBUG_ public class LexerHelper { // Give me an idea of the try/success ratio. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Parser.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Parser.cs index 4b063b29..b14f93c0 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Parser.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Parser.cs @@ -362,8 +362,8 @@ void ReadDictionaryStream(PdfDictionary dict, SuppressExceptions? suppressObject int streamLength = GetStreamLength(dict, suppressObjectOrderExceptions); if (SuppressExceptions.HasError(suppressObjectOrderExceptions)) return; -//#warning THHO4STLA What to do if startPosition + streamLength is larger than length of stream? => Better not show "Please send us your PDF file" but another error message. -// TODO_OLD THHO4STLA What to do if startPosition + streamLength is larger than length of stream? => Better not show "Please send us your PDF file" but another error message. + //#warning THHO4STLA What to do if startPosition + streamLength is larger than length of stream? => Better not show "Please send us your PDF file" but another error message. + // TODO_OLD THHO4STLA What to do if startPosition + streamLength is larger than length of stream? => Better not show "Please send us your PDF file" but another error message. int retryCount = 0; RetryReadStream: // Step 3: We try to read the stream content. @@ -400,7 +400,7 @@ void ReadDictionaryStream(PdfDictionary dict, SuppressExceptions? suppressObject { throw new InvalidOperationException( "Should not happen. Correcting stream length failed twice. There may be a bug in DetermineStreamLength. " + - "Please send us your PDF file so that we can fix this (issues (at) pdfsharp.net)."); + $"If you think this is a bug in PDFsharp, please visit {UrlLiterals.LinkToCannotOpenPdfFile} for further information."); } retryCount++; _lexer.Position = startPosition; @@ -494,7 +494,7 @@ int GetStreamLength(PdfDictionary dict, SuppressExceptions? suppressObjectOrderE PdfSharpLogHost.Logger.LogError("Object '{Object}' has no valid /Length entry. Try to determine stream length by looking for 'endstream'.", dict.ObjectID.ToString()); #if TEST_CODE_ - TestStreamWithoutLengthEntry: + TestStreamWithoutLengthEntry: #endif // Try to determine an upper limit of the stream length. var behindPosition = _document.IrefTable.GetPositionOfObjectBehind(dict, _lexer.Position); @@ -707,10 +707,11 @@ List ParseObject(Symbol stopSymbol) items.Add(new PdfName(_lexer.Token)); break; +#if DEBUG case Symbol.R: - //Debug.Assert(_options.UseOldCode == true, "Must not come here anymore"); Debug.Assert(false, "Must not come here anymore"); break; +#endif case Symbol.ObjRef: { @@ -726,7 +727,7 @@ List ParseObject(Symbol stopSymbol) { // XRefTable not complete when trailer is read. Create temporary irefs that are // removed later in PdfTrailer.Finish(). - iref = new PdfReference(objectID, 0); + iref = PdfReference.CreateForObjectID(objectID, 0); items.Add(iref); } else @@ -1043,7 +1044,7 @@ PdfObject ReadIndirectObjectFromObjectStreamInternal(PdfObjectID objectID, Suppr throw TH.PdfReaderException_ObjectCouldNotBeFoundInObjectStreams(); #endif } - + /// /// Reads the PdfObjects of all known references, no matter if they are saved at document level or inside an ObjectStream. /// @@ -1054,10 +1055,6 @@ internal void ReadAllIndirectObjects() { if (pdfReference.Value == null!) { -#if DEBUG_ - if (pdfReference.ObjectNumber == 25) - _ = typeof(int); -#endif var pdfObject = ReadIndirectObject(pdfReference, null); Debug.Assert(pdfObject.Reference == pdfReference); @@ -1153,25 +1150,46 @@ internal void ReadAllObjectStreamsAndTheirReferences() // ObjectStream could not be loaded. Maybe its stream length is saved in an ObjectStream not yet loaded. Try it again in the next round. nextObjectStreamIDsToLoad.Add(objectStreamID); - PdfSharpLogHost.PdfReadingLogger.LogWarning($"Loading ObjectStream with ID {objectStreamID} will be retried."); + PdfSharpLogHost.PdfReadingLogger.LogWarning("Loading ObjectStream with ID {objectStreamID} will be retried.", objectStreamID); // Read next ObjectStream. continue; } // Create the parser for the object stream. - var objectStreamParser = new Parser(_document, new MemoryStream(objectStream.Stream.Value), _documentParser); + var objectStreamParser = new Parser(_document, new MemoryStream(objectStream.Stream.UnfilteredValue), _documentParser); + + // Get all ObjectIDs and offsets of objects residing in the object stream. + var objectIDsWithOffset = objectStream.ReadObjectIDsWithOffsets(); - // Read and add all References to objects residing in the object stream and get all ObjectIDs and offsets . - var objectIDsWithOffset = objectStream.ReadReferencesAndOffsets(_document.IrefTable); - // Save all ObjectIDs with the parser of its ObjectStream and its offset. foreach (var objectIDWithOffset in objectIDsWithOffset) { var objectID = objectIDWithOffset.Key; var offset = objectIDWithOffset.Value; - _objectStreamObjectSources.Add(objectID, (objectStreamParser, offset)); + // PDFsharp reads objects from high addresses down to low addresses. + // Thus, the newest object should be read first. + // For duplicate IDs, we keep the first object and ignore objects read later. + if (!_objectStreamObjectSources.TryGetValue(objectID, out _)) + { + // Add object with new objectID. + _objectStreamObjectSources.Add(objectID, (objectStreamParser, offset)); + + // Create and add reference to the object if not existing yet. + if (!_document.IrefTable.Contains(objectID)) + { + // -1 indicates compressed object. + var iref = PdfReference.CreateForObjectID(objectID, -1); + + _document.IrefTable.Add(iref); + } + } + else + { + // Ignore object with objectID already on the list. + PdfSharpLogHost.PdfReadingLogger.LogWarning("Ignoring object with ID {objectID} because an object with that ID was already read.", objectID); + } } } @@ -1231,7 +1249,7 @@ internal void ReadAllObjectStreamsAndTheirReferences() continue; } - var objectStreamParser = new Parser(_document, new MemoryStream(objectStream.Stream.Value), _documentParser); + var objectStreamParser = new Parser(_document, new MemoryStream(objectStream.Stream.UnfilteredValue), _documentParser); _objectStreamsWithParsers.Add(objectStreamID, (objectStream, objectStreamParser)); // Read and add all References to objects residing in the object stream. @@ -1323,7 +1341,7 @@ internal PdfTrailer ReadTrailer() // Implementation note 18 Appendix H: // Acrobat viewers require only that the %%EOF marker appear somewhere within the last 1024 bytes of the file. int idx; - if (length < 1030) + if (length <= 1030) { // Reading the final 30 bytes should work for all files. But often it does not. string trail = _lexer.ScanRawString(length - 31, 30); //lexer.Pdf.Substring(length - 30); @@ -1424,7 +1442,8 @@ internal PdfTrailer ReadTrailer() continue; int idToUse = id; -#if true // The following issue in PDF files is rare, but must be fixed here to prevent PdfReference with wrong IDs. +#if true + // The following issue in PDF files is rare, but must be fixed here to prevent PdfReference with wrong IDs. // We found PDF files where the ID of the referenced object was misaligned by one relative to // its number from the xref table. // Check if the object at the address has the correct ID and generation. @@ -1454,7 +1473,9 @@ internal PdfTrailer ReadTrailer() // Ignore the latter one. if (xrefTable.Contains(objectID)) continue; - xrefTable.Add(new PdfReference(objectID, position)); + + var iref = PdfReference.CreateForObjectID(objectID, position); + xrefTable.Add(iref); } } else if (symbol == Symbol.Trailer) @@ -1569,12 +1590,7 @@ PdfTrailer ReadXRefStream(PdfCrossReferenceTable xrefTable) // Usually, the cross-reference stream and its reference have not been read yet. if (!xrefTable.Contains(objectID)) { - var iref = new PdfReference(xrefStream) - { - ObjectID = objectID, - Value = xrefStream, - Position = xrefStart - }; + var iref = PdfReference.CreateFromObject(xrefStream, objectID, xrefStart); xrefTable.Add(iref); } // If a cross-reference stream B is referenced in the /Prev key of another cross-reference stream A dictionary, @@ -1590,7 +1606,7 @@ PdfTrailer ReadXRefStream(PdfCrossReferenceTable xrefTable) if (oldIref.Position != xrefStart) { PdfSharpLogHost.PdfReadingLogger.LogError("Object '{ObjectID}' already exists in xref table’s references, referring to position {Position}. The latter one referring to position {Position} is used. " + - "This should not occur. If somebody came here, please send us your PDF file so that we can fix it (issues (at) pdfsharp.net.", oldIref.ObjectID, oldIref.Position, xrefStart); + $"This should not occur. If you think this is a bug in PDFsharp, please visit {UrlLiterals.LinkToCannotOpenPdfFile} for further information.", oldIref.ObjectID, oldIref.Position, xrefStart); oldIref.Position = xrefStart; } @@ -1710,12 +1726,13 @@ PdfTrailer ReadXRefStream(PdfCrossReferenceTable xrefTable) _ = typeof(int); #endif Debug.Assert(objectID.GenerationNumber == item.Field3); - + // Ignore the latter one. if (!xrefTable.Contains(objectID)) { // Add iref for all uncompressed objects. - xrefTable.Add(new PdfReference(objectID, position)); + var iref = PdfReference.CreateForObjectID(objectID, position); + xrefTable.Add(iref); } #if DEBUG_ else diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReader.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReader.cs index 26688b16..f9b9f6fc 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReader.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReader.cs @@ -398,7 +398,7 @@ PdfDocument OpenFromStream(Stream stream, string? password, PdfDocumentOpenMode // 7. Replace all document’s placeholder references by references knowing their objects. // Placeholder references are used, when reading indirect objects referring objects stored in object streams before reading and decoding them. - FinishReferences(); + FinalizeReferences(); RereadUnicodeStrings(); @@ -449,113 +449,66 @@ PdfDocument OpenFromStream(Stream stream, string? password, PdfDocumentOpenMode return _document; } - void FinishReferences() + /// + /// Ensures that all references in all objects refer to the actual object or to the null object (see ShouldUpdateReference method). + /// + void FinalizeReferences() { Debug.Assert(_document.IrefTable.IsUnderConstruction); - var finishedObjects = new HashSet(); - foreach (var iref in _document.IrefTable.AllReferences) { - Debug.Assert(iref.Value != null, - "All references saved in IrefTable should have been created when their referred PdfObject has been accessible."); + var pdfObject = iref.Value; - // Get and update object’s references. - FinishItemReferences(iref.Value, _document, finishedObjects); - } - - _document.IrefTable.IsUnderConstruction = false; - - // Fix references of trailer values and then objects and irefs are consistent. - _document.Trailer.Finish(); - } - - void FinishItemReferences(PdfItem? pdfItem, PdfDocument document, HashSet finishedObjects) - { - // Only PdfObjects may contain further PdfReferences. - if (pdfItem is not PdfObject pdfObject) - return; -#if true - // Try to add object to finished objects. - // Return, if this object was already processed. - if (!finishedObjects.Add(pdfObject)) - return; -#else - // Return, if this object is already processed. - if (finishedObjects.Contains(pdfObject)) - return; - - // Mark object as processed. - finishedObjects.Add(pdfObject); -#endif + Debug.Assert(pdfObject != null, + "All references saved in IrefTable should have been created when their referred PdfObject has been accessible."); -#if true - // For PdfDictionary and PdfArray, get and update child references. - switch (pdfObject) - { - case PdfDictionary childDictionary: - FinishChildReferences(childDictionary, finishedObjects); - break; - case PdfArray childArray: - FinishChildReferences(childArray, finishedObjects); - break; - } -#else - // For PdfDictionary and PdfArray, get and update child references. - if (pdfObject is PdfDictionary childDictionary) - FinishChildReferences(childDictionary, document, finishedObjects); - if (pdfObject is PdfArray childArray) - FinishChildReferences(childArray, document, finishedObjects); -#endif - } + // Update all references to PdfDictionary’s and PdfArray’s child objects. + switch (pdfObject) + { + case PdfDictionary dictionary: + // Dictionary elements are modified inside the loop. Avoid "Collection was modified; enumeration operation may not execute" error occuring in net 4.6.2. + // There is no way to access KeyValuePairs via index natively to use a for loop with. + // Instead, enumerate Keys and get value via Elements[key], which should be O(1). + foreach (var key in dictionary.Elements.Keys) + { + var item = dictionary.Elements[key]; - void FinishChildReferences(PdfDictionary dictionary, HashSet finishedObjects) - { - // Dictionary elements are modified inside loop. Avoid "Collection was modified; enumeration operation may not execute" error occuring in net 4.6.2. - // There is no way to access KeyValuePairs via index natively to use a for loop with. - // Instead, enumerate Keys and get value via Elements[key], which shall be O(1). - foreach (var key in dictionary.Elements.Keys) - { - var item = dictionary.Elements[key]; + // Replace each reference with its final item, if necessary. + if (item is PdfReference currentReference && ShouldUpdateReference(currentReference, out var finalItem)) + dictionary.Elements[key] = finalItem; + } + break; + case PdfArray array: + var elements = array.Elements; + for (var i = 0; i < elements.Count; i++) + { + var item = elements[i]; - // For PdfReference: Update reference, if necessary, and continue with referred item. - if (item is PdfReference iref) - { - if (FinishReference(iref, out var newIref, out var value)) - dictionary.Elements[key] = newIref; - item = value; + // Replace each reference with its final item, if necessary. + if (item is PdfReference currentReference && ShouldUpdateReference(currentReference, out var finalItem)) + elements[i] = finalItem; + } + break; } - - // Get and update item’s references. - FinishItemReferences(item, _document, finishedObjects); } - } - void FinishChildReferences(PdfArray array, HashSet finishedObjects) - { - var elements = array.Elements; - for (var i = 0; i < elements.Count; i++) - { - var item = elements[i]; - - // For PdfReference: Update reference, if necessary, and continue with referred item. - if (item is PdfReference iref) - { - if (FinishReference(iref, out var newIref, out var value)) - elements[i] = newIref; - item = value; - } + _document.IrefTable.IsUnderConstruction = false; - // Get and update item’s references. - FinishItemReferences(item, _document, finishedObjects); - } + // Fix references of trailer values and then objects and irefs are consistent. + _document.Trailer.Finish(); } - bool FinishReference(PdfReference currentReference, out PdfItem actualReference, out PdfItem value) + /// + /// Gets the final PdfItem that shall perhaps replace currentReference. It will be outputted in finalItem. + /// + /// True, if finalItem has changes compared to currentReference. + bool ShouldUpdateReference(PdfReference currentReference, out PdfItem finalItem) { var isChanged = false; PdfItem? reference = currentReference; + // Step 1: // The value of the reference may be null. // If a file level PdfObject refers object stream level PdfObjects, that were not yet decompressed when reading it, // placeholder references are used. @@ -565,32 +518,22 @@ bool FinishReference(PdfReference currentReference, out PdfItem actualReference, var newIref = _document.IrefTable[currentReference.ObjectID]; reference = newIref; isChanged = true; + // reference may be null. Don’t return yet. } + // Step: 2 // PDF Reference 2.0 section 7.3.10: // An indirect reference to an undefined object shall not be considered an error by a PDF processor; // it shall be treated as a reference to the null object. - if (reference is PdfReference { Value: null }) + // Addition: A reference replaced with null in step 1, as no reference for the object ID has been found in _document.IrefTable, + // is also considered as a reference to an undefined object here. + if (reference is PdfReference { Value: null } or null) { reference = PdfNull.Value; isChanged = true; } - if (reference == null) - { - reference = PdfNull.Value; - isChanged = true; - } - - actualReference = reference; - - if (!isChanged) - value = currentReference.Value; - else if (actualReference is PdfReference r) - value = r.Value; - else - value = PdfNull.Value; - + finalItem = reference; return isChanged; } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs index e6b5ab0b..cd70d0e6 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs @@ -19,9 +19,8 @@ public PdfWriter(Stream pdfStream, PdfDocument document, PdfStandardSecurityHand _stream = pdfStream ?? throw new ArgumentNullException(nameof(pdfStream)); _document = document ?? throw new ArgumentNullException(nameof(document)); EffectiveSecurityHandler = effectiveSecurityHandler; -#if DEBUG - Layout = PdfWriterLayout.Verbose; -#endif + + Layout = document.Options.Layout; } public void Close(bool closeUnderlyingStream) @@ -40,6 +39,14 @@ public void Close(bool closeUnderlyingStream) ///
public PdfWriterLayout Layout { get; set; } + internal bool IsCompactLayout => Layout == PdfWriterLayout.Compact; + + internal bool IsStandardLayout => Layout >= PdfWriterLayout.Standard; + + internal bool IsIndentedLayout => Layout >= PdfWriterLayout.Indented; + + internal bool IsVerboseLayout => Layout >= PdfWriterLayout.Verbose; + public PdfWriterOptions Options { get; set; } // ----------------------------------------------------------- @@ -102,17 +109,18 @@ public void Write(PdfInteger value) WriteRaw(value.Value.ToString(CultureInfo.InvariantCulture)); } - /// - /// Writes the specified value to the PDF stream. - /// -#pragma warning disable CS0618 // Type or member is obsolete - public void Write(PdfUInteger value) -#pragma warning restore CS0618 // Type or member is obsolete - { - WriteSeparator(CharCat.Character); - _lastCat = CharCat.Character; - WriteRaw(value.Value.ToString(CultureInfo.InvariantCulture)); - } + // DELETE + //// /// + //// /// Writes the specified value to the PDF stream. + //// /// + ////#pragma warning disable CS0618 // Type or member is obsolete + //// public void Write(PdfUInteger value) + ////#pragma warning restore CS0618 // Type or member is obsolete + //// { + //// WriteSeparator(CharCat.Character); + //// _lastCat = CharCat.Character; + //// WriteRaw(value.Value.ToString(CultureInfo.InvariantCulture)); + //// } /// /// Writes the specified value to the PDF stream. @@ -225,12 +233,12 @@ public void Write(PdfName value) // in any natural language, subject to the implementation limit on the length of a // name. - WriteSeparator(CharCat.Delimiter/*, '/'*/); + WriteSeparator(CharCat.Delimiter); string name = value.Value; Debug.Assert(name[0] == '/'); - // Encode to raw UTF-8 is any char is larger than 126. - // 127 [DEL] is not a valid value and is also get encoded. + // Encode to raw UTF-8 if any char is larger than 126. + // 127 [DEL] is not a valid value and is also encoded. for (int idx = 1; idx < name.Length; idx++) { char ch = name[idx]; @@ -264,6 +272,8 @@ public void Write(PdfName value) case ')': case '[': case ']': + case '{': + case '}': case '#': break; @@ -285,9 +295,12 @@ public void Write(PdfName value) public void Write(PdfLiteral value) { - WriteSeparator(CharCat.Character); - WriteRaw(value.Value); - _lastCat = CharCat.Character; + var rawString = value.Value; + var first = rawString[0]; + var last = rawString[^1]; + WriteSeparator(GetCategory(first)); + WriteRaw(rawString); + _lastCat = GetCategory(last); } public void Write(PdfRectangle rect) @@ -344,38 +357,115 @@ public void WriteDocStringHex(string text) /// public void WriteBeginObject(PdfObject obj) { - bool indirect = obj.IsIndirect; - if (indirect) + bool isIndirect = obj.IsIndirect; + if (isIndirect) { WriteObjectAddress(obj); - EffectiveSecurityHandler?.EnterObject(obj.ObjectID); } _stack.Add(new StackItem(obj)); - if (indirect) + + string? suffix = null; + if (IsVerboseLayout && _stack.Count > 1) + suffix = GetTypeAndComment(obj); + + if (isIndirect) { if (obj is PdfArray) - WriteRaw("[\n"); + { + if (IsCompactLayout) + { + WriteRaw('['); + } + else + { + if (suffix != null) + WriteRaw("[" + suffix); + else + WriteRaw("[\n"); + + } + } else if (obj is PdfDictionary) - WriteRaw("<<\n"); + { + if (IsCompactLayout) + { + WriteRaw("<<"); + } + else + { + if (suffix != null) + WriteRaw("<<" + suffix); + else + WriteRaw("<<\n"); + } + } + else + { + // Case: PdfIntegerObject or PdfNullObject + + //Debug.Assert(false, "Should not come here."); + Debug.Assert(obj is not null, "Should not come here."); + } _lastCat = CharCat.NewLine; } else { if (obj is PdfArray) { +#if true_ + // Same as PdfDictionary + NewLine(); WriteSeparator(CharCat.Delimiter); - WriteRaw('['); - _lastCat = CharCat.Delimiter; + WriteRaw("[\n"); + _lastCat = CharCat.NewLine; +#else + if (IsCompactLayout) + { + WriteRaw('['); + } + else + { + //NewLine(); + //WriteSeparator(CharCat.Delimiter); + if (suffix != null) + { + WriteRaw("[ " + GetTypeAndComment(obj)); + _lastCat = CharCat.NewLine; + } + else + { + WriteRaw('['); + _lastCat = CharCat.Delimiter; + } + } +#endif } else if (obj is PdfDictionary) { - NewLine(); - WriteSeparator(CharCat.Delimiter); - WriteRaw("<<\n"); - _lastCat = CharCat.NewLine; + if (IsCompactLayout) + { + WriteRaw("<<"); + } + else + { + NewLine(); + WriteSeparator(CharCat.Delimiter); + if (suffix != null) + WriteRaw("<< " + GetTypeAndComment(obj)); + else + WriteRaw("<<\n"); + _lastCat = CharCat.NewLine; + } + } + else + { + // Case: PdfIntegerObject or PdfNullObject + + //Debug.Assert(false, "Should not come here."); + Debug.Assert(obj is not null, "Should not come here."); } } - if (Layout == PdfWriterLayout.Verbose) + if (IsVerboseLayout) IncreaseIndent(); } @@ -384,6 +474,8 @@ public void WriteBeginObject(PdfObject obj) ///
public void WriteEndObject() { + bool noLayout = Layout == PdfWriterLayout.Compact; + int count = _stack.Count; Debug.Assert(count > 0, "PdfWriter stack underflow."); @@ -392,72 +484,140 @@ public void WriteEndObject() PdfObject value = stackItem.Object; var indirect = value.IsIndirect; - if (indirect) - EffectiveSecurityHandler?.LeaveObject(); - if (Layout == PdfWriterLayout.Verbose) + + if (IsVerboseLayout) DecreaseIndent(); + if (value is PdfArray) { if (indirect) { - WriteRaw("\n]\n"); - _lastCat = CharCat.NewLine; + if (IsCompactLayout) + { + WriteRaw("]\n"); + _lastCat = CharCat.NewLine; + } + else + { + + WriteRaw("\n]\n"); + _lastCat = CharCat.Delimiter; + } } else { - WriteRaw("]"); - _lastCat = CharCat.Delimiter; + if (IsCompactLayout) + { + WriteRaw("]"); + _lastCat = CharCat.Delimiter; + } + else + { + //WriteSeparator(CharCat.NewLine); + WriteRaw("]"); + _lastCat = CharCat.Delimiter; + } } } else if (value is PdfDictionary) { if (indirect) { - if (!stackItem.HasStream) - WriteRaw(_lastCat == CharCat.NewLine ? ">>\n" : " >>\n"); + if (IsCompactLayout) + { + if (!stackItem.HasStream) + WriteRaw(">>\n"); + _lastCat = CharCat.NewLine; + } + else + { + if (!stackItem.HasStream) + WriteRaw(">>\n"); + _lastCat = CharCat.NewLine; + } } else { Debug.Assert(!stackItem.HasStream, "Direct object with stream??"); - WriteSeparator(CharCat.NewLine); - WriteRaw(">>\n"); - _lastCat = CharCat.NewLine; + if (IsCompactLayout) + { + WriteSeparator(CharCat.NewLine); + WriteRaw(">>"); + _lastCat = CharCat.Delimiter; + } + else + { + WriteSeparator(CharCat.NewLine); + if (IsVerboseLayout) + { + WriteRaw(">>\n"); + _lastCat = CharCat.NewLine; + } + else + { + WriteRaw(">>"); + _lastCat = CharCat.Delimiter; + } + } } } if (indirect) { - NewLine(); - WriteRaw("endobj\n"); - if (Layout == PdfWriterLayout.Verbose) - WriteRaw("%--------------------------------------------------------------------------------------------------\n"); + if (IsCompactLayout) + { + NewLine(); + WriteRaw("endobj\n"); + } + else + { + NewLine(); + WriteRaw("endobj\n"); + if (IsVerboseLayout) + WriteRaw("%--------------------------------------------------------------------------------------------------\n"); + } } } /// /// Writes the stream of the specified dictionary. /// - public void WriteStream(PdfDictionary value, bool omitStream) + public void WriteStream(PdfDictionary dict, bool omitStream) { var stackItem = _stack[^1]; Debug.Assert(stackItem.Object is PdfDictionary); Debug.Assert(stackItem.Object.IsIndirect); stackItem.HasStream = true; - WriteRaw(_lastCat == CharCat.NewLine ? ">>\nstream\n" : " >>\nstream\n"); - - if (omitStream) + var bytes = dict.Stream!.Value; + if (IsCompactLayout) { - WriteRaw(" «…stream content omitted…»\n"); // useful for debugging only + WriteRaw(">>\nstream\n"); + + // Earlier versions of PDFsharp skipped the '\n' before 'endstream' if the last byte of + // the stream is a linefeed. This was wrong and is now fixed. + Write(bytes); + + WriteRaw("\nendstream\n"); } else { - // Earlier versions of PDFsharp skipped the '\n' before 'endstream' if the last byte of - // the stream is a linefeed. This was wrong and now fixed. - var bytes = value.Stream.Value; - if (bytes.Length != 0) + //WriteRaw(_lastCat == CharCat.NewLine ? ">>\nstream\n" : " >>\nstream\n"); + + if (IsVerboseLayout) + WriteRaw(Invariant($">>\n% Length: {bytes.Length}\nstream\n")); + else + WriteRaw(">>\nstream\n"); + + if (omitStream) + { + WriteRaw(" «…stream content omitted…»\n"); // Useful for debugging only. PDF file is always invalid. + } + else + { Write(bytes); + } + WriteRaw("\nendstream\n"); } - WriteRaw("\nendstream\n"); } public void WriteRaw(string rawString) @@ -572,6 +732,32 @@ public void WriteEof(PdfDocument document, SizeType startxref) } } + //static string GetFullTypeName(PdfObject obj) => obj.GetType().FullName ?? "?"; + static string? GetTypeAndComment(PdfObject value, bool typenameAlways = false) + { + var type = value.GetType(); + string comment = value.Comment; + + bool showType = typenameAlways || (type != typeof(PdfDictionary) && type != typeof(PdfArray)); + string? result; + + if (showType) + { + if (!String.IsNullOrEmpty(comment)) + result = Invariant($"% {value.GetType().Name} ({value.GetType().FullName}) -- {comment}\n"); + else + result = $"% {value.GetType().Name} ({value.GetType().FullName})\n"; + } + else + { + if (!String.IsNullOrEmpty(comment)) + result = Invariant($"% {comment}\n"); + else + result = null; + } + return result; + } + /// /// Gets or sets the indentation for a new indentation level. /// diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/enums/Symbol.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/enums/Symbol.cs index 8196928b..ab311b82 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/enums/Symbol.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/enums/Symbol.cs @@ -15,7 +15,9 @@ public enum Symbol BeginStream, EndStream, BeginArray, EndArray, BeginDictionary, EndDictionary, - Obj, EndObj, R, XRef, Trailer, StartXRef, Eof, + Obj, EndObj, + R, // Is replaced by ObjRef. + XRef, Trailer, StartXRef, Eof, // The lexer now can parse references in the form "nnn ggg R" // as a symbol in one step. diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Internal/PdfEncoders.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Internal/PdfEncoders.cs index 355ab378..31ad4021 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Internal/PdfEncoders.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Internal/PdfEncoders.cs @@ -35,22 +35,6 @@ public static Encoding WinAnsiEncoding { // We consistently use our own WinAnsiEncoding implementation in PDFsharp. get => _winAnsiEncoding ??= new AnsiEncoding(); - // #DELETE - // { - // if (_winAnsiEncoding == null) - // { - // //// Use own implementation because there is no ANSI encoding in .NET 6. - // //_winAnsiEncoding = new AnsiEncoding(); - //#if NET6_0_OR_GREATER___ // - // // There is ANSI encoding available with .NET 6. Use it. - // _winAnsiEncoding = CodePagesEncodingProvider.Instance.GetEncoding(1252)!; - //#else - // // StL 24-02-24: We are consistent on all platforms. - // _winAnsiEncoding = new AnsiEncoding(); - //#endif - // } - // return _winAnsiEncoding; - // } } static Encoding? _winAnsiEncoding; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionBase.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionBase.cs index c7e59ef6..0b9964e9 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionBase.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionBase.cs @@ -51,7 +51,6 @@ protected bool HandleCryptographicExceptionOnDecryption() "If PDFsharp will load the file and the contents seem to be correct, the file is at least partly not encrypted as expected."); return true; } - return false; } @@ -71,9 +70,9 @@ protected bool HandleCryptographicExceptionOnDecryption() public int? RevisionValue { get; protected set; } - public int? LengthValue { get; protected set; } - - public int? ActualLength { get; protected set; } + // Due to PDF reference length has not always to be set. But the adobe powered PDF viewer extension for edge cannot open files correctly, if length is missing. + // So we always output a length value. + public int LengthValue { get; protected set; } public bool EncryptMetadata { get; protected set; } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionV1To4.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionV1To4.cs index 2d30059b..937b0dc1 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionV1To4.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionV1To4.cs @@ -21,7 +21,7 @@ public PdfEncryptionV1To4(PdfStandardSecurityHandler securityHandler) : base(sec ///
public void SetEncryptionToV1() { - Initialize(1); + Initialize(1, 40); SecurityHandler.RemoveCryptFilters(); SecurityHandler._document.SetRequiredVersion(12); } @@ -44,8 +44,8 @@ public void SetEncryptionToV2(int length = 40) // ReSharper disable once InconsistentNaming public void SetEncryptionToV4UsingRC4(bool encryptMetadata = true) { - Initialize(4, null, encryptMetadata); - SecurityHandler.GetOrAddStandardCryptFilter().SetEncryptionToRC4ForV4(ActualLength!.Value); + Initialize(4, 128, encryptMetadata); + SecurityHandler.GetOrAddStandardCryptFilter().SetEncryptionToRC4ForV4(); SecurityHandler._document.SetRequiredVersion(15); } @@ -55,7 +55,7 @@ public void SetEncryptionToV4UsingRC4(bool encryptMetadata = true) /// The document metadata stream shall be encrypted (default: true). public void SetEncryptionToV4UsingAES(bool encryptMetadata = true) { - Initialize(4, null, encryptMetadata); + Initialize(4, 128, encryptMetadata); SecurityHandler.GetOrAddStandardCryptFilter().SetEncryptionToAESForV4(); SecurityHandler._document.SetRequiredVersion(16); } @@ -67,9 +67,7 @@ public override void InitializeFromLoadedSecurityHandler() { VersionValue = SecurityHandler.Elements.GetInteger(PdfSecurityHandler.Keys.V); RevisionValue = SecurityHandler.Elements.GetInteger(PdfStandardSecurityHandler.Keys.R); - LengthValue = SecurityHandler.Elements.ContainsKey(PdfSecurityHandler.Keys.Length) ? SecurityHandler.Elements.GetInteger(PdfSecurityHandler.Keys.Length) : null; - - UpdateActualLength(); + LengthValue = SecurityHandler.Elements.ContainsKey(PdfSecurityHandler.Keys.Length) ? SecurityHandler.Elements.GetInteger(PdfSecurityHandler.Keys.Length) : GetDefaultLength(); EncryptMetadata = (SecurityHandler.Elements[PdfStandardSecurityHandler.Keys.EncryptMetadata] as PdfBoolean)?.Value ?? true; // GetBoolean() returns false if not existing, but default is true. @@ -80,7 +78,7 @@ public override void InitializeFromLoadedSecurityHandler() Debug.Assert(calculatedRevision == RevisionValue); } - void Initialize(int versionValue, int? lengthValue = null, bool encryptMetadata = true) + void Initialize(int versionValue, int lengthValue, bool encryptMetadata = true) { CheckVersionAndLength(versionValue, lengthValue); @@ -88,30 +86,28 @@ void Initialize(int versionValue, int? lengthValue = null, bool encryptMetadata RevisionValue = null; // Revision is calculated later in PrepareEncryptionForSaving(). LengthValue = lengthValue; - UpdateActualLength(); - EncryptMetadata = encryptMetadata; } - void UpdateActualLength() + int GetDefaultLength() { - ActualLength = VersionValue switch + return VersionValue switch { - 1 => 40, - 2 => LengthValue ?? 40, // The default for Length value is 40. - 4 => 128, + 1 => 40, // Always 40. + 2 => 40, // Default value. + 4 => 128, // Always 128. _ => throw TH.InvalidOperationException_InvalidVersionValueForEncryptionVersion1To4() }; } - static void CheckVersionAndLength(int? versionValue, int? lengthValue) + static void CheckVersionAndLength(int? versionValue, int lengthValue) { if (!IsVersionSupported(versionValue)) throw TH.InvalidOperationException_InvalidVersionValueForEncryptionVersion1To4(); if (versionValue == 2) // Length is only needed for V2. { - if (lengthValue is null or < 40 or > 128 || lengthValue % 8 > 0) + if (lengthValue is < 40 or > 128 || lengthValue % 8 > 0) throw TH.InvalidOperationException_InvalidKeyLengthForEncryptionVersion2(); } } @@ -135,10 +131,7 @@ public override void PrepareEncryptionForSaving(string userPassword, string owne CheckVersionAndLength(VersionValue, LengthValue); SecurityHandler.Elements.SetInteger(PdfSecurityHandler.Keys.V, VersionValue!.Value); - if (LengthValue.HasValue) - SecurityHandler.Elements.SetInteger(PdfSecurityHandler.Keys.Length, LengthValue.Value); - else - SecurityHandler.Elements.Remove(PdfSecurityHandler.Keys.Length); + SecurityHandler.Elements.SetInteger(PdfSecurityHandler.Keys.Length, LengthValue); var permissionsValue = SecurityHandler.GetCorrectedPermissionsValue(); SecurityHandler.Elements.SetInteger(PdfStandardSecurityHandler.Keys.P, (int)permissionsValue); @@ -242,7 +235,7 @@ byte[] ComputeOwnerValue(byte[] userPad, byte[] ownerPad) if (RevisionValue >= 3) { // The encryption key length (in bytes) shall depend on the Length value (in bits). - var keyLength = ActualLength!.Value / 8; + var keyLength = LengthValue / 8; // Hash the pad 50 times for (var idx = 0; idx < 50; idx++) @@ -308,7 +301,7 @@ byte[] ComputeUserValueByEncryptionKey(byte[] documentId) userValue[idx] = 0; // Create encryption key with the specified length. - var keyLength = ActualLength!.Value / 8; + var keyLength = LengthValue / 8; Debug.Assert(keyLength == _globalEncryptionKey.Length); var encryptionKey = new Byte[keyLength]; @@ -368,7 +361,13 @@ void ComputeAndStoreEncryptionKey(byte[] documentId, byte[] paddedPassword, byte if (RevisionValue >= 3) { // The encryption and MD5 hashing key length (in bytes) shall depend on the Length value (in bits). - keyLength = ActualLength!.Value / 8; + keyLength = LengthValue / 8; + +#if !NET6_0_OR_GREATER + // We have to call Initialize here for .NET 4.6.2. + // .NET 6/8 include Initialize in "_md5.TransformFinalBlock()". + _md5.Initialize(); +#endif // Create the hash 50 times (only for 128 bit). for (var idx = 0; idx < 50; idx++) @@ -399,8 +398,7 @@ void ComputeAndStoreEncryptionKey(byte[] documentId, byte[] paddedPassword, byte public override PasswordValidity ValidatePassword(string inputPassword) { VersionValue = SecurityHandler.Elements.GetInteger(PdfSecurityHandler.Keys.V); - LengthValue = SecurityHandler.Elements.ContainsKey(PdfSecurityHandler.Keys.Length) ? SecurityHandler.Elements.GetInteger(PdfSecurityHandler.Keys.Length) : null; - UpdateActualLength(); + LengthValue = SecurityHandler.Elements.ContainsKey(PdfSecurityHandler.Keys.Length) ? SecurityHandler.Elements.GetInteger(PdfSecurityHandler.Keys.Length) : GetDefaultLength(); CheckVersionAndLength(VersionValue, LengthValue); RevisionValue = SecurityHandler.Elements.GetInteger(PdfStandardSecurityHandler.Keys.R); @@ -441,7 +439,7 @@ bool ValidateOwnerPassword(byte[] documentId, string inputPassword, byte[] userV if (RevisionValue >= 3) { // The encryption key length (in bytes) shall depend on the Length value (in bits). - var keyLength = ActualLength!.Value / 8; + var keyLength = LengthValue / 8; // Hash the pad 50 times. for (var idx = 0; idx < 50; idx++) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionV5.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionV5.cs index ea695f06..f387c904 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionV5.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Security.Encryption/PdfEncryptionV5.cs @@ -30,15 +30,18 @@ public void Initialize(bool encryptMetadata = true) { VersionValue = 5; // Always 5 for PdfEncryptionV5. RevisionValue = 6; // Always 6 for PdfEncryptionV5. - LengthValue = null; // Deprecated in PDF 2.0. - - ActualLength = 256; // Always 256 for PdfEncryptionV5. + LengthValue = GetDefaultLength(); // Deprecated in PDF 2.0. But the adobe powered PDF viewer extension for edge cannot open files correctly, if length is missing. EncryptMetadata = encryptMetadata; SecurityHandler.GetOrAddStandardCryptFilter().SetEncryptionToAESForV5(); } + int GetDefaultLength() + { + return 256; // Always 256 for PdfEncryptionV5. + } + /// /// Initializes the PdfEncryptionV5 with the values that were saved in the security handler. /// @@ -48,7 +51,7 @@ public override void InitializeFromLoadedSecurityHandler() Initialize(encryptMetadata); } - static void CheckValues(int? versionValue, int? revisionValue, int? lengthValue) + static void CheckValues(int? versionValue, int? revisionValue, int lengthValue) { if (versionValue is not 5) throw TH.InvalidOperationException_InvalidVersionValueForEncryptionVersion5(); @@ -56,7 +59,7 @@ static void CheckValues(int? versionValue, int? revisionValue, int? lengthValue) if (revisionValue is not (5 or 6)) throw TH.InvalidOperationException_InvalidRevisionValueForEncryptionVersion5(); - if (lengthValue is not (null or 256)) + if (lengthValue is not 256) throw TH.InvalidOperationException_InvalidLengthValueForEncryptionVersion5(); } @@ -179,7 +182,7 @@ public override void PrepareEncryptionForSaving(string userPassword, string owne SecurityHandler.Elements.SetInteger(PdfSecurityHandler.Keys.V, VersionValue!.Value); // In PDF reference, Length is marked as deprecated in PDF 2.0, but Adobe Reader cannot read V5 encrypted files if this key is omitted. - SecurityHandler.Elements.SetInteger(PdfSecurityHandler.Keys.Length, ActualLength!.Value); + SecurityHandler.Elements.SetInteger(PdfSecurityHandler.Keys.Length, LengthValue); var permissionsValue = SecurityHandler.GetCorrectedPermissionsValue(); SecurityHandler.Elements.SetInteger(PdfStandardSecurityHandler.Keys.P, (int)permissionsValue); @@ -521,7 +524,7 @@ public override PasswordValidity ValidatePassword(string inputPassword) { VersionValue = SecurityHandler.Elements.GetInteger(PdfSecurityHandler.Keys.V); RevisionValue = SecurityHandler.Elements.GetInteger(PdfStandardSecurityHandler.Keys.R); - LengthValue = SecurityHandler.Elements.ContainsKey(PdfSecurityHandler.Keys.Length) ? SecurityHandler.Elements.GetInteger(PdfSecurityHandler.Keys.Length) : null; + LengthValue = SecurityHandler.Elements.ContainsKey(PdfSecurityHandler.Keys.Length) ? SecurityHandler.Elements.GetInteger(PdfSecurityHandler.Keys.Length) : GetDefaultLength(); // Ensure properties are set to the only valid values for PdfEncryptionV5. CheckValues(VersionValue, RevisionValue, LengthValue); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfArrayWithPadding.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfArrayWithPadding.cs deleted file mode 100644 index 8c4af860..00000000 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfArrayWithPadding.cs +++ /dev/null @@ -1,35 +0,0 @@ -// PDFsharp - A .NET library for processing PDF -// See the LICENSE file in the solution root for more information. - -using PdfSharp.Pdf.IO; - -namespace PdfSharp.Pdf.Signatures -{ - /// - /// Internal PDF array used for digital signatures. - /// For digital signatures, we have to add an array with four integers, - /// but at the time we add the array we cannot yet determine - /// how many digits those integers will have. - /// - /// The document. - /// The count of spaces added after the array. - /// The contents of the array. - sealed class PdfArrayWithPadding(PdfDocument document, int paddingRight, params PdfItem[] items) - : PdfArray(document, items) - { - public int PaddingRight { get; init; } = paddingRight; - - internal override void WriteObject(PdfWriter writer) - { - StartPosition = writer.Position; - - base.WriteObject(writer); - writer.WriteRaw(new String(' ', PaddingRight)); - } - - /// - /// Position of the first byte of this string in PdfWriter’s stream. - /// - public SizeType StartPosition { get; internal set; } - } -} diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfPlaceholderObject.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfPlaceholderObject.cs new file mode 100644 index 00000000..9df1197e --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfPlaceholderObject.cs @@ -0,0 +1,66 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using PdfSharp.Pdf.IO; + +namespace PdfSharp.Pdf.Signatures +{ + /// + /// This object reserves space in the stream of the PdfWriter by adding spaces for objects that can not be written at this time. + /// It is used e.g. for digital signatures to reserve space for the ByteRange Array. + /// + /// The length of the reserved space. + sealed class PdfPlaceholderObject(int length) : PdfObject() + { + public int Length { get; init; } = length; + + /// + /// This only writes spaces as placeholder for the actual object. + /// + internal override void WriteObject(PdfWriter writer) + { + StartPosition = writer.Position; + + writer.WriteRaw(new String(' ', Length)); + } + + /// + /// Writes the object, the placeholder is used for. + /// + /// The object to write. + /// The PDFWriter. + /// Throws an exception, when the space reserved by the placeholder isn’t enough. + internal void WriteActualObject(PdfObject obj, PdfWriter writer) + { + Object = obj; + + // Cache current writer position. + var initialPosition = writer.Position; + + // Write Object at StartPosition. + writer.Stream.Position = StartPosition; + Object.WriteObject(writer); + + // Ensure that object doesn’t exceed the reserved space. + var endPosition = writer.Position; + var actualLength = endPosition - StartPosition; + if (actualLength > Length) + { + throw new Exception($"The actual length {actualLength} of this object is larger than the length {Length} of its placeholder."); + } + + // Restore writer position. + writer.Stream.Position = initialPosition; + } + + /// + /// Position of this object in PdfWriter’s stream. + /// + public SizeType StartPosition { get; internal set; } + + /// + /// The object replacing the reserved space. + /// + public PdfObject? Object { get; private set; } + } +} diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfSignatureHandler.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfSignatureHandler.cs index fb120ffd..f1f4b752 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfSignatureHandler.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Signatures/PdfSignatureHandler.cs @@ -19,10 +19,10 @@ namespace PdfSharp.Pdf.Signatures public class DigitalSignatureHandler { /// - /// Space ... big enough reserved space to replace ByteRange placeholder [0 0 0 0] with the actual computed value of the byte range to sign + /// Big enough space reserved by PdfPlaceholderObject to be replaced by the actual computed value of the byte range to sign /// Worst case: signature dictionary is near the end of an 10 GB PDF file. /// - const int ByteRangePaddingLength = 36; // = "[0 9999999999 9999999999 9999999999]".Length + const int ByteRangePlaceholderLength = 36; // = "[0 9999999999 9999999999 9999999999]".Length DigitalSignatureHandler(PdfDocument document, IDigitalSigner signer, DigitalSignatureOptions options) { @@ -64,9 +64,8 @@ internal async Task ComputeSignatureAndRange(PdfWriter writer) { var (rangedStreamToSign, byteRangeArray) = GetRangeToSignAndByteRangeArray(writer.Stream); - Debug.Assert(_signatureFieldByteRangePdfArray != null); - writer.Stream.Position = _signatureFieldByteRangePdfArray.StartPosition; - byteRangeArray.WriteObject(writer); + Debug.Assert(_signatureFieldByteRangePlaceholder != null); + _signatureFieldByteRangePlaceholder.WriteActualObject(byteRangeArray, writer); // Computing signature from document’s digest. var signature = await Signer.GetSignatureAsync(rangedStreamToSign).ConfigureAwait(false); @@ -146,9 +145,9 @@ internal async Task AddSignatureComponentsAsync() var signatureSize = await Signer.GetSignatureSizeAsync().ConfigureAwait(false); _placeholderItem = new(signatureSize); - _signatureFieldByteRangePdfArray = new PdfArrayWithPadding(Document, ByteRangePaddingLength, new PdfLongInteger(0), new PdfLongInteger(0), new PdfLongInteger(0), new PdfLongInteger(0)); + _signatureFieldByteRangePlaceholder = new PdfPlaceholderObject(ByteRangePlaceholderLength); - var signatureDictionary = GetSignatureDictionary(_placeholderItem, _signatureFieldByteRangePdfArray); + var signatureDictionary = GetSignatureDictionary(_placeholderItem, _signatureFieldByteRangePlaceholder); var signatureField = GetSignatureField(signatureDictionary); var annotations = Document.Pages[Options.PageIndex].Elements.GetArray(PdfPage.Keys.Annots); @@ -209,7 +208,7 @@ PdfSignatureField GetSignatureField(PdfSignature2 signatureDic) return signatureField; } - PdfSignature2 GetSignatureDictionary(PdfSignaturePlaceholderItem contents, PdfArray byteRange) + PdfSignature2 GetSignatureDictionary(PdfSignaturePlaceholderItem contents, PdfPlaceholderObject byteRange) { PdfSignature2 signatureDic = new(Document); @@ -230,7 +229,6 @@ PdfSignature2 GetSignatureDictionary(PdfSignaturePlaceholderItem contents, PdfAr propertyItems.Elements.Add("/Name", String.IsNullOrWhiteSpace(Options.AppName) ? new PdfName("/PDFsharp http://www.pdfsharp.net") : - //new PdfName($"/{Options.AppName}")); // #DELETE PdfName.FromString(Options.AppName)); Document.Internals.AddObject(signatureDic); @@ -239,6 +237,6 @@ PdfSignature2 GetSignatureDictionary(PdfSignaturePlaceholderItem contents, PdfAr } PdfSignaturePlaceholderItem? _placeholderItem; - PdfArrayWithPadding? _signatureFieldByteRangePdfArray; + PdfPlaceholderObject? _signatureFieldByteRangePlaceholder; } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/EntryInfoAttribute.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/EntryInfoAttribute.cs index 10a7d979..78dcf9b6 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/EntryInfoAttribute.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/EntryInfoAttribute.cs @@ -66,14 +66,19 @@ public KeyInfoAttribute(string version, KeyType keyType) KeyType = keyType; } - public KeyInfoAttribute(KeyType keyType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type objectType) + public KeyInfoAttribute(KeyType keyType, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type objectType) { //_version = version; KeyType = keyType; _objectType = objectType; } - public KeyInfoAttribute(string version, KeyType keyType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type objectType) + public KeyInfoAttribute(string version, + KeyType keyType, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type objectType) { //_version = version; KeyType = keyType; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/KeysBase.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/KeysBase.cs index af635e01..ed48d925 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/KeysBase.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/KeysBase.cs @@ -10,7 +10,10 @@ namespace PdfSharp.Pdf ///
public class KeysBase { - internal static DictionaryMeta CreateMeta([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type) => new(type); + internal static DictionaryMeta CreateMeta( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] + Type type) + => new(type); /// /// Creates the DictionaryMeta with the specified default type to return in DictionaryElements.GetValue @@ -19,7 +22,12 @@ public class KeysBase /// The type. /// Default type of the content key. /// Default type of the content. - internal static DictionaryMeta CreateMeta([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type, KeyType defaultContentKeyType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type defaultContentType) - => new(type, defaultContentKeyType, defaultContentType); + internal static DictionaryMeta CreateMeta( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] + Type type, + KeyType defaultContentKeyType, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type defaultContentType) + => new(type, defaultContentKeyType, defaultContentType); } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/KeysMeta.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/KeysMeta.cs index 650512d3..1c38d1ed 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/KeysMeta.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/KeysMeta.cs @@ -162,7 +162,10 @@ public DictionaryMeta([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes /// The type. /// Default type of the content key. /// Default type of the content. - public DictionaryMeta([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type, KeyType defaultContentKeyType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type defaultContentType) : this(type) + public DictionaryMeta([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] Type type, + KeyType defaultContentKeyType, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type defaultContentType) : this(type) { _defaultContentKeyDescriptor = new KeyDescriptor(new KeyInfoAttribute(defaultContentKeyType, defaultContentType)); } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDictionary.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDictionary.cs index 01996bad..62d014f3 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDictionary.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDictionary.cs @@ -159,7 +159,6 @@ internal override void WriteObject(PdfWriter writer) if (Stream != null) Debug.Assert(Elements.ContainsKey("/Length"), "Dictionary has a stream but no length is set."); #endif - if (_stream is not null && writer.EffectiveSecurityHandler != null) { // Encryption could change the size of the stream. @@ -170,16 +169,14 @@ internal override void WriteObject(PdfWriter writer) Elements[PdfStream.Keys.Length] = new PdfInteger(_stream?.Length ?? 0); } -#if DEBUG // Sort keys for debugging purposes. Comparing PDF files with for example programs like // Araxis Merge is easier with sorted keys. - if (writer.Layout == PdfWriterLayout.Verbose) + if (writer.IsVerboseLayout) { var list = new List(keys); list.Sort(PdfName.Comparer); list.CopyTo(keys, 0); } -#endif foreach (var key in keys) WriteDictionaryElement(writer, key); @@ -194,22 +191,17 @@ internal override void WriteObject(PdfWriter writer) /// internal virtual void WriteDictionaryElement(PdfWriter writer, PdfName key) { - if (key == null) - throw new ArgumentNullException(nameof(key)); - var item = Elements[key]; + Debug.Assert(key != null); #if DEBUG - // TODO_OLD: simplify PDFsharp - if (item is PdfObject { IsIndirect: true } pdfObject) - { - // Replace an indirect object by its Reference. - item = pdfObject.Reference; - Debug.Assert(false, "Check when we come here."); - } + if (key == "/Kids") + _ = typeof(int); #endif + var item = Elements[key]!; key.WriteObject(writer); - item?.WriteObject(writer); - writer.NewLine(); - } + item.WriteObject(writer); + if (writer.Layout == PdfWriterLayout.Verbose) + writer.NewLine(); +} /// /// Writes the stream of this dictionary. This function is intended to be overridden @@ -582,26 +574,27 @@ public void SetName(string key, string value) /// public PdfRectangle GetRectangle(string key, bool create) { - var value = new PdfRectangle(); var obj = this[key]; if (obj == null) { if (create) - this[key] = value = new PdfRectangle(); - return value; + return (PdfRectangle)(this[key] = new PdfRectangle()); + return new(); } if (obj is PdfReference reference) obj = reference.Value; if (obj is PdfArray { Elements.Count: 4 } array) { - value = new PdfRectangle(array.Elements.GetReal(0), array.Elements.GetReal(1), - array.Elements.GetReal(2), array.Elements.GetReal(3)); - this[key] = value; + return (PdfRectangle)(this[key] = + new PdfRectangle(array.Elements.GetReal(0), array.Elements.GetReal(1), + array.Elements.GetReal(2), array.Elements.GetReal(3))); } - else - value = (PdfRectangle)obj; - return value; + + if (obj is PdfRectangle rectangle) + return rectangle; + + throw new InvalidOperationException($"PDF item is '{obj.GetType().FullName}', but PdfRectangle expected."); } /// @@ -623,28 +616,26 @@ public void SetRectangle(string key, PdfRectangle rect) /// If the value is not convertible, the function throws an InvalidCastException. public XMatrix GetMatrix(string key, bool create) { - var value = new XMatrix(); var obj = this[key]; if (obj == null) { if (create) - this[key] = new PdfLiteral("[1 0 0 1 0 0]"); // cannot be parsed, implement a PdfMatrix... - return value; + this[key] = new PdfLiteral("[1 0 0 1 0 0]"); // cannot be parsed, implement a PdfMatrix... + return XMatrix.Identity; } if (obj is PdfReference reference) obj = reference.Value; - value = obj switch + return obj switch { - PdfArray { Elements.Count: 6 } array - => new XMatrix(array.Elements.GetReal(0), - array.Elements.GetReal(1), array.Elements.GetReal(2), array.Elements.GetReal(3), - array.Elements.GetReal(4), array.Elements.GetReal(5)), + PdfArray { Elements.Count: 6 } array => + new(array.Elements.GetReal(0), array.Elements.GetReal(1), + array.Elements.GetReal(2), array.Elements.GetReal(3), + array.Elements.GetReal(4), array.Elements.GetReal(5)), PdfLiteral => throw new NotImplementedException("Parsing matrix from literal."), _ => throw new InvalidCastException("Element is not an array with 6 values.") }; - return value; } /// Converts the specified value to XMatrix. @@ -670,7 +661,7 @@ public DateTime GetDateTime(string key, DateTime defaultValue) if (obj == null) return defaultValue; - // TODO_OLD obj = PdfReference.GetValueIfReference(obj) + //PdfReference.Dereference(ref obj); if (obj is PdfReference reference) obj = reference.Value; @@ -739,12 +730,7 @@ internal void SetEnumAsName(string key, object value) /// public PdfItem? GetValue(string key, VCF options) { - // PdfDictionary? dict; - // PdfArray? array; var value = this[key]; - //if (value == null || - // value is PdfNull || - // value is PdfReference && ((PdfReference)value).Value is PdfNullObject) if (value is null or PdfNull or PdfReference { Value: PdfNullObject }) { if (options != VCF.None) @@ -782,8 +768,9 @@ internal void SetEnumAsName(string key, object value) if (key == "/Info") { // We come here if PDFsharp was fully trimmed and meta-data could not be found by reflection. - throw new InvalidOperationException("PDFsharp relies on reflection and does not work when a fully-trimmed self-contained file is used.\r\n" + - "See https://docs.pdfsharp.net/ for further information."); + // Note: Should not occur since we added attributes that prevent trimming of certain parts. + throw new InvalidOperationException($"PDFsharp relies on reflection and does not work when a fully-trimmed self-contained file is used.\r\n" + + $"See {UrlLiterals.LinkToRoot} for further information."); } else { @@ -891,7 +878,10 @@ internal void SetEnumAsName(string key, object value) return type; } - PdfArray CreateArray([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type, PdfArray? oldArray) + PdfArray CreateArray( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type type, + PdfArray? oldArray) { #if true PdfArray? array; @@ -953,7 +943,10 @@ PdfArray CreateArray([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes. #endif } - PdfDictionary CreateDictionary([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type, PdfDictionary? oldDictionary) + PdfDictionary CreateDictionary( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type type, + PdfDictionary? oldDictionary) { #if true ConstructorInfo? ctorInfo; @@ -1012,7 +1005,10 @@ PdfDictionary CreateDictionary([DynamicallyAccessedMembers(DynamicallyAccessedMe #endif } - PdfItem CreateValue([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type, PdfDictionary? oldValue) + PdfItem CreateValue( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + Type type, + PdfDictionary? oldValue) { #if true var ctorInfo = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, @@ -1100,10 +1096,7 @@ public void SetValue(string key, PdfItem value) /// Gets the PdfReference with the specified key, or null if no such object exists. ///
public PdfReference? GetReference(string key) - { - var item = this[key]; - return item as PdfReference; - } + => this[key] as PdfReference; /// /// Sets the entry to the specified object. The object must not be an indirect object, @@ -1111,7 +1104,8 @@ public void SetValue(string key, PdfItem value) /// public void SetObject(string key, PdfObject obj) { - if (obj.Reference is not null) + //if (obj.Reference is not null) + if (obj.IsIndirect) throw new ArgumentException("PdfObject must not be an indirect object.", nameof(obj)); this[key] = obj; } @@ -1122,7 +1116,8 @@ public void SetObject(string key, PdfObject obj) ///
public void SetReference(string key, PdfObject obj) { - if (obj.Reference is null) + //if (obj.Reference is null) + if (obj.IsIndirect is false) throw new ArgumentException("PdfObject must be an indirect object.", nameof(obj)); this[key] = obj.Reference; } @@ -1130,7 +1125,7 @@ public void SetReference(string key, PdfObject obj) /// /// Sets the entry as a reference to the specified iref. /// - public void SetReference(string key, PdfReference? iref) + public void SetReference(string key, PdfReference iref) { if (iref is null) throw new ArgumentNullException(nameof(iref)); @@ -1233,15 +1228,6 @@ public PdfItem? this[PdfName key] public bool Remove(KeyValuePair item) => throw new NotImplementedException(); - ///// - ///// Determines whether the dictionary contains the specified name. - ///// - //[Obsolete("Use ContainsKey.")] - //public bool Contains(string key) - //{ - // return _elements.ContainsKey(key); - //} - /// /// Determines whether the dictionary contains the specified name. /// @@ -1527,7 +1513,7 @@ public byte[] UnfilteredValue /// Otherwise, the content remains untouched and the function returns false. /// The function is useful for analyzing existing PDF files. ///
- [Obsolete("Not implemented. Use the function TryUncompress.")] + [Obsolete("Not correctly implemented. Use the function TryUncompress.")] public bool TryUnfilter() { // Keep old code for not break existing code. @@ -1633,18 +1619,10 @@ public override string ToString() var filter = _ownerDictionary.Elements["/Filter"]; if (filter != null) { -#if true var decodeParms = _ownerDictionary.Elements[Keys.DecodeParms]; var bytes = Filtering.Decode(_value, filter, decodeParms); - if (bytes != null) + if (bytes != null!) stream = PdfEncoders.RawEncoding.GetString(bytes, 0, bytes.Length); -#else - - if (_owner.Elements.GetString("/Filter") == "/FlateDecode") - { - stream = Filtering.FlateDecode.DecodeToString(_value); - } -#endif else throw new NotImplementedException("Unknown filter"); } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocument.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocument.cs index 7e9db2ec..d1eb2a39 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocument.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocument.cs @@ -369,8 +369,18 @@ async Task DoSaveAsync(PdfWriter writer) _ = typeof(int); #endif iref.Position = writer.Position; - iref.Value.WriteObject(writer); + + var obj = iref.Value; + + // Enter indirect object in SecurityHandler to allow object encryption key generation for this object. + effectiveSecurityHandler?.EnterObject(obj.ObjectID); + + obj.WriteObject(writer); } + + // Leaving only the last indirect object in SecurityHandler is sufficient, as this is the first time no indirect object is entered anymore. + effectiveSecurityHandler?.LeaveObject(); + // ReSharper disable once RedundantCast. Redundant only if 64 bit. var startXRef = (SizeType)writer.Position; IrefTable.WriteObject(writer); @@ -978,9 +988,9 @@ internal void EnsureNotYetSaved() return; var message = "The document was already saved and cannot be modified anymore. " + - "Saving a document converts its in memory representation into a PDF file or stream. " + + "Saving a document converts its in-memory representation into a PDF file or stream. " + "This can only be done once. " + - "After that process the in memory representation is outdated and protected against further modification."; + "After that process the in-memory representation is outdated and protected against further modification."; throw new InvalidOperationException(message); } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocumentOptions.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocumentOptions.cs index fcc8df71..fe95413a 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocumentOptions.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocumentOptions.cs @@ -3,6 +3,8 @@ // ReSharper disable ConvertToAutoProperty +using PdfSharp.Pdf.IO; + namespace PdfSharp.Pdf { /// @@ -81,5 +83,19 @@ public PdfUseFlateDecoderForJpegImages UseFlateDecoderForJpegImages set => _useFlateDecoderForJpegImages = value; } PdfUseFlateDecoderForJpegImages _useFlateDecoderForJpegImages = PdfUseFlateDecoderForJpegImages.Never; + + /// + /// Gets or sets a value used for the PdfWriterLayout in PdfWriter. + /// + public PdfWriterLayout Layout + { + get => _writerLayout; + set => _writerLayout = value; + } +#if DEBUG + PdfWriterLayout _writerLayout = PdfWriterLayout.Verbose; +#else + PdfWriterLayout _writerLayout = PdfWriterLayout.Compact; +#endif } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfName.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfName.cs index 2a67643b..9cbc9cd2 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfName.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfName.cs @@ -152,10 +152,10 @@ public int Compare(PdfName? l, PdfName? r) { if (r != null) return String.Compare(l.Value, r.Value, StringComparison.Ordinal); - return -1; + return 1; } if (r != null) - return 1; + return -1; return 0; } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfObject.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfObject.cs index be4a1d70..a7e80ba6 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfObject.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfObject.cs @@ -110,9 +110,10 @@ internal void SetObjectID(int objectNumber, int generationNumber) { // ReSharper disable once ObjectCreationAsStatement because the new object is set to this object // in the constructor of PdfReference. - new PdfReference(this); + //new PdfReference(this); + PdfReference.CreateFromObject(this, objectID, 0); Debug.Assert(_iref != null); - _iref.ObjectID = objectID; + //_iref.ObjectID = objectID; } _iref.Value = this; _iref.Document = _document; @@ -146,7 +147,7 @@ internal virtual PdfDocument Document /// Gets or sets the comment for debugging purposes. /// public string Comment { get; set; } = ""; - + /// /// Indicates whether the object is an indirect object. /// @@ -169,7 +170,7 @@ internal virtual void PrepareForSave() /// /// Saves the stream position. 2nd Edition. /// - internal override void WriteObject(PdfWriter writer) + internal override void WriteObject(PdfWriter writer) => Debug.Assert(false, "Must not come here, WriteObject must be overridden in derived class."); /// @@ -364,7 +365,7 @@ static void FixUpObject(PdfImportedObjectTable iot, PdfDocument owner, PdfObject PdfDictionary? dict; PdfArray? array; - if ((dict = value as PdfDictionary) != null) + if ((dict = value as PdfDictionary) is not null) { // Case: The object is a dictionary. // Set document for cloned direct objects. @@ -418,13 +419,13 @@ static void FixUpObject(PdfImportedObjectTable iot, PdfDocument owner, PdfObject // The item is something else, e.g. a name. // Nothing to do. - // ...but let’s double check this case in DEBUG build. + // ...but let’s double-check this case in DEBUG build. DebugCheckNonObjects(item); } } } } - else if ((array = value as PdfArray) != null) + else if ((array = value as PdfArray) is not null) { // Case: The object is an array. // Set document for cloned direct objects. @@ -478,7 +479,7 @@ static void FixUpObject(PdfImportedObjectTable iot, PdfDocument owner, PdfObject // The item is something else, e.g. a name. // Nothing to do. - // ...but let’s double check this case in DEBUG build. + // ...but let’s double-check this case in DEBUG build. DebugCheckNonObjects(item); } } @@ -490,7 +491,7 @@ static void FixUpObject(PdfImportedObjectTable iot, PdfDocument owner, PdfObject // Indirect integers, booleans, etc. are allowed, but PDFsharp do not create them. // If such objects occur in imported PDF files from other producers, nothing more is to do. // The owner was already set, which is double-checked by the assertions below. - if (value is PdfNameObject or PdfStringObject or PdfBooleanObject /*or PdfIntegerObject*/ or PdfNumberObject) + if (value is PdfNameObject or PdfStringObject or PdfBooleanObject or PdfNumberObject) { Debug.Assert(value.IsIndirect); Debug.Assert(value.Owner == owner); diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfObjectID.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfObjectID.cs index d4094da7..ba975027 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfObjectID.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfObjectID.cs @@ -1,6 +1,9 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. +using Microsoft.Extensions.Logging; +using PdfSharp.Logging; + namespace PdfSharp.Pdf { /// @@ -10,40 +13,56 @@ namespace PdfSharp.Pdf // ReSharper disable once InconsistentNaming public readonly struct PdfObjectID : IComparable { - /// - /// Initializes a new instance of the class. - /// - /// The object number. - public PdfObjectID(int objectNumber) - { - Debug.Assert(objectNumber >= 1, "Object number out of range."); - _objectNumber = objectNumber; - _generationNumber = 0; -#if DEBUG_ - // Just a place for a breakpoint during debugging. - if (objectNumber == 5894) - _ = typeof(int); -#endif - } + //// /// + //// /// Initializes a new instance of the class. + //// /// + //// /// The object number. + //// public PdfObjectID(int objectNumber) + //// { + //// Debug.Assert(objectNumber >= 1, "Object number out of range."); + //// _objectNumber = objectNumber; + //// _generationNumber = 0; + ////#if DEBUG_ + //// // Just a place for a breakpoint during debugging. + //// if (objectNumber == 5894) + //// _ = typeof(int); + ////#endif + //// } /// /// Initializes a new instance of the class. /// /// The object number. /// The generation number. - public PdfObjectID(int objectNumber, int generationNumber) + public PdfObjectID(int objectNumber, int generationNumber = 0) { Debug.Assert(objectNumber >= 1, "Object number out of range."); //Debug.Assert(generationNumber >= 0 && generationNumber <= 65535, "Generation number out of range."); -#if DEBUG_ - // iText creates generation numbers with a value of 65536... - if (generationNumber > 65535) - Debug.WriteLine(String.Format("Generation number: {0}", generationNumber)); -#endif + + if (objectNumber is < 1 or > 0x_7F_FF_FF) + { + // We do not break existing code. + PdfSharpLogHost.PdfReadingLogger.LogError("Object number '{ObjectNumber}' is out of range [1..8388608].", objectNumber); + // No high-performance logging because it is a rare case. + } + + if (generationNumber is <0 or > 0x_FF_FF) + { + // We do not break existing code. + // We found an iText document with generation numbers with a value of 65536... + PdfSharpLogHost.PdfReadingLogger.LogError("Generation number '{GenerationNumber}' is out of range [0..65535].", generationNumber); + // No high-performance logging because it is a rare case. + } + _objectNumber = objectNumber; _generationNumber = (ushort)generationNumber; } + /// + /// Calculates a 64-bit unsigned integer from object and generation number. + /// + internal ulong UniqueNumber => ((ulong)_objectNumber << 32) + _generationNumber; + /// /// Gets or sets the object number. /// diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfOutline.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfOutline.cs index 35dcd39f..2518ea38 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfOutline.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfOutline.cs @@ -3,6 +3,7 @@ // Review: Under construction - StL/14-10-05 +using System.Diagnostics.CodeAnalysis; using System.Text; using PdfSharp.Drawing; using PdfSharp.Pdf.Actions; @@ -155,10 +156,12 @@ public string Title /// /// Gets or sets the destination page. + /// Can be null if destination page is not given directly. /// + [MaybeNull] public PdfPage DestinationPage { - get => _destinationPage ?? NRT.ThrowOnNull(); + get => _destinationPage; set => _destinationPage = value; } PdfPage? _destinationPage; @@ -305,7 +308,6 @@ void Initialize() var dest = Elements.GetValue(Keys.Dest); var a = Elements.GetValue(Keys.A); - Debug.Assert(dest == null || a == null, "Either destination or goto action."); PdfArray? destArray; if (dest != null) @@ -314,13 +316,15 @@ void Initialize() if (destArray != null) { SplitDestinationPage(destArray); + goto Done; } else { Debug.Assert(false, "See what to do when this happened."); } } - else if (a != null) + + if (a != null) { // The dictionary should be a GoTo action. if (a is PdfDictionary action && action.Elements.GetName(PdfAction.Keys.S) == "/GoTo") @@ -329,12 +333,10 @@ void Initialize() destArray = dest as PdfArray; if (destArray != null) { - // Replace Action with /Dest entry. - Elements.Remove(Keys.A); - Elements.Add(Keys.Dest, destArray); SplitDestinationPage(destArray); + goto Done; } - else if (dest is PdfString namedDestination) + if (dest is PdfString namedDestination) { // look in Destinations and name-tree if (Owner.Catalog.Destinations.Contains(namedDestination.Value)) @@ -356,20 +358,17 @@ void Initialize() } if (destArray != null) { - // Replace Action with /Dest entry. - Elements.Remove(Keys.A); - Elements.Add(Keys.Dest, destArray); SplitDestinationPage(destArray); } } else { - throw new Exception("Destination Array or Name expected."); + //throw new Exception("Destination Array or Name expected."); } } else { - Debug.Assert(false, "See what to do when this happened."); + //Debug.Assert(false, "See what to do when this happened."); } } else @@ -377,6 +376,7 @@ void Initialize() // Neither destination page nor GoTo action. } + Done: InitializeChildren(); } @@ -544,38 +544,39 @@ internal override void PrepareForSave() PdfArray CreateDestArray() { + // Only called if DestinationPage is not null. PdfArray? dest = PageDestinationType switch { // [page /XYZ left top zoom] - PdfPageDestinationType.Xyz => new PdfArray(Owner, DestinationPage.ReferenceNotNull, + PdfPageDestinationType.Xyz => new PdfArray(Owner, DestinationPage!.ReferenceNotNull, new PdfLiteral($"/XYZ {Fd(Left)} {Fd(Top)} {Fd(Zoom)}")), // [page /Fit] - PdfPageDestinationType.Fit => new PdfArray(Owner, DestinationPage.ReferenceNotNull, + PdfPageDestinationType.Fit => new PdfArray(Owner, DestinationPage!.ReferenceNotNull, new PdfLiteral("/Fit")), // [page /FitH top] - PdfPageDestinationType.FitH => new PdfArray(Owner, DestinationPage.ReferenceNotNull, + PdfPageDestinationType.FitH => new PdfArray(Owner, DestinationPage!.ReferenceNotNull, new PdfLiteral($"/FitH {Fd(Top)}")), // [page /FitV left] - PdfPageDestinationType.FitV => new PdfArray(Owner, DestinationPage.ReferenceNotNull, + PdfPageDestinationType.FitV => new PdfArray(Owner, DestinationPage!.ReferenceNotNull, new PdfLiteral($"/FitV {Fd(Left)}")), // [page /FitR left bottom right top] - PdfPageDestinationType.FitR => new PdfArray(Owner, DestinationPage.ReferenceNotNull, + PdfPageDestinationType.FitR => new PdfArray(Owner, DestinationPage!.ReferenceNotNull, new PdfLiteral($"/FitR {Fd(Left)} {Fd(Bottom)} {Fd(Right)} {Fd(Top)}")), // [page /FitB] - PdfPageDestinationType.FitB => new PdfArray(Owner, DestinationPage.ReferenceNotNull, + PdfPageDestinationType.FitB => new PdfArray(Owner, DestinationPage!.ReferenceNotNull, new PdfLiteral("/FitB")), // [page /FitBH top] - PdfPageDestinationType.FitBH => new PdfArray(Owner, DestinationPage.ReferenceNotNull, + PdfPageDestinationType.FitBH => new PdfArray(Owner, DestinationPage!.ReferenceNotNull, new PdfLiteral($"/FitBH {Fd(Top)}")), // [page /FitBV left] - PdfPageDestinationType.FitBV => new PdfArray(Owner, DestinationPage.ReferenceNotNull, + PdfPageDestinationType.FitBV => new PdfArray(Owner, DestinationPage!.ReferenceNotNull, new PdfLiteral($"/FitBV {Fd(Left)}")), _ => throw new ArgumentOutOfRangeException() @@ -590,9 +591,9 @@ static string Fd(double value) { if (Double.IsNaN(value)) throw new InvalidOperationException("Value is not a valid Double."); - return value.ToString("#.##", CultureInfo.InvariantCulture); + return value.ToString("0.##", CultureInfo.InvariantCulture); - //return Double.IsNaN(value) ? "null" : value.ToString("#.##", CultureInfo.InvariantCulture); + //return Double.IsNaN(value) ? "null" : value.ToString("0.##", CultureInfo.InvariantCulture); } /// @@ -600,7 +601,7 @@ static string Fd(double value) /// static string Fd(double? value) { - return value.HasValue ? value.Value.ToString("#.##", CultureInfo.InvariantCulture) : "null"; + return value.HasValue ? value.Value.ToString("0.##", CultureInfo.InvariantCulture) : "null"; } internal override void WriteObject(PdfWriter writer) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfPage.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfPage.cs index a1f4c8dc..9d451f45 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfPage.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfPage.cs @@ -53,7 +53,7 @@ internal void Initialize(bool setupSizeFromMediaBox) { // Setup page size from MediaBox. var rectangle = Elements.GetRectangle(InheritablePageKeys.MediaBox, false); - if (rectangle.IsEmpty) + if (rectangle.IsZero) throw new InvalidOperationException("Page has no MediaBox."); _width = XUnit.FromPoint(rectangle.X2 - rectangle.X1); @@ -180,7 +180,7 @@ public PageSize Size throw new InvalidEnumArgumentException(nameof(value), (int)value, typeof(PageSize)); var size = PageSizeConverter.ToSize(value); - MediaBox = new PdfRectangle(0, 0, size.Width, size.Height); + MediaBox = new(0, 0, size.Width, size.Height); } } @@ -191,14 +191,12 @@ public TrimMargins TrimMargins { get { - if (_trimMargins == default!) - _trimMargins = new TrimMargins(); + _trimMargins ??= new TrimMargins(); return _trimMargins; } set { - if (_trimMargins == default!) - _trimMargins = new TrimMargins(); + _trimMargins ??= new TrimMargins(); if (value != null!) { _trimMargins.Left = value.Left; @@ -210,7 +208,7 @@ public TrimMargins TrimMargins _trimMargins.All = XUnit.Zero; } } - TrimMargins _trimMargins = new TrimMargins(); + TrimMargins? _trimMargins; /// /// Gets or sets the media box directly. XGraphics is not prepared to work with a media box @@ -232,6 +230,16 @@ public PdfRectangle MediaBox } } + /// + /// Gets a value indicating whether a media box is set. + /// + public bool HasMediaBox => Elements[InheritablePageKeys.MediaBox] != null; + + /// + /// Gets a copy of the media box if it exists, or PdfRectangle.Empty if no media box is set. + /// + public PdfRectangle MediaBoxReadOnly => Elements.GetRectangle(InheritablePageKeys.MediaBox, false); + /// /// Gets or sets the crop box. /// @@ -241,6 +249,29 @@ public PdfRectangle CropBox set => Elements.SetRectangle(InheritablePageKeys.CropBox, value); } + /// + /// Gets a value indicating whether a crop box is set. + /// + public bool HasCropBox => Elements[InheritablePageKeys.CropBox] != null; + + /// + /// Gets a copy of the crop box if it exists, or PdfRectangle.Empty if no crop box is set. + /// + public PdfRectangle CropBoxReadOnly => Elements.GetRectangle(InheritablePageKeys.CropBox, false); + + /// + /// Gets a copy of the effective crop box if it exists, or PdfRectangle.Empty if neither crop box nor media box are set. + /// + public PdfRectangle EffectiveCropBoxReadOnly + { + get + { + if (HasCropBox) + return CropBox; + return MediaBoxReadOnly; + } + } + /// /// Gets or sets the bleed box. /// @@ -250,6 +281,29 @@ public PdfRectangle BleedBox set => Elements.SetRectangle(Keys.BleedBox, value); } + /// + /// Gets a value indicating whether a bleed box is set. + /// + public bool HasBleedBox => Elements[Keys.BleedBox] != null; + + /// + /// Gets a copy of the bleed box if it exists, or PdfRectangle.Empty if no bleed box is set. + /// + public PdfRectangle BleedBoxReadOnly => Elements.GetRectangle(Keys.BleedBox, false); + + /// + /// Gets a copy of the effective bleed box if it exists, or PdfRectangle.Empty if neither bleed box nor crop box nor media box are set. + /// + public PdfRectangle EffectiveBleedBoxReadOnly + { + get + { + if (HasBleedBox) + return BleedBox; + return EffectiveCropBoxReadOnly; + } + } + /// /// Gets or sets the art box. /// @@ -259,6 +313,29 @@ public PdfRectangle ArtBox set => Elements.SetRectangle(Keys.ArtBox, value); } + /// + /// Gets a value indicating whether an art box is set. + /// + public bool HasArtBox => Elements[Keys.ArtBox] != null; + + /// + /// Gets a copy of the art box if it exists, or PdfRectangle.Empty if no art box is set. + /// + public PdfRectangle ArtBoxReadOnly => Elements.GetRectangle(Keys.ArtBox, false); + + /// + /// Gets a copy of the effective art box if it exists, or PdfRectangle.Empty if neither art box nor crop box nor media box are set. + /// + public PdfRectangle EffectiveArtBoxReadOnly + { + get + { + if (HasArtBox) + return ArtBox; + return EffectiveCropBoxReadOnly; + } + } + /// /// Gets or sets the trim box. /// @@ -268,6 +345,29 @@ public PdfRectangle TrimBox set => Elements.SetRectangle(Keys.TrimBox, value); } + /// + /// Gets a value indicating whether a trim box is set. + /// + public bool HasTrimBox => Elements[Keys.TrimBox] != null; + + /// + /// Gets a copy of the trim box if it exists, or PdfRectangle.Empty if no trim box is set. + /// + public PdfRectangle TrimBoxReadOnly => Elements.GetRectangle(Keys.TrimBox, false); + + /// + /// Gets a copy of the effective trim box if it exists, or PdfRectangle.Empty if neither trim box nor crop box nor media box are set. + /// + public PdfRectangle EffectiveTrimBoxReadOnly + { + get + { + if (HasTrimBox) + return TrimBox; + return EffectiveCropBoxReadOnly; + } + } + /// /// Gets or sets the height of the page. /// If the page width is less than or equal to page height, the orientation is Portrait; @@ -820,15 +920,17 @@ internal static void InheritValues(PdfDictionary page, ref InheritedValues value internal override void PrepareForSave() { - if (_trimMargins.AreSet) + if (_trimMargins?.AreSet ?? false) { // These are the values InDesign set for an A4 page with 3mm crop margin at each edge. - // (recall that PDF rect are two points and NOT a point and a width) - // /MediaBox[0.0 0.0 612.283 858.898] 216 302.7 - // /CropBox[0.0 0.0 612.283 858.898] - // /BleedBox[0.0 0.0 612.283 858.898] - // /ArtBox[8.50394 8.50394 603.78 850.394] 3 3 213 300 - // /TrimBox[8.50394 8.50394 603.78 850.394] + // (recall that PDF rectangles are two points and NOT a point and width and height) + // /MediaBox[0.0 0.0 612.283 858.898] # in millimeter: (0 0) (216 302.7) + // /CropBox[0.0 0.0 612.283 858.898] # -------------- " --------------- + // /BleedBox[0.0 0.0 612.283 858.898] # -------------- " --------------- + // /ArtBox[8.50394 8.50394 603.78 850.394] # in millimeter: (3 3) (213 300) + // /TrimBox[8.50394 8.50394 603.78 850.394] # ------------- " -------------- + // + // An A4 page has a size of 210 x 297 mm² double width = _trimMargins.Left.Point + Width.Point + _trimMargins.Right.Point; double height = _trimMargins.Top.Point + Height.Point + _trimMargins.Bottom.Point; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfRectangle.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfRectangle.cs index da5019c2..1e6ef8fd 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfRectangle.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfRectangle.cs @@ -5,9 +5,9 @@ using System.Drawing; #endif #if WPF -using System.Windows.Media; +using System.Windows; #endif -using PdfSharp.Internal; +using System.CodeDom; using PdfSharp.Drawing; using PdfSharp.Pdf.Advanced; using PdfSharp.Pdf.IO; @@ -16,15 +16,16 @@ namespace PdfSharp.Pdf { /// - /// Represents a PDF rectangle value, that is internally an array with 4 real values. + /// Represents an immutable PDF rectangle value. + /// In a PDF file it is represented by an array of four real values. /// [DebuggerDisplay("{" + nameof(DebuggerDisplay) + "}")] public sealed class PdfRectangle : PdfItem { - // This class must behave like a value type. Therefore it cannot be changed (like System.String). + // This reference type must behave like a value type. Therefore, it cannot be changed (like System.String). /// - /// Initializes a new instance of the PdfRectangle class. + /// Initializes a new instance of the PdfRectangle class with all values set to zero. /// public PdfRectangle() { } @@ -37,10 +38,10 @@ public PdfRectangle() /// internal PdfRectangle(double x1, double y1, double x2, double y2) { - _x1 = x1; - _y1 = y1; - _x2 = x2; - _y2 = y2; + X1 = x1; + Y1 = y1; + X2 = x2; + Y2 = y2; } #if GDI @@ -50,10 +51,24 @@ internal PdfRectangle(double x1, double y1, double x2, double y2) /// public PdfRectangle(PointF pt1, PointF pt2) { - _x1 = pt1.X; - _y1 = pt1.Y; - _x2 = pt2.X; - _y2 = pt2.Y; + X1 = pt1.X; + Y1 = pt1.Y; + X2 = pt2.X; + Y2 = pt2.Y; + } +#endif + +#if WPF + /// + /// Initializes a new instance of the PdfRectangle class with two points specifying + /// two diagonally opposite corners. + /// + public PdfRectangle(Point pt1, Point pt2) + { + X1 = pt1.X; + Y1 = pt1.Y; + X2 = pt2.X; + Y2 = pt2.Y; } #endif @@ -63,10 +78,10 @@ public PdfRectangle(PointF pt1, PointF pt2) /// public PdfRectangle(XPoint pt1, XPoint pt2) { - _x1 = pt1.X; - _y1 = pt1.Y; - _x2 = pt2.X; - _y2 = pt2.Y; + X1 = pt1.X; + Y1 = pt1.Y; + X2 = pt2.X; + Y2 = pt2.Y; } #if GDI @@ -75,10 +90,10 @@ public PdfRectangle(XPoint pt1, XPoint pt2) /// public PdfRectangle(PointF pt, SizeF size) { - _x1 = pt.X; - _y1 = pt.Y; - _x2 = pt.X + size.Width; - _y2 = pt.Y + size.Height; + X1 = pt.X; + Y1 = pt.Y; + X2 = pt.X + size.Width; + Y2 = pt.Y + size.Height; } #endif @@ -87,10 +102,10 @@ public PdfRectangle(PointF pt, SizeF size) ///
public PdfRectangle(XPoint pt, XSize size) { - _x1 = pt.X; - _y1 = pt.Y; - _x2 = pt.X + size.Width; - _y2 = pt.Y + size.Height; + X1 = pt.X; + Y1 = pt.Y; + X2 = pt.X + size.Width; + Y2 = pt.Y + size.Height; } /// @@ -98,10 +113,13 @@ public PdfRectangle(XPoint pt, XSize size) /// public PdfRectangle(XRect rect) { - _x1 = rect.X; - _y1 = rect.Y; - _x2 = rect.X + rect.Width; - _y2 = rect.Y + rect.Height; + if (rect.IsEmpty) + throw new InvalidOperationException("Cannot create PdfRectangle from an empty XRect."); + + X1 = rect.X; + Y1 = rect.Y; + X2 = rect.X + rect.Width; + Y2 = rect.Y + rect.Height; } /// @@ -119,46 +137,40 @@ internal PdfRectangle(PdfItem item) if (array == null) throw new InvalidOperationException(PsMsgs.UnexpectedTokenInPdfFile); - _x1 = array.Elements.GetReal(0); - _y1 = array.Elements.GetReal(1); - _x2 = array.Elements.GetReal(2); - _y2 = array.Elements.GetReal(3); + X1 = array.Elements.GetReal(0); + Y1 = array.Elements.GetReal(1); + X2 = array.Elements.GetReal(2); + Y2 = array.Elements.GetReal(3); } /// /// Clones this instance. /// - public new PdfRectangle Clone() - => (PdfRectangle)Copy(); + public new PdfRectangle Clone() => (PdfRectangle)Copy(); /// /// Implements cloning this instance. /// - protected override object Copy() - { - PdfRectangle rect = (PdfRectangle)base.Copy(); - return rect; - } + protected override object Copy() => (PdfRectangle)base.Copy(); /// /// Tests whether all coordinates are zero. /// - public bool IsEmpty => _x1 == 0 && _y1 == 0 && _x2 == 0 && _y2 == 0; + [Obsolete("Use 'IsZero' instead.")] + public bool IsEmpty => IsZero; + + /// + /// Tests whether all coordinates are zero. + /// + public bool IsZero => X1 == 0 && Y1 == 0 && X2 == 0 && Y2 == 0; /// /// Tests whether the specified object is a PdfRectangle and has equal coordinates. /// - public override bool Equals(object? obj) - { - // ReSharper disable CompareOfFloatsByEqualityOperator - if (obj is PdfRectangle rectangle) - { - var rect = rectangle; - return rect._x1 == _x1 && rect._y1 == _y1 && rect._x2 == _x2 && rect._y2 == _y2; - } - return false; - // ReSharper restore CompareOfFloatsByEqualityOperator - } + // ReSharper disable CompareOfFloatsByEqualityOperator + public override bool Equals(object? obj) => + obj is PdfRectangle rect && rect.X1 == X1 && rect.Y1 == Y1 && rect.X2 == X2 && rect.Y2 == Y2; + // ReSharper restore CompareOfFloatsByEqualityOperator /// /// Serves as a hash function for a particular type. @@ -166,10 +178,10 @@ public override bool Equals(object? obj) public override int GetHashCode() { // This code is from System.Drawing... - return (int)(((((uint)_x1) ^ ((((uint)_y1) << 13) | - (((uint)_y1) >> 0x13))) ^ ((((uint)_x2) << 0x1a) | - (((uint)_x2) >> 6))) ^ ((((uint)_y2) << 7) | - (((uint)_y2) >> 0x19))); + return (int)(((((uint)X1) ^ ((((uint)Y1) << 13) | + (((uint)Y1) >> 0x13))) ^ ((((uint)X2) << 0x1a) | + (((uint)X2) >> 6))) ^ ((((uint)Y2) << 7) | + (((uint)Y2) >> 0x19))); } /// @@ -182,7 +194,7 @@ public override int GetHashCode() if ((object?)left != null) { if ((object?)right != null) - return left._x1 == right._x1 && left._y1 == right._y1 && left._x2 == right._x2 && left._y2 == right._y2; + return left.X1 == right.X1 && left.Y1 == right.Y1 && left.X2 == right.X2 && left.Y2 == right.Y2; return false; } return (object?)right == null; @@ -192,122 +204,94 @@ public override int GetHashCode() /// /// Tests whether two structures differ in one or more coordinates. /// - public static bool operator !=(PdfRectangle? left, PdfRectangle? right) - { - return !(left == right); - } + public static bool operator !=(PdfRectangle? left, PdfRectangle? right) => !(left == right); /// /// Gets or sets the x-coordinate of the first corner of this PdfRectangle. /// - public double X1 => _x1; - - readonly double _x1; + public double X1 { get; } /// /// Gets or sets the y-coordinate of the first corner of this PdfRectangle. /// - public double Y1 => _y1; - - readonly double _y1; + public double Y1 { get; } /// /// Gets or sets the x-coordinate of the second corner of this PdfRectangle. /// - public double X2 => _x2; - - readonly double _x2; + public double X2 { get; } /// /// Gets or sets the y-coordinate of the second corner of this PdfRectangle. /// - public double Y2 => _y2; - - readonly double _y2; + public double Y2 { get; } /// /// Gets X2 - X1. /// - public double Width => _x2 - _x1; + public double Width => X2 - X1; /// /// Gets Y2 - Y1. /// - public double Height => _y2 - _y1; + public double Height => Y2 - Y1; /// /// Gets or sets the coordinates of the first point of this PdfRectangle. /// - public XPoint Location => new XPoint(_x1, _y1); + public XPoint Location => new(X1, Y1); /// /// Gets or sets the size of this PdfRectangle. /// - public XSize Size => new XSize(_x2 - _x1, _y2 - _y1); + public XSize Size => new(X2 - X1, Y2 - Y1); #if GDI /// /// Determines if the specified point is contained within this PdfRectangle. /// - public bool Contains(PointF pt) - { - return Contains(pt.X, pt.Y); - } + public bool Contains(PointF pt) => Contains(pt.X, pt.Y); #endif /// /// Determines if the specified point is contained within this PdfRectangle. /// - public bool Contains(XPoint pt) - { - return Contains(pt.X, pt.Y); - } + public bool Contains(XPoint pt) => Contains(pt.X, pt.Y); /// /// Determines if the specified point is contained within this PdfRectangle. /// - public bool Contains(double x, double y) - { + public bool Contains(double x, double y) => // Treat rectangle inclusive/inclusive. - return _x1 <= x && x <= _x2 && _y1 <= y && y <= _y2; - } + X1 <= x && x <= X2 && Y1 <= y && y <= Y2; #if GDI /// /// Determines if the rectangular region represented by rect is entirely contained within this PdfRectangle. /// - public bool Contains(RectangleF rect) - { - return _x1 <= rect.X && (rect.X + rect.Width) <= _x2 && - _y1 <= rect.Y && (rect.Y + rect.Height) <= _y2; - } + public bool Contains(RectangleF rect) => + X1 <= rect.X && (rect.X + rect.Width) <= X2 && + Y1 <= rect.Y && (rect.Y + rect.Height) <= Y2; #endif /// /// Determines if the rectangular region represented by rect is entirely contained within this PdfRectangle. /// - public bool Contains(XRect rect) - { - return _x1 <= rect.X && (rect.X + rect.Width) <= _x2 && - _y1 <= rect.Y && (rect.Y + rect.Height) <= _y2; - } + public bool Contains(XRect rect) => + X1 <= rect.X && (rect.X + rect.Width) <= X2 && + Y1 <= rect.Y && (rect.Y + rect.Height) <= Y2; /// /// Determines if the rectangular region represented by rect is entirely contained within this PdfRectangle. /// - public bool Contains(PdfRectangle rect) - { - return _x1 <= rect._x1 && rect._x2 <= _x2 && - _y1 <= rect._y1 && rect._y2 <= _y2; - } + public bool Contains(PdfRectangle rect) => + X1 <= rect.X1 && rect.X2 <= X2 && + Y1 <= rect.Y1 && rect.Y2 <= Y2; /// /// Returns the rectangle as an XRect object. /// - public XRect ToXRect() - { - return new XRect(_x1, _y1, Width, Height); - } + public XRect ToXRect() => new(X1, Y1, Width, Height); /// /// Returns the rectangle as a string in the form «[x1 y1 x2 y2]». @@ -315,16 +299,19 @@ public XRect ToXRect() public override string ToString() { const string format = Config.SignificantDecimalPlaces3; - return PdfEncoders.Format("[{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "}]", _x1, _y1, _x2, _y2); + return PdfEncoders.Format("[{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "}]", X1, Y1, X2, Y2); } /// /// Writes the rectangle. /// - internal override void WriteObject(PdfWriter writer) - { - writer.Write(this); - } + internal override void WriteObject(PdfWriter writer) => writer.Write(this); + + /// + /// Represents an empty PdfRectangle. + /// + [Obsolete("A rectangle defined by two points cannot be meaningfully defined as empty. Do not use this property.")] + public static PdfRectangle Empty => throw new InvalidOperationException("Use 'new PdfRectangle()' instead of 'PdfRectangle.Empty'"); /// /// Gets the DebuggerDisplayAttribute text. @@ -337,107 +324,8 @@ string DebuggerDisplay { const string format = Config.SignificantDecimalPlaces10; return String.Format(CultureInfo.InvariantCulture, - "X1={0:" + format + "}, Y1={1:" + format + "}, X2={2:" + format + "}, Y2={3:" + format + "}", _x1, _y1, _x2, _y2); + "X1={0:" + format + "}, Y1={1:" + format + "}, X2={2:" + format + "}, Y2={3:" + format + "}", X1, Y1, X2, Y2); } } - -#if false // This object is considered as immutable. - // /// - // /// Adjusts the location of this PdfRectangle by the specified amount. - // /// - // public void Offset(PointF pos) - // { - // Offset(pos.X, pos.Y); - // } - // - // /// - // /// Adjusts the location of this PdfRectangle by the specified amount. - // /// - // public void Offset(double x, double y) - // { - // _x1 += x; - // _y1 += y; - // _x2 += x; - // _y2 += y; - // } - // - // /// - // /// Inflates this PdfRectangle by the specified amount. - // /// - // public void Inflate(double x, double y) - // { - // _x1 -= x; - // _y1 -= y; - // _x2 += x; - // _y2 += y; - // } - // - // /// - // /// Inflates this PdfRectangle by the specified amount. - // /// - // public void Inflate(SizeF size) - // { - // Inflate(size.Width, size.Height); - // } - // - // /// - // /// Creates and returns an inflated copy of the specified PdfRectangle. - // /// - // public static PdfRectangle Inflate(PdfRectangle rect, double x, double y) - // { - // rect.Inflate(x, y); - // return rect; - // } - // - // /// - // /// Replaces this PdfRectangle with the intersection of itself and the specified PdfRectangle. - // /// - // public void Intersect(PdfRectangle rect) - // { - // PdfRectangle rect2 = PdfRectangle.Intersect(rect, this); - // _x1 = rect2.x1; - // _y1 = rect2.y1; - // _x2 = rect2.x2; - // _y2 = rect2.y2; - // } - // - // /// - // /// Returns a PdfRectangle that represents the intersection of two rectangles. If there is no intersection, - // /// an empty PdfRectangle is returned. - // /// - // public static PdfRectangle Intersect(PdfRectangle rect1, PdfRectangle rect2) - // { - // double xx1 = Math.Max(rect1.x1, rect2.x1); - // double xx2 = Math.Min(rect1.x2, rect2.x2); - // double yy1 = Math.Max(rect1.y1, rect2.y1); - // double yy2 = Math.Min(rect1.y2, rect2.y2); - // if (xx2 >= xx1 && yy2 >= yy1) - // return new PdfRectangle(xx1, yy1, xx2, yy2); - // return PdfRectangle.Empty; - // } - // - // /// - // /// Determines if this rectangle intersects with the specified PdfRectangle. - // /// - // public bool IntersectsWith(PdfRectangle rect) - // { - // return rect.x1 < _x2 && _x1 < rect.x2 && rect.y1 < _y2 && _y1 < rect.y2; - // } - // - // /// - // /// Creates the smallest rectangle that can contain both of two specified rectangles. - // /// - // public static PdfRectangle Union(PdfRectangle rect1, PdfRectangle rect2) - // { - // return new PdfRectangle( - // Math.Min(rect1.x1, rect2.x1), Math.Max(rect1.x2, rect2.x2), - // Math.Min(rect1.y1, rect2.y1), Math.Max(rect1.y2, rect2.y2)); - // } -#endif - - /// - /// Represents an empty PdfRectangle. - /// - public static readonly PdfRectangle Empty = new PdfRectangle(); } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfString.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfString.cs index d5654aed..a05fbdff 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfString.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfString.cs @@ -47,7 +47,7 @@ public enum PdfStringEncoding /// /// Not yet used by PDFsharp. /// - MacRomanEncoding = PdfStringFlags.MacExpertEncoding, + MacRomanEncoding = PdfStringFlags.MacRomanEncoding, /// /// Not yet used by PDFsharp. @@ -68,12 +68,12 @@ public enum PdfStringEncoding enum PdfStringFlags { // ReSharper disable InconsistentNaming - RawEncoding = 0x00, - StandardEncoding = 0x01, // not used by PDFsharp + RawEncoding = 0x00, // Each char maps to a byte. + StandardEncoding = 0x01, // Not used by PDFsharp. PDFDocEncoding = 0x02, WinAnsiEncoding = 0x03, - MacRomanEncoding = 0x04, // not used by PDFsharp - MacExpertEncoding = 0x05, // not used by PDFsharp + MacRomanEncoding = 0x04, // Not used by PDFsharp. + MacExpertEncoding = 0x05, // Not used by PDFsharp. Unicode = 0x06, EncodingMask = 0x0F, diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfUInteger.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfUInteger.cs index dff4e2fe..86dfcc40 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfUInteger.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfUInteger.cs @@ -1,6 +1,8 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. +#if false // DELETE 2025-12-31 - PDF has no explicit unsigned number type. + using PdfSharp.Pdf.IO; namespace PdfSharp.Pdf @@ -160,3 +162,4 @@ public uint ToUInt32(IFormatProvider? provider) #endregion } } +#endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfUIntegerObject.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfUIntegerObject.cs index 28964439..19e18aeb 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfUIntegerObject.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfUIntegerObject.cs @@ -1,6 +1,7 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. +#if false // DELETE 2025-12-31 - PDF has no explicit unsigned number type. using PdfSharp.Pdf.IO; namespace PdfSharp.Pdf @@ -61,3 +62,4 @@ internal override void WriteObject(PdfWriter writer) } } } +#endif diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/PdfSharp.csproj b/src/foundation/src/PDFsharp/src/PdfSharp/PdfSharp.csproj index 6fb9e5af..dd12565d 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/PdfSharp.csproj +++ b/src/foundation/src/PDFsharp/src/PdfSharp/PdfSharp.csproj @@ -1,7 +1,7 @@  library - net6.0;net8.0;netstandard2.0 + net8.0;net9.0;net10.0;netstandard2.0 PdfSharp CORE diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Properties/GlobalDeclarations.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Properties/GlobalDeclarations.cs index 6d44c245..3b6d8a7d 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Properties/GlobalDeclarations.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Properties/GlobalDeclarations.cs @@ -19,7 +19,7 @@ [assembly: ComVisible(false)] [assembly: SuppressMessage("LoggingGenerator", "SYSLIB1006:Multiple logging methods cannot use the same event ID within a class", - Justification = "We use logging event ids as documented, i.e. multiple times", Scope = "member"/*, Target = "~M:PdfSharp.Internal.Logging.LogMessages.XGraphicsCreated(Microsoft.Extensions.Logging.ILogger,System.String)"*/)] + Justification = "We use logging event IDs as documented, i.e. multiple times", Scope = "member"/*, Target = "~M:PdfSharp.Internal.Logging.LogMessages.XGraphicsCreated(Microsoft.Extensions.Logging.ILogger,System.String)"*/)] // TODO_OLD We should add a WPF Preview panel //#if WPF diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Properties/PdfSharpProductVersionInformation.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Properties/PdfSharpProductVersionInformation.cs index ab3cbcb2..1eb063b4 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Properties/PdfSharpProductVersionInformation.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Properties/PdfSharpProductVersionInformation.cs @@ -1,7 +1,7 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. -#pragma warning disable 0436 +//#pragma warning disable 0436 namespace PdfSharp { @@ -27,48 +27,48 @@ public static class PdfSharpProductVersionInformation /// /// The major version number of the product. /// - public static readonly string VersionMajor = GitVersionInformation.Major; + public static readonly string VersionMajor = PdfSharpGitVersionInformation.Major; /// /// The minor version number of the product. /// - public static readonly string VersionMinor = GitVersionInformation.Minor; + public static readonly string VersionMinor = PdfSharpGitVersionInformation.Minor; /// /// The patch number of the product. /// - public static readonly string VersionPatch = GitVersionInformation.Patch; + public static readonly string VersionPatch = PdfSharpGitVersionInformation.Patch; /// /// The Version PreRelease string for NuGet. /// - public static readonly string VersionPreRelease = GitVersionInformation.NuGetPreReleaseTagV2; - + public static readonly string VersionPreRelease = PdfSharpGitVersionInformation.PreReleaseLabel; + /// /// The PDF creator application information string. /// - public static readonly string Creator = $"{Title} {GitVersionInformation.NuGetVersion}{Technology}"; + public static readonly string Creator = $"{Title} {PdfSharpGitVersionInformation.InformationalVersion}{Technology}"; /// /// The PDF producer (created by) information string. /// TODO_OLD: Called Creator in MigraDoc??? /// - public static readonly string Producer = $"{Title} {GitVersionInformation.NuGetVersion} ({Url})"; + public static readonly string Producer = $"{Title} {PdfSharpGitVersionInformation.InformationalVersion} ({Url})"; /// /// The full version number. /// - public static readonly string Version = GitVersionInformation.MajorMinorPatch; + public static readonly string Version = PdfSharpGitVersionInformation.MajorMinorPatch; /// /// The full semantic version number created by GitVersion. /// - public static readonly string SemanticVersion = GitVersionInformation.SemVer; + public static readonly string SemanticVersion = PdfSharpGitVersionInformation.SemVer; /// /// The home page of this product. /// - public const string Url = "www.pdfsharp.net"; + public const string Url = "www.pdfsharp.com"; /// /// Unused. @@ -88,7 +88,7 @@ public static class PdfSharpProductVersionInformation /// /// The copyright information. /// - public const string Copyright = "Copyright © 2005-2024 empira Software GmbH."; + public const string Copyright = "Copyright © 2005-2026 empira Software GmbH."; /// /// The trademark of the product. @@ -109,95 +109,95 @@ public static class PdfSharpProductVersionInformation // ReSharper restore RedundantNameQualifier #endif -#if Not_used_anymore - /// - /// E.g. "2005-01-01", for use in NuGet Script. - /// - public const string VersionReferenceDate = "2005-01-01"; - - /// - /// Use _ instead of blanks and special characters. Can be complemented with a suffix in the NuGet Script. - /// Nuspec Doc: The unique identifier for the package. This is the package name that is shown when packages - /// are listed using the Package Manager Console. These are also used when installing a package using the - /// Install-Package command within the Package Manager Console. Package IDs may not contain any spaces - /// or characters that are invalid in an URL. In general, they follow the same rules as .NET namespaces do. - /// So Foo.Bar is a valid ID, Foo! and Foo Bar are not. - /// - public const string NuGetID = "PDFsharp"; - - /// - /// Nuspec Doc: The human-friendly title of the package displayed in the Manage NuGet Packages dialog. - /// If none is specified, the ID is used instead. - /// - public const string NuGetTitle = "PDFsharp"; - - /// - /// Nuspec Doc: A comma-separated list of authors of the package code. - /// - public const string NuGetAuthors = "empira Software GmbH"; - - /// - /// Nuspec Doc: A comma-separated list of the package creators. This is often the same list as in authors. - /// This is ignored when uploading the package to the NuGet.org Gallery. - /// - public const string NuGetOwners = "empira Software GmbH"; - - /// - /// Nuspec Doc: A long description of the package. This shows up in the right pane of the Add Package Dialog - /// as well as in the Package Manager Console when listing packages using the Get-Package command. - /// - // This assignment must be written in one line because it will be parsed from a PS1 file. - public const string NuGetDescription = "PDFsharp is the Open Source .NET library that easily creates and processes PDF documents on the fly from any .NET language. The same drawing routines can be used to create PDF documents, draw on the screen, or send output to any printer."; - - /// - /// Nuspec Doc: A description of the changes made in each release of the package. This field only shows up - /// when the _Updates_ tab is selected and the package is an update to a previously installed package. - /// It is displayed where the Description would normally be displayed. - /// - public const string NuGetReleaseNotes = ""; - - /// - /// Nuspec Doc: A short description of the package. If specified, this shows up in the middle pane of the - /// Add Package Dialog. If not specified, a truncated version of the description is used instead. - /// - public const string NuGetSummary = "A .NET library for processing PDF."; - - /// - /// Nuspec Doc: The locale ID for the package, such as en-us. - /// - public const string NuGetLanguage = ""; - - /// - /// Nuspec Doc: A URL for the home page of the package. - /// - /// - /// http://www.pdfsharp.net/NuGetPackage_PDFsharp-GDI.ashx - /// http://www.pdfsharp.net/NuGetPackage_PDFsharp-WPF.ashx - /// - public const string NuGetProjectUrl = "www.pdfsharp.net"; - - /// - /// Nuspec Doc: A URL for the image to use as the icon for the package in the Manage NuGet Packages - /// dialog box. This should be a 32x32-pixel .png file that has a transparent background. - /// - public const string NuGetIconUrl = "http://www.pdfsharp.net/resources/PDFsharp-Logo-32x32.png"; - - /// - /// Nuspec Doc: A link to the license that the package is under. - /// - public const string NuGetLicenseUrl = "http://www.pdfsharp.net/PDFsharp_License.ashx"; - - /// - /// Nuspec Doc: A Boolean value that specifies whether the client needs to ensure that the package license (described by licenseUrl) is accepted before the package is installed. - /// - public const bool NuGetRequireLicenseAcceptance = false; - - /// - /// Nuspec Doc: A space-delimited list of tags and keywords that describe the package. This information is used to help make sure users can find the package using - /// searches in the Add Package Reference dialog box or filtering in the Package Manager Console window. - /// - public const string NuGetTags = "PDFsharp PDF creation"; -#endif +//#if Not_used_anymore +// /// +// /// E.g. "2005-01-01", for use in NuGet Script. +// /// +// public const string VersionReferenceDate = "2005-01-01"; + +// /// +// /// Use _ instead of blanks and special characters. Can be complemented with a suffix in the NuGet Script. +// /// Nuspec Doc: The unique identifier for the package. This is the package name that is shown when packages +// /// are listed using the Package Manager Console. These are also used when installing a package using the +// /// Install-Package command within the Package Manager Console. Package IDs may not contain any spaces +// /// or characters that are invalid in a URL. In general, they follow the same rules as .NET namespaces do. +// /// So Foo.Bar is a valid ID, Foo! and Foo Bar are not. +// /// +// public const string NuGetID = "PDFsharp"; + +// /// +// /// Nuspec Doc: The human-friendly title of the package displayed in the Manage NuGet Packages dialog. +// /// If none is specified, the ID is used instead. +// /// +// public const string NuGetTitle = "PDFsharp"; + +// /// +// /// Nuspec Doc: A comma-separated list of authors of the package code. +// /// +// public const string NuGetAuthors = "empira Software GmbH"; + +// /// +// /// Nuspec Doc: A comma-separated list of the package creators. This is often the same list as in authors. +// /// This is ignored when uploading the package to the NuGet.org Gallery. +// /// +// public const string NuGetOwners = "empira Software GmbH"; + +// /// +// /// Nuspec Doc: A long description of the package. This shows up in the right pane of the Add Package Dialog +// /// as well as in the Package Manager Console when listing packages using the Get-Package command. +// /// +// // This assignment must be written in one line because it will be parsed from a PS1 file. +// public const string NuGetDescription = "PDFsharp is the Open Source .NET library that easily creates and processes PDF documents on the fly from any .NET language. The same drawing routines can be used to create PDF documents, draw on the screen, or send output to any printer."; + +// /// +// /// Nuspec Doc: A description of the changes made in each release of the package. This field only shows up +// /// when the _Updates_ tab is selected and the package is an update to a previously installed package. +// /// It is displayed where the Description would normally be displayed. +// /// +// public const string NuGetReleaseNotes = ""; + +// /// +// /// Nuspec Doc: A short description of the package. If specified, this shows up in the middle pane of the +// /// Add Package Dialog. If not specified, a truncated version of the description is used instead. +// /// +// public const string NuGetSummary = "A .NET library for processing PDF."; + +// /// +// /// Nuspec Doc: The locale ID for the package, such as en-us. +// /// +// public const string NuGetLanguage = ""; + +// /// +// /// Nuspec Doc: A URL for the home page of the package. +// /// +// /// +// /// http://www.pdfsharp.net/NuGetPackage_PDF/sharp-GDI.ashx +// /// http://www.pdfsharp.net/NuGetPackage_PDF/sharp-WPF.ashx +// /// +// public const string NuGetProjectUrl = "www.pdfsharp.com"; + +// /// +// /// Nuspec Doc: A URL for the image to use as the icon for the package in the Manage NuGet Packages +// /// dialog box. This should be a 32x32-pixel .png file that has a transparent background. +// /// +// public const string NuGetIconUrl = "http://www.pdf/sharp.net/resources/PDF/sharp-Logo-32x32.png"; + +// /// +// /// Nuspec Doc: A link to the license that the package is under. +// /// +// public const string NuGetLicenseUrl = "http://www.pdfsharp.net/PDF/sharp_License.ashx"; + +// /// +// /// Nuspec Doc: A Boolean value that specifies whether the client needs to ensure that the package license (described by licenseUrl) is accepted before the package is installed. +// /// +// public const bool NuGetRequireLicenseAcceptance = false; + +// /// +// /// Nuspec Doc: A space-delimited list of tags and keywords that describe the package. This information is used to help make sure users can find the package using +// /// searches in the Add Package Reference dialog box or filtering in the Package Manager Console window. +// /// +// public const string NuGetTags = "PDFsharp PDF creation"; +//#endif /// /// The technology tag of the product: diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests-gdi/PdfSharp.Tests-gdi.csproj b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests-gdi/PdfSharp.Tests-gdi.csproj index cb0eeb3f..52fc24c9 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests-gdi/PdfSharp.Tests-gdi.csproj +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests-gdi/PdfSharp.Tests-gdi.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true true GDI @@ -29,6 +29,7 @@ + diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/CSharpFeaturesTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/CSharpFeaturesTests.cs index 2debdd88..b25944ea 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/CSharpFeaturesTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/CSharpFeaturesTests.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. using FluentAssertions; @@ -18,7 +18,7 @@ namespace PdfSharp.Tests.Build /// /// Test what features of C# 11 to C# 12 can be used with /// .NET 6/8 and C# 11 to C# 12 with .NET 4.62 / .NET Standard 2.0. - /// Thats amazing! + /// That’s amazing! /// [Collection("PDFsharp")] public class CSharpFeaturesTests diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/ReleaseBuildTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/ReleaseBuildTests.cs index 1cd610d7..95a0e67d 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/ReleaseBuildTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Build/ReleaseBuildTests.cs @@ -29,7 +29,7 @@ public void Check_renamed_identifiers() // Check to undo some temporary renames. const string automatic = nameof(PdfFontEmbedding.TryComputeSubset); (!automatic.EndsWith("_")).Should().BeTrue("some identifiers must be re-renamed before release."); - _ = automatic; + _ = automatic; } #endif @@ -37,7 +37,9 @@ public void Check_renamed_identifiers() //[Fact] public void Check_CS_files_for_non_ASCII_characters() { -#if NET6_0_OR_GREATER || CORE + // Tests runs only under .NET Framework and GDI. +#if NET6_0_OR_GREATER || CORE || WPF + // Exit here if not GDI under .NET Framework. return; #else #if DEBUG @@ -70,6 +72,19 @@ static void CheckFile(string file) bool utf16Bom = bytes is [0xFF, 0xFE, ..] or [0xFE, 0xFF, ..]; + bool hasCommentAnsi = bytes is [0x2F, 0x2F, ..]; + bool hasCommentUtf8 = bytes is [0xEF, 0xBB, 0xBF, 0x2F, 0x2F, ..]; + bool hasCommentUtf16Be = bytes is [0xFE, 0xFF, 0x00, 0x2F, 0x00, 0x2F, ..]; + bool hasCommentUtf16Le = bytes is [0xFF, 0xFE, 0x2F, 0x00, 0x2F, 0x00, ..]; + + bool hasComment = hasCommentAnsi || hasCommentUtf8 || hasCommentUtf16Be || hasCommentUtf16Le; + + if (!hasComment) + { + _ = typeof(int); + throw new InvalidOperationException($"File '{file}' does not start with a comment."); + } + int idx = 0; bool ascii = true; bool? nonAsciiBecauseOfApostrophe = null; @@ -200,28 +215,30 @@ static void Resave(byte[] bytes, bool isAnsi, string fileName, bool withBom) } } + /// + /// Writes the file. + /// Must be called only if the file requires an update (add a non-existing BOM or remove an existing BOM). + /// static void WriteFile(String fileName, Byte[] bytes, Boolean addBom) { bool utf8Bom = bytes is [0xEF, 0xBB, 0xBF, ..]; + (addBom == utf8Bom).Should().BeFalse("Should not come here."); + using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { if (addBom && !utf8Bom) { // Write new BOM. fs.Write([0xEF, 0xBB, 0xBF], 0, 3); - } - if (!addBom && utf8Bom) - { - // Write bytes without existing BOM. - fs.Write(bytes, 3, bytes.Length - 3); + // Write bytes as they are. + fs.Write(bytes, 0, bytes.Length); } else { - Debug.Assert(addBom && !utf8Bom, "Should not come here for other cases."); - // Write bytes as they are. - fs.Write(bytes, 0, bytes.Length); + // Write bytes without existing BOM. + fs.Write(bytes, 3, bytes.Length - 3); } } } diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/images/ImageTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/images/ImageTests.cs index 8a81f4d4..8988fbd0 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/images/ImageTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/images/ImageTests.cs @@ -71,7 +71,7 @@ public void PDF_with_Images() var font = new XFont("Arial", 20, XFontStyleEx.BoldItalic); // Draw the text. - gfx.DrawString("Hello, dotnet 6.0!", font, XBrushes.Black, + gfx.DrawString("Hello, World!", font, XBrushes.Black, new XRect(0, 0, width, height), XStringFormats.Center); //var imagePath = "PDFsharp/images/samples/jpeg/windows7problem.jpg"; // OK @@ -164,7 +164,7 @@ public void WriteAndRead_PDF_with_FlateDecode() var font = new XFont("Arial", 20, XFontStyleEx.BoldItalic); // Draw the text. - gfx.DrawString("Hello, dotnet 6.0!", font, XBrushes.Black, + gfx.DrawString("Hello, World!", font, XBrushes.Black, new XRect(0, 0, width, height), XStringFormats.Center); var imagePaths = new[] @@ -248,7 +248,7 @@ void ExportJpeg(PdfDictionary image) } [Fact] - void PDF_with_Image_from_stream() + public void PDF_with_Image_from_stream() { // Attempt to avoid "image file locked" under .NET 4.6.2. GC.Collect(); @@ -261,7 +261,7 @@ void PDF_with_Image_from_stream() var imagePath = IOUtility.GetAssetsPath("PDFsharp/images/samples/jpeg/truecolorA.jpg")!; - var stream = new FileStream(imagePath, FileMode.Open); + var stream = new FileStream(imagePath, FileMode.Open, FileAccess.Read); using var xImage = XImage.FromStream(stream); gfx.DrawImage(xImage, 100, 100, 100, 100); @@ -278,6 +278,113 @@ void PDF_with_Image_from_stream() GC.WaitForFullGCComplete(); } + [Fact] + public void PDF_with_Image_from_private_memorystream() + { + // Attempt to avoid "image file locked" under .NET 4.6.2. + GC.Collect(); + GC.WaitForFullGCComplete(); + + { + var document = new PdfDocument(); + var page = document.AddPage(); + var gfx = XGraphics.FromPdfPage(page); + + var imagePath = IOUtility.GetAssetsPath("PDFsharp/images/samples/jpeg/truecolorA.jpg")!; + var pngBytes = File.ReadAllBytes(imagePath); + + // Create a MemoryStream that does not allow GetBuffer. + var stream = new MemoryStream(pngBytes); + using var xImage = XImage.FromStream(stream); + + gfx.DrawImage(xImage, 100, 100, 100, 100); + + // Save the document... + var filename = PdfFileUtility.GetTempPdfFileName("ImageFromStream"); + document.Save(filename); + // ...and start a viewer. + PdfFileUtility.ShowDocumentIfDebugging(filename); + } + + // Attempt to avoid "image file locked" under .NET 4.6.2. + GC.Collect(); + GC.WaitForFullGCComplete(); + } + + [Fact] + public void PDF_with_Image_from_public_memorystream() + { + // Attempt to avoid "image file locked" under .NET 4.6.2. + GC.Collect(); + GC.WaitForFullGCComplete(); + + { + var document = new PdfDocument(); + var page = document.AddPage(); + var gfx = XGraphics.FromPdfPage(page); + + var imagePath = IOUtility.GetAssetsPath("PDFsharp/images/samples/jpeg/truecolorA.jpg")!; + var pngBytes = File.ReadAllBytes(imagePath); + + // Create a MemoryStream that allows GetBuffer. + var stream = new MemoryStream(pngBytes, 0, pngBytes.Length, false, true); + using var xImage = XImage.FromStream(stream); + + gfx.DrawImage(xImage, 100, 100, 100, 100); + + // Save the document... + var filename = PdfFileUtility.GetTempPdfFileName("ImageFromStream"); + document.Save(filename); + // ...and start a viewer. + PdfFileUtility.ShowDocumentIfDebugging(filename); + } + + // Attempt to avoid "image file locked" under .NET 4.6.2. + GC.Collect(); + GC.WaitForFullGCComplete(); + } + +#if GDI + [Fact] + public void PDF_with_image_from_GDI() + { + // Create a new PDF document. + var document = new PdfDocument(); + +#if DEBUG + // Create PDF files that are somewhat human-readable. + document.Options.Layout = PdfWriterLayout.Verbose; +#endif + + // Create an empty page in this document. + var page = document.AddPage(); + + // Get an XGraphics object for drawing on this page. + var gfx = XGraphics.FromPdfPage(page); + + var imageFolder = IOUtility.GetAssetsPath("pdfsharp/images/samples/jpeg"); + var imageFile = Path.Combine(imageFolder ?? throw new InvalidOperationException("Call Download-Assets.ps1 before running the tests."), "truecolorA.jpg"); + + var gdiImage = Image.FromFile(imageFile); + var xImage = XImage.FromGdiPlusImage(gdiImage); + gfx.DrawImage(xImage, new RectangleF(0f, 0f, 128f, 128f)); + + imageFolder = IOUtility.GetAssetsPath("pdfsharp/images/samples/png"); + imageFile = Path.Combine(imageFolder ?? throw new InvalidOperationException("Call Download-Assets.ps1 before running the tests."), "truecolorA.png"); + + gdiImage = Image.FromFile(imageFile); + xImage = XImage.FromGdiPlusImage(gdiImage); + gfx.DrawImage(xImage, new RectangleF(0f, 144f, 128f, 128f)); + + // Save the document... + var filename = PdfFileUtility.GetTempPdfFileName("ImageFromStream"); + document.Save(filename); + // ...and start a viewer. + PdfFileUtility.ShowDocumentIfDebugging(filename); + } + +#endif + #if NET6_0_OR_GREATER [Fact] public async Task PDF_with_Image_from_http_stream() diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/GlyphHelperTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/GlyphHelperTests.cs index cec5fa96..c43a2b05 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/GlyphHelperTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Drawing/text/GlyphHelperTests.cs @@ -66,7 +66,7 @@ public void GlyphIndicesFromString_Test() [Fact] public void Glyphs_from_invalid_ANSI_codes() { - // Ensure no glyph ids for non ANSI characters. + // Ensure no glyph IDs for non ANSI characters. var font = new XFont("Arial", 10); diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Filters/Ascii85Tests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Filters/Ascii85Tests.cs new file mode 100644 index 00000000..50d3e703 --- /dev/null +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Filters/Ascii85Tests.cs @@ -0,0 +1,202 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System.Text; +using FluentAssertions; +using PdfSharp.Pdf.Filters; +using Xunit; + +namespace PdfSharp.Tests.Filters +{ + [Collection("PDFsharp")] + public class Ascii85Tests + { + [Fact] + public void Check_Wikipedia_example() + { + // From Wikipedia: https://en.wikipedia.org/wiki/Ascii85#Example_for_Ascii85 + // Ensure that our code has no endianness issues. + + var filter = new Ascii85Decode(); + + string textOriginal = + "Man is distinguished, not only by his reason, but by this singular passion from other animals, " + + "which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, " + + "exceeds the short vehemence of any carnal pleasure."; + string textEncrypted = + "9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKFCj@.4Gp$d7F!,L7@<6@)/0JDEF@3BB/F*&OCAfu2/AKYi(""" + + "DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF-FD5W8ARlolDIal(" + + "DIdu" + + "D.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c~>"; + + var test = filter.Decode(StringToBytes(textEncrypted)); + var testString = BytesToString(test); + + var (e, d) = EncodeDecode(StringToBytes(textOriginal), filter); + + string encoded = BytesToString(e); + string decoded = BytesToString(d); + int encryptedLength1 = textEncrypted.Length; + int encryptedLength2 = encoded.Length; + + textOriginal.Should().Be(decoded); + textEncrypted.Should().Be(encoded); + } + + [Fact] + public void Check_empty_data() + { + var filter = new Ascii85Decode(); + + var (e, d) = EncodeDecode([], filter); + e.Length.Should().Be(2); + d.Length.Should().Be(0); + } + + [Fact] + public void Check_no_padding() + { + var filter = new Ascii85Decode(); + var bytes = new byte[4]; + + TestRange(0, 500); + //TestRange(0, 0xffffffff); // Takes long, but succeeds. + TestRange(0, 700); + TestRange(0xfffff000, 0xffffffff); + return; + + void TestRange(uint from, uint to) + { + for (long val = from; val <= to; val++) + { + bytes[0] = (byte)(val >> 24); + bytes[1] = (byte)(val >> 16); + bytes[2] = (byte)(val >> 8); + bytes[3] = (byte)(val); + var (e, d) = EncodeDecode(bytes, filter); + e.Length.Should().BeLessThanOrEqualTo(5 + 2); + d.Length.Should().Be(4); + + val.Should().Be(((uint)(d[0] << 24) | (uint)(d[1] << 16) | (uint)(d[2] << 8) | d[3])); + } + } + } + + [SkippableFact] + public void Check_padding() + { + Skip.If(SkippableTests.SkipSlowTests()); + + var filter = new Ascii85Decode(); + + // One byte. + var bytes = new byte[1]; + for (uint val = 0; val <= 0xff; val++) + { + bytes[0] = (byte)val; + var (e, d) = EncodeDecode(bytes, filter); + e.Length.Should().Be(2 + 2); + d.Length.Should().Be(1); + d[0].Should().Be((byte)val); + } + + // Two bytes. + bytes = new byte[2]; + for (uint val = 0; val <= 0xffff; val++) + { + bytes[0] = (byte)(val >> 8); + bytes[1] = (byte)val; + var (e, d) = EncodeDecode(bytes, filter); + e.Length.Should().Be(3 + 2); + d.Length.Should().Be(2); + d[0].Should().Be((byte)(val >> 8)); + d[1].Should().Be((byte)val); + } + + // Three bytes. + bytes = new byte[3]; + for (uint val = 0; val <= 0xffffff; val++) + { + //val += 0xc79ab; + + bytes[0] = (byte)(val >> 16); + bytes[1] = (byte)(val >> 8); + bytes[2] = (byte)val; + var (e, d) = EncodeDecode(bytes, filter); + e.Length.Should().Be(4 + 2); + d.Length.Should().Be(3); + d[0].Should().Be((byte)(val >> 16)); + d[1].Should().Be((byte)(val >> 8)); + d[2].Should().Be((byte)val); + } + } + + [Fact] + public void Check_literal_data() + { + var filter = new Ascii85Decode(); + + byte[][] bytes = + [ + StringToBytes("The quick fox."), + [255], // Largest padding value + [], + [0x12], + [0x12, 0x23], + [0x12, 0x23, 0x34], + [0x12, 0x23, 0x34, 0x45], + [0x12, 0x23, 0x34, 0x45, 0x56], + [0x12, 0x23, 0x34, 0x45, 0x56, 0x67], + [0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78], + [0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89], + [0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x9a], + [0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x9a, 0xab], + ]; + + for (int idx = 0; idx < bytes.Length; idx++) + { + var source = bytes[idx]; + var (e, d) = EncodeDecode(source, filter); + source.SequenceEqual(d).Should().BeTrue(); + string s = BytesToString(d); + + var size = e.Length; + var e2 = new Byte[3 * e.Length]; + var sb = new StringBuilder(); + for (int idxChar = 0; idxChar < size; idxChar++) + { + sb.Append(' '); + sb.Append((char)e[idxChar]); + sb.Append('\n'); + } + var d2 = filter.Decode(StringToBytes(sb.ToString()), (FilterParms?)null); + source.SequenceEqual(d2).Should().BeTrue(); + s = BytesToString(d); + } + } + + static (byte[] Encoded, byte[] Decoded) EncodeDecode(byte[] bytes, Ascii85Decode filter) + { + var encoded = filter.Encode(bytes); + var decoded = filter.Decode(encoded, (FilterParms?)null); + return (encoded, decoded); + } + + static byte[] StringToBytes(string s) + { + var bytes = new byte[s.Length]; + for (int idx = 0; idx < s.Length; idx++) + bytes[idx] = (byte)s[idx]; + return bytes; + } + + static string BytesToString(byte[] bytes) + { + var sb = new StringBuilder(); + for (int idx = 0; idx < bytes.Length; idx++) + sb.Append((char)bytes[idx]); + return sb.ToString(); + } + } +} diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Helper/XunitHelper.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Helper/XunitHelper.cs index a94d9153..8db8becf 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Helper/XunitHelper.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Helper/XunitHelper.cs @@ -1,4 +1,7 @@ -using System; +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/LexerTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/LexerTests.cs index e9d9e937..99bba3c0 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/LexerTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/LexerTests.cs @@ -5,20 +5,18 @@ using System.IO; #endif using FluentAssertions; -using PdfSharp.Diagnostics; -using PdfSharp.Drawing; -using PdfSharp.Fonts; using PdfSharp.Pdf; using PdfSharp.Pdf.Internal; using PdfSharp.Pdf.IO; -using PdfSharp.Quality; -using PdfSharp.Snippets; -using PdfSharp.Snippets.Font; -using PdfSharp.TestHelper; +using System.Numerics; using Xunit; namespace PdfSharp.Tests.IO { + /// + /// Most Lexer function are tested implicitly by correctly parsing PDF files. + /// We only test the non-trivial functions. + /// [Collection("PDFsharp")] public class LexerTests { @@ -85,5 +83,187 @@ public void ReverseSolidusTests() modifiedDocument.Info.Creator.Should().Be(creatorExpected); } + + [Fact] + public void ScanNumberTests() + { + var lexer = CreateLexer("123"); + var symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Integer); + lexer.TokenToInteger.Should().Be(123); + + lexer = CreateLexer("5000000000"); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.LongInteger); + lexer.TokenToLongInteger.Should().Be(5_000_000_000); + + // Int32.MaxValue must be Integer + lexer = CreateLexer(Invariant($"{Int32.MaxValue}")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Integer); + lexer.TokenToInteger.Should().Be(Int32.MaxValue); + + // Int32.MaxValue must be Integer, even with leading zeros. + lexer = CreateLexer(Invariant($"000000{Int32.MaxValue}")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Integer); + lexer.TokenToInteger.Should().Be(Int32.MaxValue); + + // Int32.MaxValue + 1 must be LongInteger + lexer = CreateLexer(Invariant($"{Int32.MaxValue + 1L}")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.LongInteger); + lexer.TokenToLongInteger.Should().Be(Int32.MaxValue + 1L); + + // Int32.MinValue must be Integer + lexer = CreateLexer(Invariant($"{Int32.MinValue}")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Integer); + lexer.TokenToInteger.Should().Be(Int32.MinValue); + + // Int32.MinValue - 1 must be LongInteger + lexer = CreateLexer(Invariant($"{Int32.MinValue - 1L}")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.LongInteger); + lexer.TokenToLongInteger.Should().Be(Int32.MinValue - 1L); + + // Int64.MaxValue must be LongInteger + lexer = CreateLexer(Invariant($"{Int64.MaxValue}")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.LongInteger); + lexer.TokenToLongInteger.Should().Be(Int64.MaxValue); + + // Int64.MaxValue + 1 must be Real + lexer = CreateLexer(Invariant($"{(BigInteger)1 + Int64.MaxValue}")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Real); + lexer.TokenToReal.Should().Be((double)((BigInteger)1 + Int64.MaxValue)); + + // Int64.MinValue must be LongInteger + lexer = CreateLexer(Invariant($"{Int64.MinValue}")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.LongInteger); + lexer.TokenToLongInteger.Should().Be(Int64.MinValue); + + // Int64.MinValue - 1 must be Real + lexer = CreateLexer(Invariant($"{(BigInteger)Int64.MinValue - 1}")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Real); + lexer.TokenToReal.Should().Be((double)((BigInteger)Int64.MinValue - 1)); + + // From https://github.com/empira/PDFsharp/issues/223 + lexer = CreateLexer("00000000000001588776"); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Integer); + lexer.TokenToInteger.Should().Be(00000000000001588776); + + // Real literals + + lexer = CreateLexer("100.124"); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Real); + lexer.TokenToReal.Should().Be(100.124); + + lexer = CreateLexer("123."); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Real); + lexer.TokenToReal.Should().Be(123); + + lexer = CreateLexer("123.00000000000000000000000000000"); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Real); + lexer.TokenToReal.Should().Be(123); + + + lexer = CreateLexer(Invariant($"{Int64.MaxValue - 42}.")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Real); + lexer.TokenToReal.Should().Be(Int64.MaxValue - 42); + + lexer = CreateLexer(Invariant($"{Int64.MaxValue - 42}.00")); + symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Real); + lexer.TokenToReal.Should().Be(Int64.MaxValue - 42); + } + + [Theory] + [InlineData("42", 42, true, true)] + [InlineData("2147483647", 2147483647, true, true)] // int32.MaxValue is 2147483647. + [InlineData("-2147483648", -2147483648, true, true)] + public void Scan_Integer_Tests(string text, int value, bool testAsLong, bool testAsReal) + { + var lexer = CreateLexer(text); + var symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Integer); + lexer.TokenToInteger.Should().Be(value); + if (testAsLong) + lexer.TokenToLongInteger.Should().Be(value); + if (testAsReal) + lexer.TokenToReal.Should().Be(value); + } + + [Theory] + [InlineData("9223372036854775807", 9223372036854775807L, true, true)] // UInt64.MaxValue is 9223372036854775807L. + [InlineData("-9223372036854775808", -9223372036854775808L, true, true)] + [InlineData("2147483648", 2147483648, true, true)] // int32.MaxValue is 2147483647. + [InlineData("-2147483649", -2147483649, true, true)] + public void Scan_LongInteger_Tests(string text, long value, bool testAsInteger, bool testAsReal) + { + var lexer = CreateLexer(text); + var symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.LongInteger); + lexer.TokenToLongInteger.Should().Be(value); + if (testAsInteger) + { + var getInt = () => lexer.TokenToInteger; + getInt.Should().Throw(); + } + if (testAsReal) + lexer.TokenToReal.Should().Be(value); + } + + [Theory] + [InlineData("42.0", 42, true, true)] + [InlineData("42.17", 42.17, true, true)] + [InlineData("42.12345678", 42.12345678, true, true)] + [InlineData("-42.0", -42, true, true)] + [InlineData("-42.17", -42.17, true, true)] + [InlineData("-42.12345678", -42.12345678, true, true)] + [InlineData("9223372036854775808", 9223372036854775808, true, true)] // UInt64.MaxValue is 9223372036854775807L. + [InlineData("-9223372036854775809", -9223372036854775809d, true, true)] + [InlineData("9223372036854775807.0", 9223372036854775807L, true, true)] // UInt64.MaxValue is 9223372036854775807L. + [InlineData("-9223372036854775808.0", -9223372036854775808L, true, true)] + [InlineData("2147483648.0", 2147483648, true, true)] // int32.MaxValue is 2147483647. + [InlineData("-2147483649.0", -2147483649, true, true)] + public void Scan_Real_Tests(string text, double value, bool testAsInteger, bool testAsLong) + { + var lexer = CreateLexer(text); + var symbol = lexer.ScanNumber(false); + symbol.Should().Be(Symbol.Real); + lexer.TokenToReal.Should().Be(value); + if (testAsInteger) + { + var getInt = () => lexer.TokenToInteger; + getInt.Should().Throw(); + } + if (testAsLong) + { + var getInt = () => lexer.TokenToLongInteger; + getInt.Should().Throw(); + } + } + + public void Scan_ObjRef_Tests(string text, (int, int) objID/*, bool testAsLong, bool testAsReal*/) + { + + } + + Lexer CreateLexer(string text) + { + var pdfString = new PdfString(text, PdfStringEncoding.RawEncoding); + var bytes = pdfString.GetRawBytes(); + var stream = new MemoryStream(bytes); + return new(stream, null); + } } } diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs index 2b03e397..278b4b9c 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs @@ -6,6 +6,7 @@ using PdfSharp.Drawing; using PdfSharp.Fonts; using PdfSharp.Pdf; +using PdfSharp.Pdf.Internal; using PdfSharp.Pdf.IO; using PdfSharp.Quality; using PdfSharp.Snippets.Font; @@ -17,6 +18,50 @@ namespace PdfSharp.Tests.IO [Collection("PDFsharp")] public class WriterTests { + +#if true + [Fact] + public void Test_issues() + { + var document = CreateDocument("CompactLayout-IssuesXXX"); + //var dict = new PdfDictionary(); + document.Options.Layout = PdfWriterLayout.Compact; + + var catalog = document.Catalog; + + var dict = new PdfDictionary(document/*, true*/); + document.Internals.AddObject(dict); + var bytes = PdfEncoders.RawEncoding.GetBytes("ABC"); + dict.CreateStream(bytes); + + catalog.Elements.Add("/TestStream", dict); + + Save(document); + //Reload(); + //ReloadedDocument.Options.Layout = PdfWriterLayout.Compact; + //Resave(); + + //CreateDocument("CompactLayout-Issues"); + } + protected PdfDocument CreateDocument(string name) + { + var _document = PdfDocUtility.CreateNewPdfDocument(name); + _document.Info.Title = name; + var _page = _document.AddPage(); + + return _document; + } + protected string Save(PdfDocument document, string? filename = null) + { + filename ??= document.Info.Title; + var _fullFilename = PdfFileUtility.GetTempPdfFullFileName("Pdf-ObjectModel/" + filename); + //Document.Options.Layout = PdfWriterLayout.Compact; + document.Save(_fullFilename); + return _fullFilename; + } +#endif + + [Fact] public void Write_import_file() { diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/creation/BasicTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/creation/BasicTests.cs index 6fe6f893..e0b410af 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/creation/BasicTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/creation/BasicTests.cs @@ -1,6 +1,7 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. +using FluentAssertions; using PdfSharp.Diagnostics; using PdfSharp.Drawing; using PdfSharp.Fonts; @@ -57,8 +58,13 @@ public void Create_Hello_World_BasicTests() var font = new XFont("Times New Roman", 20, XFontStyleEx.BoldItalic); // Draw the text. - gfx.DrawString("Hello, dotnet 6.0!", font, XBrushes.Black, +#if NET6_0_OR_GREATER + gfx.DrawString($"Hello, dotnet {Environment.Version.Major}.{Environment.Version.Minor}!", font, XBrushes.Black, new XRect(0, 0, width, height), XStringFormats.Center); +#else + gfx.DrawString("Hello, World!", font, XBrushes.Black, + new XRect(0, 0, width, height), XStringFormats.Center); +#endif // Save the document... string filename = PdfFileUtility.GetTempPdfFileName("HelloWorld"); @@ -66,5 +72,318 @@ public void Create_Hello_World_BasicTests() // ...and start a viewer. PdfFileUtility.ShowDocumentIfDebugging(filename); } + + [Fact] + public void Create_CropBox_BasicTests() + { + // Create a new PDF document. + var document = new PdfDocument(); + document.Info.Title = "Created with PDFsharp"; + + // Create an empty page in this document. + var page = document.AddPage(); + + var mediaBox = page.MediaBoxReadOnly; + mediaBox.Should().NotBeNull(); + mediaBox.Should().NotBe(XRect.Empty); + mediaBox.IsZero.Should().BeFalse(); + + // CropBox does not exist by default. + var cropBox = page.CropBoxReadOnly; + cropBox.IsZero.Should().BeTrue(); + + cropBox = page.EffectiveCropBoxReadOnly; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeFalse(); + + page.Width = XUnit.FromCentimeter(5); + page.Height = XUnit.FromCentimeter(2); + + mediaBox = page.MediaBoxReadOnly; + mediaBox.Should().NotBeNull(); + mediaBox.Should().NotBe(XRect.Empty); + mediaBox.IsZero.Should().BeFalse(); + + cropBox = page.CropBoxReadOnly; + cropBox.IsZero.Should().BeTrue(); + + cropBox = page.EffectiveCropBoxReadOnly; + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeFalse(); + + // Calling page.CropBox sets "new PdfRectangle()" as CropBox. + // For "new PdfRectangle()", IsZero is true. + cropBox = page.CropBox; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeTrue(); + + cropBox = page.EffectiveCropBoxReadOnly; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeTrue(); + + cropBox = page.CropBoxReadOnly; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeTrue(); + + cropBox = page.CropBox; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeTrue(); + + page.CropBox = new PdfRectangle(XUnitPt.FromMillimeter(1), XUnitPt.FromMillimeter(1), + XUnitPt.FromMillimeter(49), XUnitPt.FromMillimeter(19)); + + cropBox = page.CropBox; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeFalse(); + + // Get an XGraphics object for drawing on this page. + var gfx = XGraphics.FromPdfPage(page); + + // Draw two lines with a red default pen. + var width = page.Width.Point; + var height = page.Height.Point; + gfx.DrawLine(XPens.Red, 0, 0, width, height); + gfx.DrawLine(XPens.Red, width, 0, 0, height); + + // Draw a circle with a red pen which is 1.5 point thick. + var r = width / 6; + gfx.DrawEllipse(new XPen(XColors.Red, 1.5), XBrushes.White, new XRect(width / 2 - r, height / 2 - r, 2 * r, 2 * r)); + + // Create a font. + var font = new XFont("Times New Roman", 10, XFontStyleEx.BoldItalic); + +#if NET6_0_OR_GREATER + gfx.DrawString($"Hello, dotnet {Environment.Version.Major}.{Environment.Version.Minor}!", font, XBrushes.Black, + new XRect(0, 0, width, height), XStringFormats.Center); +#else + gfx.DrawString("Hello, World!", font, XBrushes.Black, + new XRect(0, 0, width, height), XStringFormats.Center); +#endif + + // Save the document... + string filename = PdfFileUtility.GetTempPdfFileName("BasicMediaBoxTest"); + document.Save(filename); + // ...and start a viewer. + PdfFileUtility.ShowDocumentIfDebugging(filename); + } + + [Fact] + public void Create_all_boxes_BasicTests() + { + // Create a new PDF document. + var document = new PdfDocument(); + document.Info.Title = "Created with PDFsharp"; + + // Create an empty page in this document. + var page = document.AddPage(); + var pageWidth = page.Width.Point; + var pageHeight = page.Height.Point; + var pageRectangle = new PdfRectangle(0, 0, pageWidth, pageHeight); + var defaultRectangle = new PdfRectangle(); + + var mediaBox = page.MediaBoxReadOnly; + mediaBox.Should().NotBeNull(); + mediaBox.Should().Be(pageRectangle); + + // CropBox does not exist by default. + var cropBox = page.CropBoxReadOnly; + cropBox.Should().Be(defaultRectangle); + + cropBox = page.EffectiveCropBoxReadOnly; + cropBox.Should().NotBeNull(); + cropBox.Should().Be(pageRectangle); + + page.Width = XUnit.FromCentimeter(5); + page.Height = XUnit.FromCentimeter(2); + + mediaBox = page.MediaBoxReadOnly; + mediaBox.Should().NotBeNull(); + mediaBox.Should().NotBe(XRect.Empty); + mediaBox.IsZero.Should().BeFalse(); + + // ----- CropBox ----- + cropBox = page.CropBoxReadOnly; + cropBox.IsZero.Should().BeTrue(); + + cropBox = page.EffectiveCropBoxReadOnly; + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeFalse(); + + // Calling page.CropBox sets "new PdfRectangle()" as CropBox. + // For "new PdfRectangle()", IsZero is true. + cropBox = page.CropBox; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeTrue(); + + cropBox = page.EffectiveCropBoxReadOnly; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeTrue(); + + cropBox = page.CropBoxReadOnly; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeTrue(); + + cropBox = page.CropBox; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeTrue(); + + page.CropBox = page.MediaBox; + + cropBox = page.CropBox; + cropBox.Should().NotBeNull(); + cropBox.Should().NotBe(XRect.Empty); + cropBox.IsZero.Should().BeFalse(); + + // ----- ArtBox ----- + var artBox = page.ArtBoxReadOnly; + artBox.IsZero.Should().BeTrue(); + + artBox = page.EffectiveArtBoxReadOnly; + artBox.Should().NotBe(XRect.Empty); + artBox.IsZero.Should().BeFalse(); + + // Calling page.ArtBox sets "new PdfRectangle()" as ArtBox. + // For "new PdfRectangle()", IsZero is true. + artBox = page.ArtBox; + artBox.Should().NotBeNull(); + artBox.Should().NotBe(XRect.Empty); + artBox.IsZero.Should().BeTrue(); + + artBox = page.EffectiveArtBoxReadOnly; + artBox.Should().NotBeNull(); + artBox.Should().NotBe(XRect.Empty); + artBox.IsZero.Should().BeTrue(); + + artBox = page.ArtBoxReadOnly; + artBox.Should().NotBeNull(); + artBox.Should().NotBe(XRect.Empty); + artBox.IsZero.Should().BeTrue(); + + artBox = page.ArtBox; + artBox.Should().NotBeNull(); + artBox.Should().NotBe(XRect.Empty); + artBox.IsZero.Should().BeTrue(); + + page.ArtBox = page.MediaBox; + + artBox = page.ArtBox; + artBox.Should().NotBeNull(); + artBox.Should().NotBe(XRect.Empty); + artBox.IsZero.Should().BeFalse(); + + // ----- BleedBox ----- + var bleedBox = page.BleedBoxReadOnly; + bleedBox.IsZero.Should().BeTrue(); + + bleedBox = page.EffectiveBleedBoxReadOnly; + bleedBox.Should().NotBe(XRect.Empty); + bleedBox.IsZero.Should().BeFalse(); + + // Calling page.BleedBox sets "new PdfRectangle()" as BleedBox. + // For "new PdfRectangle()", IsZero is true. + bleedBox = page.BleedBox; + bleedBox.Should().NotBeNull(); + bleedBox.Should().NotBe(XRect.Empty); + bleedBox.IsZero.Should().BeTrue(); + + bleedBox = page.EffectiveBleedBoxReadOnly; + bleedBox.Should().NotBeNull(); + bleedBox.Should().NotBe(XRect.Empty); + bleedBox.IsZero.Should().BeTrue(); + + bleedBox = page.BleedBoxReadOnly; + bleedBox.Should().NotBeNull(); + bleedBox.Should().NotBe(XRect.Empty); + bleedBox.IsZero.Should().BeTrue(); + + bleedBox = page.BleedBox; + bleedBox.Should().NotBeNull(); + bleedBox.Should().NotBe(XRect.Empty); + bleedBox.IsZero.Should().BeTrue(); + + page.BleedBox = page.MediaBox; + + bleedBox = page.BleedBox; + bleedBox.Should().NotBeNull(); + bleedBox.Should().NotBe(XRect.Empty); + bleedBox.IsZero.Should().BeFalse(); + + // ----- TrimBox ----- + var trimBox = page.TrimBoxReadOnly; + trimBox.IsZero.Should().BeTrue(); + + trimBox = page.EffectiveTrimBoxReadOnly; + trimBox.Should().NotBe(XRect.Empty); + trimBox.IsZero.Should().BeFalse(); + + // Calling page.TrimBox sets "new PdfRectangle()" as TrimBox. + // For "new PdfRectangle()", IsZero is true. + trimBox = page.TrimBox; + trimBox.Should().NotBeNull(); + trimBox.Should().NotBe(XRect.Empty); + trimBox.IsZero.Should().BeTrue(); + + trimBox = page.EffectiveTrimBoxReadOnly; + trimBox.Should().NotBeNull(); + trimBox.Should().NotBe(XRect.Empty); + trimBox.IsZero.Should().BeTrue(); + + trimBox = page.TrimBoxReadOnly; + trimBox.Should().NotBeNull(); + trimBox.Should().NotBe(XRect.Empty); + trimBox.IsZero.Should().BeTrue(); + + trimBox = page.TrimBox; + trimBox.Should().NotBeNull(); + trimBox.Should().NotBe(XRect.Empty); + trimBox.IsZero.Should().BeTrue(); + + page.TrimBox = page.MediaBox; + + trimBox = page.TrimBox; + trimBox.Should().NotBeNull(); + trimBox.Should().NotBe(XRect.Empty); + trimBox.IsZero.Should().BeFalse(); + + // Get an XGraphics object for drawing on this page. + var gfx = XGraphics.FromPdfPage(page); + + // Draw two lines with a red default pen. + var width = page.Width.Point; + var height = page.Height.Point; + gfx.DrawLine(XPens.Red, 0, 0, width, height); + gfx.DrawLine(XPens.Red, width, 0, 0, height); + + // Draw a circle with a red pen which is 1.5 point thick. + var r = width / 6; + gfx.DrawEllipse(new XPen(XColors.Red, 1.5), XBrushes.White, new XRect(width / 2 - r, height / 2 - r, 2 * r, 2 * r)); + + // Create a font. + var font = new XFont("Times New Roman", 10, XFontStyleEx.BoldItalic); + +#if NET6_0_OR_GREATER + gfx.DrawString($"Hello, dotnet {Environment.Version.Major}.{Environment.Version.Minor}!", font, XBrushes.Black, + new XRect(0, 0, width, height), XStringFormats.Center); +#else + gfx.DrawString("Hello, World!", font, XBrushes.Black, + new XRect(0, 0, width, height), XStringFormats.Center); +#endif + + // Save the document... + string filename = PdfFileUtility.GetTempPdfFileName("BasicAllBoxesTest"); + document.Save(filename); + // ...and start a viewer. + PdfFileUtility.ShowDocumentIfDebugging(filename); + } } } diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/signatures/BouncyCastleSignerTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/signatures/BouncyCastleSignerTests.cs index 930e0583..4865d9a1 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/signatures/BouncyCastleSignerTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/signatures/BouncyCastleSignerTests.cs @@ -116,12 +116,24 @@ public void Sign_existing_file_Bouncy() // Do not use password literals for real certificates in source code. var certificatePassword = "Seecrit1243"; +#if NET9_0_OR_GREATER + // New API introduced with .NET 9. + // Breaking change in .NET 9: X509KeyStorageFlags.MachineKeySet is treated differently. + // We do not use X509KeyStorageFlags.MachineKeySet with .NET 9. + var certificate = X509CertificateLoader.LoadPkcs12(rawData, certificatePassword, + X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); + + var collection = X509CertificateLoader.LoadPkcs12Collection(rawData, certificatePassword, + X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); +#else + // Old API, obsolete since .NET 9. var certificate = new X509Certificate2(rawData, certificatePassword, - X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); + /*X509KeyStorageFlags.MachineKeySet |*/ X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); var collection = new X509Certificate2Collection(); - collection.Import(rawData, certificatePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); + collection.Import(rawData, certificatePassword, /*X509KeyStorageFlags.MachineKeySet |*/ X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); +#endif return (certificate, collection); } diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/signatures/DefaultSignerTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/signatures/DefaultSignerTests.cs index 58705dfb..7142ad2d 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/signatures/DefaultSignerTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/Pdf/signatures/DefaultSignerTests.cs @@ -95,7 +95,7 @@ public void Sign_new_file_with_DefaultAppearance(string certType, PdfMessageDige // Time stamping not implemented for .NET Standard or .NET Framework. // Some arbitrarily selected timestamp servers. [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://zeitstempel.dfn.de")] - [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://timestamp.sectigo.com")] + // 2025-05-19 Commented out because tests failed sporadically [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://timestamp.sectigo.com")] [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://timestamp.apple.com/ts01")] #if DEBUG [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://timestamp.digicert.com")] @@ -167,7 +167,7 @@ public void Sign_new_file_Default(string certType, PdfMessageDigestType digestTy // Time stamping not implemented for .NET Standard or .NET Framework. // Some arbitrarily selected timestamp servers. [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://zeitstempel.dfn.de")] - [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://timestamp.sectigo.com")] + // 2025-05-19 Commented out because tests failed sporadically [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://timestamp.sectigo.com")] [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://timestamp.apple.com/ts01")] #if DEBUG [InlineData("test-cert_rsa_1024", PdfMessageDigestType.SHA256, "http://timestamp.digicert.com")] @@ -391,9 +391,16 @@ static X509Certificate2 GetCertificate(string certName) // Do not use password literals for real certificates in source code. var certificatePassword = "Seecrit1243"; //@@@??? +#if NET9_0_OR_GREATER + // New API introduced with .NET 9. + var certificate = X509CertificateLoader.LoadPkcs12(rawData, certificatePassword, + X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); +#else + // Old API, obsolete since .NET 9. var certificate = new X509Certificate2(rawData, certificatePassword, - X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); + /*X509KeyStorageFlags.MachineKeySet |*/ X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); +#endif return certificate; } diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/PdfSharp.Tests.csproj b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/PdfSharp.Tests.csproj index 31dd675c..3fd160cc 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/PdfSharp.Tests.csproj +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/PdfSharp.Tests.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;net462 + net8.0;net9.0;net10.0;net462 CORE - + diff --git a/src/foundation/src/shared/src/PdfSharp.Shared/Properties/GlobalDeclarations.cs b/src/foundation/src/shared/src/PdfSharp.Shared/Properties/GlobalDeclarations.cs index 9569c891..b3191fe0 100644 --- a/src/foundation/src/shared/src/PdfSharp.Shared/Properties/GlobalDeclarations.cs +++ b/src/foundation/src/shared/src/PdfSharp.Shared/Properties/GlobalDeclarations.cs @@ -17,4 +17,4 @@ [assembly: ComVisible(false)] //[assembly: SuppressMessage("LoggingGenerator", "SYSLIB1006:Multiple logging methods cannot use the same event ID within a class", -// Justification = "We use logging event ids as documented, i.e. multiple times", Scope = "member"/*, Target = "~M:PdfSharp.Internal.Logging.LogMessages.XGraphicsCreated(Microsoft.Extensions.Logging.ILogger,System.String)"*/)] +// Justification = "We use logging event IDs as documented, i.e. multiple times", Scope = "member"/*, Target = "~M:PdfSharp.Internal.Logging.LogMessages.XGraphicsCreated(Microsoft.Extensions.Logging.ILogger,System.String)"*/)] diff --git a/src/foundation/src/shared/src/PdfSharp.Shared/System/CompilerServices.cs b/src/foundation/src/shared/src/PdfSharp.Shared/System/CompilerServices.cs index 559e8563..ab6f55c5 100644 --- a/src/foundation/src/shared/src/PdfSharp.Shared/System/CompilerServices.cs +++ b/src/foundation/src/shared/src/PdfSharp.Shared/System/CompilerServices.cs @@ -1,4 +1,4 @@ -// PDFsharp - A .NET library for processing PDF +// PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. // This file contains code from the .NET source to use some newer C# features in .NET Standard / Framework. @@ -151,8 +151,8 @@ public int Value /// Calculate the offset from the start using the giving collection length. /// The length of the collection that the Index will be used with. length has to be a positive value /// - /// For performance reason, we dont validate the input length parameter and the returned offset value against negative values. - /// we dont validate either the returned offset is greater than the input length. + /// For performance reason, we don’t validate the input length parameter and the returned offset value against negative values. + /// we don’t validate either the returned offset is greater than the input length. /// It is expected Index will be used with collections which always have non-negative length/count. If the returned offset is negative and /// then used to index a collection will get out of range exception which will be same affect as the validation. /// @@ -257,7 +257,7 @@ public override string ToString() /// Calculate the start offset and length of range object using a collection length. /// The length of the collection that the range will be used with. length has to be a positive value. /// - /// For performance reason, we dont validate the input length parameter against negative values. + /// For performance reason, we don’t validate the input length parameter against negative values. /// It is expected Range will be used with collections which always have non-negative length/count. /// We validate the range is inside the length scope though. /// diff --git a/src/foundation/src/shared/src/PdfSharp.Snippets-gdi/PdfSharp.Snippets-gdi.csproj b/src/foundation/src/shared/src/PdfSharp.Snippets-gdi/PdfSharp.Snippets-gdi.csproj index 9bde7391..443d0611 100644 --- a/src/foundation/src/shared/src/PdfSharp.Snippets-gdi/PdfSharp.Snippets-gdi.csproj +++ b/src/foundation/src/shared/src/PdfSharp.Snippets-gdi/PdfSharp.Snippets-gdi.csproj @@ -1,13 +1,14 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true PdfSharp.Snippets true TRACE;GDI True ..\..\..\..\..\StrongnameKey.snk + true diff --git a/src/foundation/src/shared/src/PdfSharp.Snippets-wpf/PdfSharp.Snippets-wpf.csproj b/src/foundation/src/shared/src/PdfSharp.Snippets-wpf/PdfSharp.Snippets-wpf.csproj index 9a1848ff..69e98b77 100644 --- a/src/foundation/src/shared/src/PdfSharp.Snippets-wpf/PdfSharp.Snippets-wpf.csproj +++ b/src/foundation/src/shared/src/PdfSharp.Snippets-wpf/PdfSharp.Snippets-wpf.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 true PdfSharp.Snippets true diff --git a/src/foundation/src/shared/src/PdfSharp.Snippets/Font/selection/DefaultConstructionSnippets.cs b/src/foundation/src/shared/src/PdfSharp.Snippets/Font/selection/DefaultConstructionSnippets.cs index a7fd6204..52ea9e2d 100644 --- a/src/foundation/src/shared/src/PdfSharp.Snippets/Font/selection/DefaultConstructionSnippets.cs +++ b/src/foundation/src/shared/src/PdfSharp.Snippets/Font/selection/DefaultConstructionSnippets.cs @@ -54,7 +54,7 @@ public class DefaultWindowsFontsSnippet : Snippet #endif #if TIMES_NEW_ROMAN - private const string FamilyName = "Times New Roman"; + const string FamilyName = "Times New Roman"; #elif SEGOE_UI const string FamilyName = "Segoe UI"; #endif @@ -442,7 +442,7 @@ public class PlatformFontConstructionSnippet : Snippet #endif #if TIMES_NEW_ROMAN - private const string FamilyName = "Times New Roman"; + const string FamilyName = "Times New Roman"; #elif SEGOE_UI const string FamilyName = "Segoe UI"; #endif diff --git a/src/foundation/src/shared/src/PdfSharp.Snippets/PdfSharp.Snippets.csproj b/src/foundation/src/shared/src/PdfSharp.Snippets/PdfSharp.Snippets.csproj index f43843c7..4b446a6f 100644 --- a/src/foundation/src/shared/src/PdfSharp.Snippets/PdfSharp.Snippets.csproj +++ b/src/foundation/src/shared/src/PdfSharp.Snippets/PdfSharp.Snippets.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;netstandard2.0 + net8.0;net9.0;net10.0;netstandard2.0 PdfSharp.Snippets PdfSharp.Snippets TRACE;CORE diff --git a/src/foundation/src/shared/src/PdfSharp.System/PdfSharp.System.csproj b/src/foundation/src/shared/src/PdfSharp.System/PdfSharp.System.csproj index e817514b..a280d2b1 100644 --- a/src/foundation/src/shared/src/PdfSharp.System/PdfSharp.System.csproj +++ b/src/foundation/src/shared/src/PdfSharp.System/PdfSharp.System.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;netstandard2.0 + net8.0;net9.0;net10.0;netstandard2.0 PdfSharp True @@ -23,7 +23,7 @@ - + diff --git a/src/foundation/src/shared/src/PdfSharp.System/Properties/GlobalDeclarations.cs b/src/foundation/src/shared/src/PdfSharp.System/Properties/GlobalDeclarations.cs index b05fbb8f..1f8cc8db 100644 --- a/src/foundation/src/shared/src/PdfSharp.System/Properties/GlobalDeclarations.cs +++ b/src/foundation/src/shared/src/PdfSharp.System/Properties/GlobalDeclarations.cs @@ -18,4 +18,4 @@ [assembly: ComVisible(false)] //[assembly: SuppressMessage("LoggingGenerator", "SYSLIB1006:Multiple logging methods cannot use the same event ID within a class", -// Justification = "We use logging event ids as documented, i.e. multiple times", Scope = "member"/*, Target = "~M:PdfSharp.Internal.Logging.LogMessages.XGraphicsCreated(Microsoft.Extensions.Logging.ILogger,System.String)"*/)] +// Justification = "We use logging event IDs as documented, i.e. multiple times", Scope = "member"/*, Target = "~M:PdfSharp.Internal.Logging.LogMessages.XGraphicsCreated(Microsoft.Extensions.Logging.ILogger,System.String)"*/)] diff --git a/src/foundation/src/shared/src/PdfSharp.System/System/CodeAnalysis.cs b/src/foundation/src/shared/src/PdfSharp.System/System/CodeAnalysis.cs index 4bc9a49c..5d147f42 100644 --- a/src/foundation/src/shared/src/PdfSharp.System/System/CodeAnalysis.cs +++ b/src/foundation/src/shared/src/PdfSharp.System/System/CodeAnalysis.cs @@ -1,3 +1,6 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + using System; namespace System.Diagnostics.CodeAnalysis diff --git a/src/foundation/src/shared/src/PdfSharp.System/extensions/SystemStringExtensions.cs b/src/foundation/src/shared/src/PdfSharp.System/extensions/SystemStringExtensions.cs index 1d77dafa..685ce093 100644 --- a/src/foundation/src/shared/src/PdfSharp.System/extensions/SystemStringExtensions.cs +++ b/src/foundation/src/shared/src/PdfSharp.System/extensions/SystemStringExtensions.cs @@ -1,4 +1,7 @@ -using System; +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/foundation/src/shared/src/PdfSharp.Testing-gdi/PdfSharp.Testing-gdi.csproj b/src/foundation/src/shared/src/PdfSharp.Testing-gdi/PdfSharp.Testing-gdi.csproj index 11d52042..d3e2a67b 100644 --- a/src/foundation/src/shared/src/PdfSharp.Testing-gdi/PdfSharp.Testing-gdi.csproj +++ b/src/foundation/src/shared/src/PdfSharp.Testing-gdi/PdfSharp.Testing-gdi.csproj @@ -1,7 +1,7 @@ - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 PdfSharp.Testing_gdi enable enable diff --git a/src/foundation/src/shared/src/PdfSharp.Testing-wpf/PdfSharp.Testing-wpf.csproj b/src/foundation/src/shared/src/PdfSharp.Testing-wpf/PdfSharp.Testing-wpf.csproj index f711666e..f255f9cd 100644 --- a/src/foundation/src/shared/src/PdfSharp.Testing-wpf/PdfSharp.Testing-wpf.csproj +++ b/src/foundation/src/shared/src/PdfSharp.Testing-wpf/PdfSharp.Testing-wpf.csproj @@ -1,7 +1,7 @@ - net6.0-windows;net8.0-windows;net462 + net8.0-windows;net9.0-windows;net10.0-windows;net462 PdfSharp.Testing_wpf enable enable diff --git a/src/foundation/src/shared/src/PdfSharp.Testing/PdfSharp.Testing.csproj b/src/foundation/src/shared/src/PdfSharp.Testing/PdfSharp.Testing.csproj index 7e807ee0..808424f0 100644 --- a/src/foundation/src/shared/src/PdfSharp.Testing/PdfSharp.Testing.csproj +++ b/src/foundation/src/shared/src/PdfSharp.Testing/PdfSharp.Testing.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;netstandard2.0 + net8.0;net9.0;net10.0;netstandard2.0 PdfSharp True @@ -17,7 +17,7 @@ --> - + diff --git a/src/foundation/src/shared/src/PdfSharp.WPFonts/PdfSharp.WPFonts.csproj b/src/foundation/src/shared/src/PdfSharp.WPFonts/PdfSharp.WPFonts.csproj index ba2d9d2f..901b466e 100644 --- a/src/foundation/src/shared/src/PdfSharp.WPFonts/PdfSharp.WPFonts.csproj +++ b/src/foundation/src/shared/src/PdfSharp.WPFonts/PdfSharp.WPFonts.csproj @@ -1,7 +1,7 @@  - net6.0;net8.0;netstandard2.0 + net8.0;net9.0;net10.0;netstandard2.0 disable True ..\..\..\..\..\StrongnameKey.snk diff --git a/src/foundation/src/shared/testapps/PdfSharp.Fonts.TestApp/PdfSharp.Fonts.TestApp.csproj b/src/foundation/src/shared/testapps/PdfSharp.Fonts.TestApp/PdfSharp.Fonts.TestApp.csproj index b1c164c3..b074f6f5 100644 --- a/src/foundation/src/shared/testapps/PdfSharp.Fonts.TestApp/PdfSharp.Fonts.TestApp.csproj +++ b/src/foundation/src/shared/testapps/PdfSharp.Fonts.TestApp/PdfSharp.Fonts.TestApp.csproj @@ -2,7 +2,7 @@ Exe - net6.0;net8.0;net462 + net8.0;net9.0;net10.0;net462 true diff --git a/src/foundation/src/shared/testapps/Shared.TestApp/Program.cs b/src/foundation/src/shared/testapps/Shared.TestApp/Program.cs index e49e7bf8..4946fb8c 100644 --- a/src/foundation/src/shared/testapps/Shared.TestApp/Program.cs +++ b/src/foundation/src/shared/testapps/Shared.TestApp/Program.cs @@ -24,21 +24,21 @@ static void Main( /*string[] args*/) //.AddFilter("System", LogLevel.Warning) //.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug) .AddFilter("", LogLevel.Debug) + .AddFilter(PdfSharpLogCategory.DocumentProcessing, LogLevel.Debug) + .AddFilter(PdfSharpLogCategory.FontManagement, LogLevel.Debug) + .AddFilter(PdfSharpLogCategory.PdfReading, LogLevel.Debug) + .AddFilter(PdfSharpLogCategory.ImageProcessing, LogLevel.Debug) //.AddFilter("PDFsharp", LogLevel.Critical) .AddConsole(); }); + LogHost.Factory = loggerFactory; ILogger logger = loggerFactory.CreateLogger(); - //logger.LogInformation("Example log message 1"); - - //LogHost.Logger.LogInformation("Example log message 2"); - - LogHost.Factory = loggerFactory; //LogHost.Logger.LogError("Something went wrong."); //LogHost.Logger.TestMessage(LogLevel.Critical, "blah"); //LogHost.Logger.TestMessage("di-blub"); - //LogHost.Logger.TestMessage("------------------------------------------------------------------------------"); + LogHost.Logger.TestMessage("------------------------------------------------------------------------------"); @@ -48,7 +48,7 @@ static void Main( /*string[] args*/) // Call some developer specific test code from a file not in the repo. // Implement your code in ProgramEx.cs in partial class Program. - var test = typeof(Program).GetMethod("Test", BindingFlags.Static| BindingFlags.NonPublic); + var test = typeof(Program).GetMethod("Test", BindingFlags.Static | BindingFlags.NonPublic); if (test != null) { test.Invoke(null, null); diff --git a/src/foundation/src/shared/testapps/Shared.TestApp/Shared.TestApp.csproj b/src/foundation/src/shared/testapps/Shared.TestApp/Shared.TestApp.csproj index 66a41c72..aa742563 100644 --- a/src/foundation/src/shared/testapps/Shared.TestApp/Shared.TestApp.csproj +++ b/src/foundation/src/shared/testapps/Shared.TestApp/Shared.TestApp.csproj @@ -2,7 +2,7 @@ Exe - net6.0;net8.0;net462 + net8.0;net9.0;net10.0;net462 true diff --git a/src/foundation/src/shared/tests/PdfSharp.Fonts.Test/PdfSharp.Fonts.Test.csproj b/src/foundation/src/shared/tests/PdfSharp.Fonts.Test/PdfSharp.Fonts.Test.csproj index 6023e4b8..cc6d7c22 100644 --- a/src/foundation/src/shared/tests/PdfSharp.Fonts.Test/PdfSharp.Fonts.Test.csproj +++ b/src/foundation/src/shared/tests/PdfSharp.Fonts.Test/PdfSharp.Fonts.Test.csproj @@ -1,7 +1,7 @@  - net6.0;net462 + net8.0;net462 diff --git a/src/foundation/src/shared/tests/Shared.Tests/BasicTests.cs b/src/foundation/src/shared/tests/Shared.Tests/BasicTests.cs index f8fcb85a..d580fb48 100644 --- a/src/foundation/src/shared/tests/Shared.Tests/BasicTests.cs +++ b/src/foundation/src/shared/tests/Shared.Tests/BasicTests.cs @@ -55,9 +55,13 @@ public void Create_Hello_World_BasicTests() // Create a font. var font = new XFont("Times New Roman", 20, XFontStyleEx.BoldItalic); - // Draw the text. - gfx.DrawString("Hello, dotnet 6.0!", font, XBrushes.Black, +#if NET6_0_OR_GREATER + gfx.DrawString($"Hello, dotnet {Environment.Version.Major}.{Environment.Version.Minor}!", font, XBrushes.Black, new XRect(0, 0, width, height), XStringFormats.Center); +#else + gfx.DrawString("Hello, World!", font, XBrushes.Black, + new XRect(0, 0, width, height), XStringFormats.Center); +#endif // Save the document... string filename = PdfFileUtility.GetTempPdfFileName("HelloWorld"); diff --git a/src/foundation/src/shared/tests/Shared.Tests/Shared.Tests.csproj b/src/foundation/src/shared/tests/Shared.Tests/Shared.Tests.csproj index 96e2c680..7df23636 100644 --- a/src/foundation/src/shared/tests/Shared.Tests/Shared.Tests.csproj +++ b/src/foundation/src/shared/tests/Shared.Tests/Shared.Tests.csproj @@ -1,24 +1,9 @@  - net6.0;net462 + net8.0;net462 True ..\..\..\..\..\StrongnameKey.snk - - - - $(DefineConstants);CORE - - - - $(DefineConstants);CORE - - - - $(DefineConstants);CORE - - - $(DefineConstants);CORE diff --git a/src/samples/src/MigraDoc/src/HelloWorld-gdi/HelloWorld,MigraDoc-gdi.csproj b/src/samples/src/MigraDoc/src/HelloWorld-gdi/HelloWorld,MigraDoc-gdi.csproj index de1c7154..cd2c3ed0 100644 --- a/src/samples/src/MigraDoc/src/HelloWorld-gdi/HelloWorld,MigraDoc-gdi.csproj +++ b/src/samples/src/MigraDoc/src/HelloWorld-gdi/HelloWorld,MigraDoc-gdi.csproj @@ -2,7 +2,7 @@ Exe - net6.0-windows;net462 + net8.0-windows;net462 true true HelloWorld_gdi diff --git a/src/samples/src/MigraDoc/src/HelloWorld-wpf/HelloWorld,MigraDoc-wpf.csproj b/src/samples/src/MigraDoc/src/HelloWorld-wpf/HelloWorld,MigraDoc-wpf.csproj index 29dc10b0..a6d0e050 100644 --- a/src/samples/src/MigraDoc/src/HelloWorld-wpf/HelloWorld,MigraDoc-wpf.csproj +++ b/src/samples/src/MigraDoc/src/HelloWorld-wpf/HelloWorld,MigraDoc-wpf.csproj @@ -2,7 +2,7 @@ Exe - net6.0-windows;net462 + net8.0-windows;net462 true true HelloWorld_wpf diff --git a/src/samples/src/MigraDoc/src/HelloWorld/HelloWorld,MigraDoc.csproj b/src/samples/src/MigraDoc/src/HelloWorld/HelloWorld,MigraDoc.csproj index c8294de1..b81b60f9 100644 --- a/src/samples/src/MigraDoc/src/HelloWorld/HelloWorld,MigraDoc.csproj +++ b/src/samples/src/MigraDoc/src/HelloWorld/HelloWorld,MigraDoc.csproj @@ -2,7 +2,7 @@ Exe - net6.0;net462 + net8.0;net462 diff --git a/src/samples/src/PDFsharp/src/HelloWorld-gdi/HelloWorld-gdi,PDFsharp.csproj b/src/samples/src/PDFsharp/src/HelloWorld-gdi/HelloWorld-gdi,PDFsharp.csproj index 27833e39..f4954fa0 100644 --- a/src/samples/src/PDFsharp/src/HelloWorld-gdi/HelloWorld-gdi,PDFsharp.csproj +++ b/src/samples/src/PDFsharp/src/HelloWorld-gdi/HelloWorld-gdi,PDFsharp.csproj @@ -2,7 +2,7 @@ Exe - net6.0-windows;net462 + net8.0-windows;net462 true true diff --git a/src/samples/src/PDFsharp/src/HelloWorld-wpf/HelloWorld-wpf,PDFsharp.csproj b/src/samples/src/PDFsharp/src/HelloWorld-wpf/HelloWorld-wpf,PDFsharp.csproj index 7a6d3f52..13ce5bb7 100644 --- a/src/samples/src/PDFsharp/src/HelloWorld-wpf/HelloWorld-wpf,PDFsharp.csproj +++ b/src/samples/src/PDFsharp/src/HelloWorld-wpf/HelloWorld-wpf,PDFsharp.csproj @@ -2,7 +2,7 @@ Exe - net6.0-windows;net462 + net8.0-windows;net462 true true diff --git a/src/samples/src/PDFsharp/src/HelloWorld/HelloWorld,PDFsharp.csproj b/src/samples/src/PDFsharp/src/HelloWorld/HelloWorld,PDFsharp.csproj index 319ff08c..3d7e7994 100644 --- a/src/samples/src/PDFsharp/src/HelloWorld/HelloWorld,PDFsharp.csproj +++ b/src/samples/src/PDFsharp/src/HelloWorld/HelloWorld,PDFsharp.csproj @@ -2,7 +2,7 @@ Exe - net6.0;net462 + net8.0;net462 HelloWorld,PDFsharp diff --git a/src/tools/src/CopyAsLink/CopyAsLink.csproj b/src/tools/src/CopyAsLink/CopyAsLink.csproj index edf7506b..43264bf1 100644 --- a/src/tools/src/CopyAsLink/CopyAsLink.csproj +++ b/src/tools/src/CopyAsLink/CopyAsLink.csproj @@ -2,7 +2,7 @@ Exe - net8.0-windows + net8.0-windows CopyAsLink true diff --git a/src/tools/src/NRT-Tests/NRT-Tests.csproj b/src/tools/src/NRT-Tests/NRT-Tests.csproj index 047bbc8a..432f1983 100644 --- a/src/tools/src/NRT-Tests/NRT-Tests.csproj +++ b/src/tools/src/NRT-Tests/NRT-Tests.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net8.0 NRT_Tests diff --git a/src/tools/src/PdfFileViewer/PdfFileViewer.csproj b/src/tools/src/PdfFileViewer/PdfFileViewer.csproj index 87e9c84f..9f950e67 100644 --- a/src/tools/src/PdfFileViewer/PdfFileViewer.csproj +++ b/src/tools/src/PdfFileViewer/PdfFileViewer.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net8.0 true true win-x64 diff --git a/src/tools/src/PdfSharp.TestHelper-gdi/PdfSharp.TestHelper-gdi.csproj b/src/tools/src/PdfSharp.TestHelper-gdi/PdfSharp.TestHelper-gdi.csproj index 91ca14ff..3061816e 100644 --- a/src/tools/src/PdfSharp.TestHelper-gdi/PdfSharp.TestHelper-gdi.csproj +++ b/src/tools/src/PdfSharp.TestHelper-gdi/PdfSharp.TestHelper-gdi.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net462 + net8.0-windows;net462 true true GDI diff --git a/src/tools/src/PdfSharp.TestHelper-wpf/PdfSharp.TestHelper-wpf.csproj b/src/tools/src/PdfSharp.TestHelper-wpf/PdfSharp.TestHelper-wpf.csproj index 54816cbd..c7a3d959 100644 --- a/src/tools/src/PdfSharp.TestHelper-wpf/PdfSharp.TestHelper-wpf.csproj +++ b/src/tools/src/PdfSharp.TestHelper-wpf/PdfSharp.TestHelper-wpf.csproj @@ -1,7 +1,7 @@  - net6.0-windows;net462 + net8.0-windows;net462 true true WPF diff --git a/src/tools/src/PdfSharp.TestHelper/PdfSharp.TestHelper.csproj b/src/tools/src/PdfSharp.TestHelper/PdfSharp.TestHelper.csproj index b203f0da..6f5be2a8 100644 --- a/src/tools/src/PdfSharp.TestHelper/PdfSharp.TestHelper.csproj +++ b/src/tools/src/PdfSharp.TestHelper/PdfSharp.TestHelper.csproj @@ -1,7 +1,7 @@  - net6.0;netstandard2.0 + net8.0;netstandard2.0