feat: rebrand to MMD PDF, single corporate theme, and remove original text under an edit

- 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.
This commit is contained in:
2026-08-27 07:37:09 +02:00
parent 532485a830
commit 6610acfa44
230 changed files with 9362 additions and 11508 deletions
+14 -14
View File
@@ -4,7 +4,7 @@ using System.IO;
using System.Text;
using System.Windows;
namespace KillerPDF.Features
namespace MmdPdf.Features
{
/// <summary>
/// Everything the About card does that is not drawing: reading the signature and release date,
@@ -21,9 +21,9 @@ namespace KillerPDF.Features
// Steve's: a fork signed by somebody else must not claim the alias, and an unsigned build
// has no subject at all. Family standard, see code/CLAUDE.md.
private const string SignerName = "Stephen Riley";
private const string AkaName = "Steve the Killer";
private const string AkaName = "MMD Steel Group IT";
private const string Repo = "https://github.com/SteveTheKiller/KillerPDF";
private const string Repo = "https://github.com/SteveTheKiller/MmdPdf";
private readonly IAboutHost _host;
@@ -109,7 +109,7 @@ namespace KillerPDF.Features
{
System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
using var http = new System.Net.Http.HttpClient { Timeout = TimeSpan.FromSeconds(4) };
http.DefaultRequestHeaders.UserAgent.ParseAdd("KillerPDF-UpdateCheck");
http.DefaultRequestHeaders.UserAgent.ParseAdd("MmdPdf-UpdateCheck");
var json = await http.GetStringAsync($"{Repo.Replace("github.com", "api.github.com/repos")}/releases/latest")
.ConfigureAwait(true);
@@ -148,13 +148,13 @@ namespace KillerPDF.Features
if (_host.IsDirty)
{
KillerDialog.Show(_host.Window, _host.Loc("Str_Dlg_SaveBeforeUpdate"),
"KillerPDF", MessageBoxButton.OK, MessageBoxImage.Warning);
"MmdPdf", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
var confirm = KillerDialog.Show(_host.Window,
string.Format(_host.Loc("Str_UpdatePrompt"), tag),
"KillerPDF", MessageBoxButton.OKCancel, MessageBoxImage.Question);
"MmdPdf", MessageBoxButton.OKCancel, MessageBoxImage.Question);
if (confirm != MessageBoxResult.OK) return;
_host.UpdateEnabled = false;
@@ -187,9 +187,9 @@ namespace KillerPDF.Features
{
System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
using var http = new System.Net.Http.HttpClient { Timeout = TimeSpan.FromSeconds(90) };
http.DefaultRequestHeaders.UserAgent.ParseAdd("KillerPDF-UpdateCheck");
http.DefaultRequestHeaders.UserAgent.ParseAdd("MmdPdf-UpdateCheck");
var exeUrl = $"{Repo}/releases/download/{tag}/KillerPDF.exe";
var exeUrl = $"{Repo}/releases/download/{tag}/MmdPdf.exe";
// Read the checksums from the release ASSET next to the exe, not from
// raw.githubusercontent at the tag. Both files are uploaded to the release
// together, so the hash can never drift from the exe the way a repo-committed
@@ -202,7 +202,7 @@ namespace KillerPDF.Features
string? expected = null;
foreach (var line in sumsTxt.Replace("\r", "").Split('\n'))
{
if (line.TrimStart().StartsWith("KillerPDF.exe", StringComparison.OrdinalIgnoreCase))
if (line.TrimStart().StartsWith("MmdPdf.exe", StringComparison.OrdinalIgnoreCase))
{
var parts = line.Split([' ', '\t'], StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 2) expected = parts[^1];
@@ -216,7 +216,7 @@ namespace KillerPDF.Features
actual = BitConverter.ToString(sha.ComputeHash(exeBytes)).Replace("-", "");
if (!actual.Equals(expected, StringComparison.OrdinalIgnoreCase)) return null;
var path = Path.Combine(Path.GetTempPath(), $"KillerPDF_update_{Guid.NewGuid():N}.exe");
var path = Path.Combine(Path.GetTempPath(), $"MmdPdf_update_{Guid.NewGuid():N}.exe");
File.WriteAllBytes(path, exeBytes);
return path;
}
@@ -233,9 +233,9 @@ namespace KillerPDF.Features
var reopen = _host.FileToReopen;
var pid = Process.GetCurrentProcess().Id;
var relArg = string.IsNullOrEmpty(reopen) ? "" : $" \"{reopen}\"";
var bat = Path.Combine(Path.GetTempPath(), $"killerpdf_update_{Guid.NewGuid():N}.bat");
var bat = Path.Combine(Path.GetTempPath(), $"mmdpdf_update_{Guid.NewGuid():N}.bat");
bool portable = App.IsPortable();
string? portableLauncher = Environment.GetEnvironmentVariable("KILLERPDF_LAUNCHER_PATH");
string? portableLauncher = Environment.GetEnvironmentVariable("MMDPDF_LAUNCHER_PATH");
bool packagedPortable = portable && !string.IsNullOrWhiteSpace(portableLauncher) && File.Exists(portableLauncher);
if (!App.VerifyAuthenticode(newExe).Valid)
@@ -252,7 +252,7 @@ namespace KillerPDF.Features
// When elevated, relaunch through explorer.exe so the app comes back at the user's
// normal integrity level rather than inheriting the elevated token. explorer.exe
// cannot forward arguments, so the currently-open file is not reopened on that
// path - a one-off convenience loss, preferred over leaving KillerPDF running as
// path - a one-off convenience loss, preferred over leaving MmdPdf running as
// administrator for the rest of the session.
var script = new StringBuilder()
.AppendLine("@echo off")
@@ -262,7 +262,7 @@ namespace KillerPDF.Features
if (packagedPortable)
{
if (int.TryParse(Environment.GetEnvironmentVariable("KILLERPDF_LAUNCHER_PID"), out int launcherPid))
if (int.TryParse(Environment.GetEnvironmentVariable("MMDPDF_LAUNCHER_PID"), out int launcherPid))
{
script.AppendLine(":waitlauncher")
.AppendLine($"tasklist /fi \"PID eq {launcherPid}\" 2>nul | find \"{launcherPid}\" >nul")
+2 -2
View File
@@ -1,4 +1,4 @@
namespace KillerPDF.Features
namespace MmdPdf.Features
{
/// <summary>
/// What AboutController needs from the window hosting it, beyond the shared shell services.
@@ -6,7 +6,7 @@ namespace KillerPDF.Features
/// Every member is a value or a plain string, never a control, so the controller holds no
/// reference to a TextBlock or a Button and can be driven by a stub in a test.
///
/// KillerPDF differs from Killendar's version in one way worth knowing: several of the About
/// MmdPdf differs from Killendar's version in one way worth knowing: several of the About
/// card's lines are built as INLINES rather than set as text - the wordmark is two differently
/// styled runs, and the tagline, version and alias each carry a hyperlink. Constructing those
/// is UI work, so it stays in the shell and the controller hands over only the strings and the