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
+32 -32
View File
@@ -16,13 +16,13 @@ using Microsoft.Win32;
using PdfSharpCore.Drawing;
using PdfSharpCore.Pdf;
using PdfSharpCore.Pdf.IO;
using KillerPDF.Services;
using MmdPdf.Services;
// CliParsePageRange moved out with the CLI runner but is used here too (Export Images'
// range box); its encoder sibling is now Services/BitmapHelpers.EncodeJpeg.
using static KillerPDF.Features.CliRunner;
using static MmdPdf.Features.CliRunner;
using PdfPigDoc = UglyToad.PdfPig.PdfDocument;
namespace KillerPDF
namespace MmdPdf
{
public partial class MainWindow
{
@@ -123,14 +123,14 @@ namespace KillerPDF
SetStatus(string.Format(Loc("Str_OpenedReadOnlyXRef"), System.IO.Path.GetFileName(path), _doc.PageCount));
KillerDialog.Show(this,
$"\"{System.IO.Path.GetFileName(path)}\" has a non-standard structure and was opened read-only.\n\nEditing, saving, and some other features may not work correctly.",
"KillerPDF", MessageBoxButton.OK, MessageBoxImage.Warning);
"MmdPdf", MessageBoxButton.OK, MessageBoxImage.Warning);
}
catch
{
// ReadOnly also failed - offer to repair.
var result = KillerDialog.Show(this,
$"This PDF has a damaged structure and couldn't be opened.\n\nWould you like KillerPDF to attempt a repair? A repaired copy will be created - the original file will not be changed.\n\nNote: repaired files may be missing bookmarks, forms, and other interactive features.",
"KillerPDF", MessageBoxButton.YesNo, MessageBoxImage.Warning);
$"This PDF has a damaged structure and couldn't be opened.\n\nWould you like MmdPdf to attempt a repair? A repaired copy will be created - the original file will not be changed.\n\nNote: repaired files may be missing bookmarks, forms, and other interactive features.",
"MmdPdf", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
TryRepairAndOpen(srcPath);
}
@@ -150,8 +150,8 @@ namespace KillerPDF
// we can't classify the damage, but the PDFium-based repair often recovers it anyway, so
// offer the repair rather than just failing outright.
var result = KillerDialog.Show(this,
"This PDF couldn't be opened - its structure may be damaged.\n\nWould you like KillerPDF to attempt a repair? A repaired copy will be created - the original file will not be changed.\n\nNote: repaired files may be missing bookmarks, forms, and other interactive features.",
"KillerPDF", MessageBoxButton.YesNo, MessageBoxImage.Warning);
"This PDF couldn't be opened - its structure may be damaged.\n\nWould you like MmdPdf to attempt a repair? A repaired copy will be created - the original file will not be changed.\n\nNote: repaired files may be missing bookmarks, forms, and other interactive features.",
"MmdPdf", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
TryRepairAndOpen(srcPath); // sets _asyncOpenPending and finalizes the tab itself
}
@@ -213,7 +213,7 @@ namespace KillerPDF
// Themed "Password Required" prompt (KillerDialog): family dialog chrome + themed PasswordBox.
private string? PromptForPassword(string filename) => KillerDialog.PromptPassword(this, filename);
// ALL direct PDFium P/Invoke lives in Services/PdfiumInterop.cs (KillerUI refactor) -
// ALL direct PDFium P/Invoke lives in Services/PdfiumInterop.cs (MmdPdfUI refactor) -
// one class, one lock (Docnet's), so the thread-safety discipline stays auditable.
// PdfFileHasEncryption and TryImportRepairToPath live in Services/PdfImport.cs.
@@ -234,7 +234,7 @@ namespace KillerPDF
bool raster = false;
// Strategy 0 (#103): lossless PDFium re-save. PDFium's tolerant parser recovers
// broken xref tables (including the dangling /Outlines entry older KillerPDF
// broken xref tables (including the dangling /Outlines entry older MmdPdf
// builds wrote) and rewrites a clean file preserving EVERYTHING - forms,
// bookmarks, text. The import-copy below drops the document-level AcroForm,
// which is what used to turn a repaired fillable form into a flat one.
@@ -267,7 +267,7 @@ namespace KillerPDF
_asyncOpenPending = false;
KillerDialog.Show(this,
"Repair failed - the file is too severely damaged to recover.\n\nTry opening the original in a different application (Adobe Acrobat, browsers) which may have additional recovery options.",
"KillerPDF", MessageBoxButton.OK, MessageBoxImage.Error);
"MmdPdf", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
@@ -284,13 +284,13 @@ namespace KillerPDF
raster
? string.Format(Loc("Str_Dlg_RepairedRaster"), System.IO.Path.GetFileName(path))
: string.Format(Loc("Str_Dlg_Repaired"), System.IO.Path.GetFileName(path)),
"KillerPDF", MessageBoxButton.OK, MessageBoxImage.None);
"MmdPdf", MessageBoxButton.OK, MessageBoxImage.None);
}
catch (Exception ex)
{
HideBusyOverlay(busy);
_asyncOpenPending = false;
KillerDialog.Show(this, Loc("Str_Err_RepairFailed") + "\n" + ex.Message, "KillerPDF",
KillerDialog.Show(this, Loc("Str_Err_RepairFailed") + "\n" + ex.Message, "MmdPdf",
MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
@@ -333,7 +333,7 @@ namespace KillerPDF
HideBusyOverlay(busy);
_asyncOpenPending = false;
KillerDialog.Show(this, Loc("Str_Err_OpenProtected") + "\n" + ex.Message,
"KillerPDF", MessageBoxButton.OK, MessageBoxImage.Error);
"MmdPdf", MessageBoxButton.OK, MessageBoxImage.Error);
EndCancellableOp();
}
}
@@ -363,7 +363,7 @@ namespace KillerPDF
{
var res = KillerDialog.Show(this,
Loc("Str_Dlg_UnsavedClose"),
"KillerPDF", MessageBoxButton.YesNo, MessageBoxImage.Warning);
"MmdPdf", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (res != MessageBoxResult.Yes) return;
}
_doc.Close();
@@ -445,7 +445,7 @@ namespace KillerPDF
{
AbortTabLoad(target, prev, createdNew);
KillerDialog.Show(this, Loc("Str_Err_NewDocFailed") + "\n" + ex.Message,
"KillerPDF", MessageBoxButton.OK, MessageBoxImage.Error);
"MmdPdf", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -478,7 +478,7 @@ namespace KillerPDF
var item = MakeMenuItem(System.IO.Path.GetFileName(path), (_, _) =>
{
if (System.IO.File.Exists(path)) OpenInNewTab(path);
else KillerDialog.Show(this, Loc("Str_Err_FileNotFound") + "\n" + path, "KillerPDF",
else KillerDialog.Show(this, Loc("Str_Err_FileNotFound") + "\n" + path, "MmdPdf",
MessageBoxButton.OK, MessageBoxImage.Warning);
});
item.ToolTip = path;
@@ -562,7 +562,7 @@ namespace KillerPDF
}
// The file-type icon lookup (per-extension cache + SHGetFileInfo) lives in
// Services/ShellIcons.cs - the same shape the KillerUI file picker uses.
// Services/ShellIcons.cs - the same shape the MmdPdfUI file picker uses.
// Fills the empty-state "Recent" list with clickable filenames (hidden when there are none).
// The start screen belongs to a PANE, so a pane filling its own list has to name itself: the
@@ -714,7 +714,7 @@ namespace KillerPDF
// through ActiveViewer. Clicking pane B's recents opened the file in pane A.
FocusPane(pane);
if (System.IO.File.Exists(path)) OpenInNewTab(path);
else KillerDialog.Show(this, Loc("Str_Err_FileNotFound") + "\n" + path, "KillerPDF",
else KillerDialog.Show(this, Loc("Str_Err_FileNotFound") + "\n" + path, "MmdPdf",
MessageBoxButton.OK, MessageBoxImage.Warning);
};
list.Items.Add(row);
@@ -800,15 +800,15 @@ namespace KillerPDF
}
catch (Exception ex)
{
KillerDialog.Show(this, Loc("Str_Err_MergeFailed") + "\n" + ex.Message, "KillerPDF", MessageBoxButton.OK, MessageBoxImage.Error);
KillerDialog.Show(this, Loc("Str_Err_MergeFailed") + "\n" + ex.Message, "MmdPdf", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
// The named-destination helpers (BuildNamedDestMap, RewriteNamedDestLinks and their
// private walkers) live in Services/PdfImport.cs (KillerUI refactor).
// private walkers) live in Services/PdfImport.cs (MmdPdfUI refactor).
// DerefItemStatic, RectNum and the pre-save scrubs live in Services/PdfScrub.cs
// (KillerUI refactor) - pure functions shared by the GUI saves, TempReload and the CLI.
// (MmdPdfUI refactor) - pure functions shared by the GUI saves, TempReload and the CLI.
// ============================================================
// Adobe page-size guard
@@ -817,8 +817,8 @@ namespace KillerPDF
// Adobe Reader only displays pages whose sides are 3-14400 points; anything outside
// that range shows "The dimensions of this page are out-of-range" and renders blank.
// Such pages usually come from images with broken DPI metadata turned into a PDF (by
// KillerPDF 1.6.1 and earlier, or by other tools). PDFium renders any size, so the
// file looks normal in KillerPDF and only fails in Adobe.
// MmdPdf 1.6.1 and earlier, or by other tools). PDFium renders any size, so the
// file looks normal in MmdPdf and only fails in Adobe.
// Min/MaxAdobePageDim live in Services/PdfImport.cs (shared with the image importer).
private static bool PageOutOfAdobeRange(PdfPage p)
@@ -838,7 +838,7 @@ namespace KillerPDF
if (PageOutOfAdobeRange(_doc.Pages[i])) bad++;
if (bad == 0) return;
var res = KillerDialog.Show(this, string.Format(Loc("Str_Dlg_PageOutOfRange"), bad),
"KillerPDF", MessageBoxButton.YesNo, MessageBoxImage.Warning);
"MmdPdf", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (res != MessageBoxResult.Yes) return;
for (int i = 0; i < _doc.PageCount; i++)
if (PageOutOfAdobeRange(_doc.Pages[i]))
@@ -971,7 +971,7 @@ namespace KillerPDF
}
catch (Exception ex)
{
KillerDialog.Show(this, Loc("Str_Err_SaveFailed") + "\n" + ex.Message, "KillerPDF", MessageBoxButton.OK, MessageBoxImage.Error);
KillerDialog.Show(this, Loc("Str_Err_SaveFailed") + "\n" + ex.Message, "MmdPdf", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -1088,7 +1088,7 @@ namespace KillerPDF
}
catch (Exception ex)
{
KillerDialog.Show(this, Loc("Str_Err_SaveFailed") + "\n" + ex.Message, "KillerPDF", MessageBoxButton.OK, MessageBoxImage.Error);
KillerDialog.Show(this, Loc("Str_Err_SaveFailed") + "\n" + ex.Message, "MmdPdf", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -1171,7 +1171,7 @@ namespace KillerPDF
}
catch (Exception ex)
{
try { KillerDialog.Show(this, Loc("Str_Err_FlattenFailed") + "\n" + ex.GetType().Name + ": " + ex.Message, "KillerPDF", MessageBoxButton.OK, MessageBoxImage.Error); }
try { KillerDialog.Show(this, Loc("Str_Err_FlattenFailed") + "\n" + ex.GetType().Name + ": " + ex.Message, "MmdPdf", MessageBoxButton.OK, MessageBoxImage.Error); }
catch { /* dialog failed; overlay still removed in finally */ }
}
finally
@@ -1207,7 +1207,7 @@ namespace KillerPDF
if (selected is null)
{
KillerDialog.Show(this, rangeErr.Length > 0 ? rangeErr : Loc("Str_InvalidRange"),
"KillerPDF", MessageBoxButton.OK, MessageBoxImage.Warning);
"MmdPdf", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
}
@@ -1284,7 +1284,7 @@ namespace KillerPDF
}
catch (Exception ex)
{
KillerDialog.Show(this, Loc("Str_Err_ExportFailed") + "\n" + ex.Message, "KillerPDF", MessageBoxButton.OK, MessageBoxImage.Error);
KillerDialog.Show(this, Loc("Str_Err_ExportFailed") + "\n" + ex.Message, "MmdPdf", MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
@@ -1430,7 +1430,7 @@ namespace KillerPDF
// Open the preview window immediately. Pages rasterize on a background thread and
// stream in via SetRenderedPage, so the window appears at once and the app stays
// responsive on large files. WPF's OS PrintDialog can't show a preview, so KillerPDF
// responsive on large files. WPF's OS PrintDialog can't show a preview, so MmdPdf
// renders it and drives printing itself.
string renderPath = printPath;
string? cleanup = tempFlattened;
@@ -1481,7 +1481,7 @@ namespace KillerPDF
}
catch (Exception ex)
{
try { KillerDialog.Show(this, Loc("Str_Err_PrintFailed") + "\n" + ex.GetType().Name + ": " + ex.Message, "KillerPDF", MessageBoxButton.OK, MessageBoxImage.Error); }
try { KillerDialog.Show(this, Loc("Str_Err_PrintFailed") + "\n" + ex.GetType().Name + ": " + ex.Message, "MmdPdf", MessageBoxButton.OK, MessageBoxImage.Error); }
catch { }
}
}