- Services/PdfRedactText.cs: strip text whose origin falls inside a CoverAnnotation from the page content stream at save time, hooked into PdfBurn.DrawAnnotationsIntoDoc. Fixes edited values staying recoverable by text extraction. - Themes/MMD.xaml replaces all thirteen themes; picker and accent strip removed; no dark mode. - Rename KillerPDF -> MMD PDF across code, resources, packaging and locale strings; new icon. - Remove the upstream author credit and the in-app install button.
134 lines
6.2 KiB
PowerShell
134 lines
6.2 KiB
PowerShell
#Requires -Version 5.1
|
|
param(
|
|
[string]$Configuration = "Release",
|
|
[switch]$KeepSymbols,
|
|
[switch]$RepackOnly,
|
|
[switch]$RequireSignature
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
Set-StrictMode -Version Latest
|
|
|
|
$projectDir = Split-Path -Parent $PSScriptRoot
|
|
$appProject = Join-Path $projectDir 'MmdPdf.csproj'
|
|
$launcherProject = Join-Path $projectDir 'Packaging\MmdPdfLauncher\MmdPdfLauncher.csproj'
|
|
$artifactRoot = Join-Path $projectDir "bin\$Configuration\net48\portable-package"
|
|
$payloadDir = Join-Path $artifactRoot 'payload'
|
|
$payloadZip = Join-Path $artifactRoot 'payload.zip'
|
|
$launcherOutput = Join-Path $artifactRoot 'launcher'
|
|
$publicDir = Join-Path $projectDir "bin\$Configuration\net48\publish"
|
|
$publicExe = Join-Path $publicDir 'MmdPdf.exe'
|
|
|
|
if (-not $RepackOnly) {
|
|
if ([IO.Directory]::Exists($artifactRoot)) { [IO.Directory]::Delete($artifactRoot, $true) }
|
|
}
|
|
if ([IO.Directory]::Exists($launcherOutput)) { [IO.Directory]::Delete($launcherOutput, $true) }
|
|
[IO.Directory]::CreateDirectory($artifactRoot) | Out-Null
|
|
[IO.Directory]::CreateDirectory($payloadDir) | Out-Null
|
|
[IO.Directory]::CreateDirectory($launcherOutput) | Out-Null
|
|
[IO.Directory]::CreateDirectory($publicDir) | Out-Null
|
|
|
|
$versionXml = [xml](Get-Content -Raw -LiteralPath $appProject)
|
|
$versionNode = $versionXml.SelectSingleNode('/Project/PropertyGroup/Version')
|
|
$version = if ($versionNode) { [string]$versionNode.InnerText } else { '' }
|
|
if (-not $version) { throw 'MmdPdf.csproj has no Version.' }
|
|
|
|
if (-not $RepackOnly) {
|
|
Write-Host "==> Building loose MmdPdf payload $version..." -ForegroundColor Cyan
|
|
& dotnet publish $appProject -c $Configuration `
|
|
-p:KillerPayloadBuild=true `
|
|
-p:PublishDir="$payloadDir\"
|
|
if ($LASTEXITCODE -ne 0) { throw 'Payload build failed.' }
|
|
|
|
if (-not $KeepSymbols) {
|
|
foreach ($symbol in [IO.Directory]::GetFiles($payloadDir, '*.pdb', [IO.SearchOption]::AllDirectories)) {
|
|
[IO.File]::Delete($symbol)
|
|
}
|
|
}
|
|
|
|
# The PDF file-type icon is a loose installed asset even though the application also embeds it.
|
|
[IO.File]::Copy((Join-Path $projectDir 'Resources\pdf-file.ico'),
|
|
(Join-Path $payloadDir 'pdf-file.ico'), $true)
|
|
} elseif (-not [IO.File]::Exists((Join-Path $payloadDir 'MmdPdf.App.exe'))) {
|
|
throw 'RepackOnly requested but the prepared payload is missing.'
|
|
}
|
|
|
|
$manifestPath = Join-Path $payloadDir 'payload.manifest'
|
|
$payloadFiles = @([IO.Directory]::GetFiles($payloadDir, '*', [IO.SearchOption]::AllDirectories) |
|
|
Where-Object { -not [string]::Equals($_, $manifestPath, [StringComparison]::OrdinalIgnoreCase) } |
|
|
Sort-Object { $_.Substring($payloadDir.Length + 1) })
|
|
$actualPayloadNames = @($payloadFiles | ForEach-Object {
|
|
$_.Substring($payloadDir.Length + 1).Replace('\', '/')
|
|
})
|
|
$expectedPayloadNames = @(Get-Content -LiteralPath (Join-Path $PSScriptRoot 'payload-files.txt') |
|
|
Where-Object { $_ -and -not $_.StartsWith('#') } | Sort-Object)
|
|
$payloadDifference = @(Compare-Object $expectedPayloadNames $actualPayloadNames)
|
|
if ($payloadDifference.Count -gt 0) {
|
|
$details = ($payloadDifference | ForEach-Object { "$($_.SideIndicator) $($_.InputObject)" }) -join [Environment]::NewLine
|
|
throw "Payload file set changed. Review dependencies and update build\payload-files.txt deliberately:`n$details"
|
|
}
|
|
foreach ($required in 'MmdPdf.App.exe', 'pdfium.dll', 'PdfSharpCore.dll', 'System.Text.Json.dll') {
|
|
if ($actualPayloadNames -notcontains $required) {
|
|
throw "Required loose payload file is missing ($required). Costura/Fody may have run accidentally."
|
|
}
|
|
}
|
|
$manifestLines = foreach ($file in $payloadFiles) {
|
|
$relative = $file.Substring($payloadDir.Length + 1).Replace('\', '/')
|
|
$hash = (Get-FileHash -LiteralPath $file -Algorithm SHA256).Hash
|
|
$size = ([IO.FileInfo]$file).Length
|
|
"$hash`t$size`t$relative"
|
|
}
|
|
[IO.File]::WriteAllLines($manifestPath, $manifestLines, [Text.UTF8Encoding]::new($false))
|
|
|
|
Write-Host "==> Compressing one verified payload..." -ForegroundColor Cyan
|
|
Add-Type -AssemblyName System.IO.Compression
|
|
if ([IO.File]::Exists($payloadZip)) { [IO.File]::Delete($payloadZip) }
|
|
$zipStream = [IO.File]::Open($payloadZip, [IO.FileMode]::CreateNew)
|
|
try {
|
|
$archive = [IO.Compression.ZipArchive]::new($zipStream, [IO.Compression.ZipArchiveMode]::Create, $false)
|
|
try {
|
|
$allFiles = @([IO.Directory]::GetFiles($payloadDir, '*', [IO.SearchOption]::AllDirectories) |
|
|
Sort-Object { $_.Substring($payloadDir.Length + 1) })
|
|
foreach ($file in $allFiles) {
|
|
$relative = $file.Substring($payloadDir.Length + 1).Replace('\', '/')
|
|
$entry = $archive.CreateEntry($relative, [IO.Compression.CompressionLevel]::Optimal)
|
|
$entry.LastWriteTime = [DateTimeOffset]::new(2020, 1, 1, 0, 0, 0, [TimeSpan]::Zero)
|
|
$input = [IO.File]::OpenRead($file)
|
|
$output = $entry.Open()
|
|
try { $input.CopyTo($output) }
|
|
finally { $output.Dispose(); $input.Dispose() }
|
|
}
|
|
}
|
|
finally { $archive.Dispose() }
|
|
}
|
|
finally { $zipStream.Dispose() }
|
|
|
|
Write-Host "==> Building the public portable launcher..." -ForegroundColor Cyan
|
|
& dotnet publish $launcherProject -c $Configuration `
|
|
-p:LauncherAssemblyName=MmdPdf `
|
|
-p:LauncherVersion=$version `
|
|
-p:LauncherIcon="$(Join-Path $projectDir 'Resources\mmd-icon.ico')" `
|
|
-p:PayloadZip="$payloadZip" `
|
|
-p:AllowUnsignedInstall="$(!$RequireSignature)" `
|
|
-p:PublishDir="$launcherOutput\"
|
|
if ($LASTEXITCODE -ne 0) { throw 'Launcher build failed.' }
|
|
|
|
$builtLauncher = Join-Path $launcherOutput 'MmdPdf.exe'
|
|
if (-not [IO.File]::Exists($builtLauncher)) { throw "Launcher output is missing: $builtLauncher" }
|
|
[IO.File]::Copy($builtLauncher, $publicExe, $true)
|
|
|
|
$payloadBytes = ([IO.FileInfo]$payloadZip).Length
|
|
$publicBytes = ([IO.FileInfo]$publicExe).Length
|
|
Write-Host " Payload files : $($payloadFiles.Count)" -ForegroundColor Green
|
|
Write-Host " Payload zip : $payloadBytes bytes" -ForegroundColor Green
|
|
Write-Host " Public EXE : $publicBytes bytes" -ForegroundColor Green
|
|
Write-Host " Output : $publicExe" -ForegroundColor Green
|
|
|
|
[pscustomobject]@{
|
|
Version = $version
|
|
PayloadFiles = $payloadFiles.Count
|
|
PayloadZipBytes = $payloadBytes
|
|
PublicExeBytes = $publicBytes
|
|
PublicExe = $publicExe
|
|
}
|