From 6610acfa44954509a109e1a7ef0781db7959df80 Mon Sep 17 00:00:00 2001 From: kua-agent Date: Thu, 27 Aug 2026 07:37:09 +0200 Subject: [PATCH] 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. --- App.xaml | 18 +- App.xaml.cs | 156 +- BuildInfo.cs | 2 +- CHANGELOG.md | 80 +- Controls/Anim.cs | 6 +- Controls/ColorPickerDialog.cs | 6 +- Controls/DialogChrome.cs | 12 +- Controls/DocumentInfoDialog.cs | 6 +- Controls/ExportImagesDialog.cs | 6 +- Controls/FileDialog.xaml | 6 +- Controls/FileDialog.xaml.cs | 6 +- Controls/FlyoutPlacement.cs | 4 +- Controls/FolderTree.cs | 2 +- Controls/KillerDialog.cs | 24 +- Controls/Picker.cs | 2 +- Controls/PickerStyles.xaml | 4 +- Controls/PrintPreviewWindow.cs | 16 +- Controls/SignDocumentDialog.cs | 14 +- Controls/StampWindow.cs | 8 +- Controls/ThumbViewportFloorConverter.cs | 2 +- Controls/TransformWindow.cs | 8 +- Controls/UiKit.cs | 4 +- Controls/Viewer/PdfViewer.Annotations.cs | 4 +- Controls/Viewer/PdfViewer.Api.cs | 2 +- Controls/Viewer/PdfViewer.Bridge.cs | 2 +- Controls/Viewer/PdfViewer.Bridge2.cs | 2 +- Controls/Viewer/PdfViewer.Crop.cs | 4 +- Controls/Viewer/PdfViewer.Forms.cs | 6 +- Controls/Viewer/PdfViewer.Links.cs | 8 +- Controls/Viewer/PdfViewer.PageSelection.cs | 4 +- Controls/Viewer/PdfViewer.Selection.cs | 4 +- Controls/Viewer/PdfViewer.TabStrip.cs | 4 +- Controls/Viewer/PdfViewer.Tabs.cs | 8 +- Controls/Viewer/PdfViewer.TabsApi.cs | 2 +- Controls/Viewer/PdfViewer.TextEditing.cs | 6 +- Controls/Viewer/PdfViewer.Viewport.cs | 4 +- Controls/Viewer/PdfViewer.Zoom.cs | 4 +- Controls/Viewer/PdfViewer.xaml | 2 +- Controls/Viewer/PdfViewer.xaml.cs | 6 +- Controls/WindowFx.cs | 2 +- FORK-NOTICE.md | 19 + Features/About/AboutController.cs | 28 +- Features/About/IAboutHost.cs | 4 +- Features/Cli/BatchRunner.cs | 12 +- Features/Cli/CliRunner.cs | 42 +- Features/IShellServices.cs | 2 +- Features/Ocr/IOcrHost.cs | 2 +- Features/Ocr/OcrController.cs | 24 +- Features/Search/ISearchHost.cs | 2 +- Features/Search/SearchController.cs | 6 +- Features/Viewer/IViewerHost.cs | 4 +- Features/Viewer/MainWindowTabStubs.cs | 2 +- Features/Viewer/MainWindowViewerBridge.cs | 2 +- Features/Viewer/MainWindowViewerElements.cs | 4 +- Features/Viewer/MainWindowViewerHost.cs | 6 +- Features/Viewer/MainWindowViewerStubs.cs | 2 +- MainWindow.xaml | 204 +- MainWindow.xaml.cs | 6 +- .../AnnotationRotateTests.cs | 4 +- .../FlyoutPlacementTests.cs | 2 +- .../LocalizationParityTests.cs | 2 +- .../MmdPdf.Tests.csproj | 2 +- .../OcrCatalogTests.cs | 12 +- .../OutlineDestinationTests.cs | 2 +- .../PdfBurnRotationTests.cs | 4 +- .../PdfFontStyleTests.cs | 4 +- .../PdfScrubTests.cs | 4 +- .../PdfTextSizeTests.cs | 2 +- .../PerspectiveWarpTests.cs | 4 +- .../ProtocolRegistrarTests.cs | 12 +- .../SearchServiceTests.cs | 4 +- .../ShortcutTableTests.cs | 4 +- .../SignatureStoreTests.cs | 4 +- .../TextFormatterTests.cs | 6 +- .../TextRunServiceTests.cs | 4 +- .../WheelPageFlipGateTests.cs | 4 +- KillerPDF.csproj => MmdPdf.csproj | 26 +- KillerPDF.pdf => MmdPdf.pdf | Bin KillerPDF.sln => MmdPdf.sln | 4 +- Models/EditingTypes.cs | 2 +- Models/LinkTypes.cs | 2 +- Models/PageThumbnailVm.cs | 4 +- Models/StampModels.cs | 2 +- Models/UndoTypes.cs | 6 +- Models/ViewTypes.cs | 8 +- Models/ViewerState.cs | 4 +- .../MmdPdfLauncher.csproj} | 2 +- .../Program.cs | 28 +- .../app.manifest | 2 +- README.md | 50 +- Resources/kp-icon.ico | Bin 42200 -> 0 bytes Resources/kp-icon.png | Bin 20471 -> 0 bytes Resources/mmd-icon.ico | Bin 0 -> 105861 bytes Resources/mmd-icon.png | Bin 0 -> 3942 bytes Services/AnnotationRotate.cs | 2 +- Services/BitmapHelpers.cs | 6 +- Services/CmapCoverage.cs | 2 +- Services/CrashReporter.cs | 8 +- Services/FontCoverage.cs | 2 +- Services/KeyLayout.cs | 2 +- Services/LocaleManager.cs | 6 +- Services/OcrCatalog.cs | 8 +- Services/OcrLanguages.cs | 6 +- Services/OcrNativeBootstrap.cs | 10 +- Services/OcrService.cs | 2 +- Services/PdfBurn.cs | 41 +- Services/PdfFontStyle.cs | 2 +- Services/PdfFonts.cs | 2 +- Services/PdfImages.cs | 2 +- Services/PdfImport.cs | 4 +- Services/PdfOutlines.cs | 4 +- Services/PdfRasterize.cs | 4 +- Services/PdfRedactText.cs | 211 + Services/PdfScrub.cs | 6 +- Services/PdfiumInterop.cs | 8 +- Services/PerspectiveWarp.cs | 2 +- Services/ProtocolRegistrar.cs | 10 +- Services/SearchService.cs | 2 +- Services/ShellIcons.cs | 4 +- Services/ShortcutTable.cs | 4 +- Services/SignatureStore.cs | 4 +- Services/Signing/ICertificateProvider.cs | 2 +- Services/Signing/KillerCmsSigner.cs | 2 +- Services/Signing/PdfSigner.cs | 4 +- .../Signing/PfxFileCertificateProvider.cs | 2 +- Services/Signing/WindowsCertificateStore.cs | 2 +- Services/StartupTrace.cs | 8 +- Services/TextRunService.cs | 2 +- Services/ThemeManager.cs | 34 +- Services/WheelPageFlipGate.cs | 2 +- Shell/About.cs | 12 +- Shell/AnnotationBars.cs | 4 +- Shell/AppScale.cs | 2 +- Shell/ContextMenu.cs | 6 +- Shell/DirtyTracking.cs | 6 +- Shell/DragDrop.cs | 8 +- Shell/ExternalOpen.cs | 8 +- Shell/FileOperations.cs | 64 +- Shell/FullScreen.cs | 4 +- Shell/ImportAndZip.cs | 24 +- Shell/KeyboardMapOverlay.cs | 6 +- Shell/KeyboardShortcuts.cs | 8 +- Shell/Ocr.cs | 16 +- Shell/PageOperations.cs | 14 +- Shell/PaneDrag.cs | 4 +- Shell/RailFlyouts.cs | 26 +- Shell/Rotate.cs | 6 +- Shell/Search.cs | 6 +- Shell/SettingsPanel.cs | 276 +- Shell/Shapes.cs | 2 +- Shell/ShortcutsOverlay.cs | 2 +- Shell/SidebarLayout.cs | 216 +- Shell/SidebarOutline.cs | 6 +- Shell/Signing.cs | 10 +- Shell/SplitPane.cs | 4 +- Shell/Stamps.cs | 4 +- Shell/SystemMenu.cs | 10 +- Shell/TempReload.cs | 4 +- Shell/TextSettingsBar.cs | 8 +- Shell/ToolSelection.cs | 4 +- Shell/WindowChrome.cs | 6 +- Strings/bn.xaml | 54 +- Strings/cs-CZ.xaml | 54 +- Strings/de-DE.xaml | 54 +- Strings/en-US.xaml | 52 +- Strings/es.xaml | 54 +- Strings/fr-FR.xaml | 54 +- Strings/hu-HU.xaml | 54 +- Strings/ja-JP.xaml | 50 +- Strings/pl-PL.xaml | 54 +- Strings/tr-TR.xaml | 54 +- Strings/zh-CN.xaml | 54 +- Strings/zh-TW.xaml | 54 +- TRANSLATING.md | 6 +- Themes/98SE.xaml | 586 --- Themes/Accents/98SE/Blue.xaml | 5 - Themes/Accents/98SE/Green.xaml | 5 - Themes/Accents/98SE/Orange.xaml | 5 - Themes/Accents/98SE/Purple.xaml | 5 - Themes/Accents/98SE/Red.xaml | 5 - Themes/Accents/98SE/Teal.xaml | 5 - Themes/Accents/Black/Blue.xaml | 26 - Themes/Accents/Black/Orange.xaml | 27 - Themes/Accents/Black/Purple.xaml | 26 - Themes/Accents/Black/Red.xaml | 27 - Themes/Accents/Black/Teal.xaml | 26 - Themes/Accents/Dark/Blue.xaml | 26 - Themes/Accents/Dark/Orange.xaml | 28 - Themes/Accents/Dark/Purple.xaml | 26 - Themes/Accents/Dark/Red.xaml | 25 - Themes/Accents/Dark/Teal.xaml | 25 - Themes/Accents/Light/Blue.xaml | 26 - Themes/Accents/Light/Orange.xaml | 26 - Themes/Accents/Light/Purple.xaml | 26 - Themes/Accents/Light/Red.xaml | 26 - Themes/Accents/Light/Teal.xaml | 26 - Themes/Black.xaml | 106 - Themes/Blood.xaml | 93 - Themes/Cyanotic.xaml | 91 - Themes/Dark.xaml | 103 - Themes/Decay.xaml | 103 - Themes/Delirium.xaml | 103 - Themes/Ectoplasm.xaml | 103 - Themes/Greed.xaml | 91 - Themes/Light.xaml | 97 - Themes/MMD.xaml | 105 + Themes/Malaise.xaml | 103 - Themes/Mourning.xaml | 105 - Themes/Sepulchre.xaml | 106 - app.manifest | 2 +- build/build-portable.ps1 | 20 +- build/measure-startup.ps1 | 14 +- build/payload-files.txt | 4 +- choco/{killerpdf.nuspec => mmdpdf.nuspec} | 20 +- choco/tools/chocolateyInstall.ps1 | 12 +- choco/tools/chocolateyUninstall.ps1 | 4 +- release.ps1 | 64 +- .../Drawing.Layout/XTextFormatter.cs | 932 ++-- .../Drawing.Pdf/XGraphicsPdfRenderer.cs | 3602 +++++++-------- third_party/PdfSharpCore/Drawing/XGraphics.cs | 3964 ++++++++--------- .../Pdf.Advanced/PdfExtGStateTable.cs | 224 +- third_party/PdfSharpCore/Pdf.IO/PdfReader.cs | 1264 +++--- third_party/PdfSharpCore/Pdf.IO/PdfWriter.cs | 1312 +++--- third_party/PdfSharpCore/Pdf/PdfDocument.cs | 1984 ++++----- third_party/PdfSharpCore/Pdf/PdfPage.cs | 2056 ++++----- third_party/PdfSharpCore/PdfSharpCore.csproj | 128 +- third_party/PdfSharpCore/VENDORED.txt | 2 +- validation/Compare-VeraPDF.ps1 | 8 +- validation/QpdfSweep.ps1 | 4 +- validation/RESULTS.md | 30 +- 230 files changed, 9362 insertions(+), 11508 deletions(-) create mode 100644 FORK-NOTICE.md rename {KillerPDF.Tests => MmdPdf.Tests}/AnnotationRotateTests.cs (98%) rename {KillerPDF.Tests => MmdPdf.Tests}/FlyoutPlacementTests.cs (97%) rename {KillerPDF.Tests => MmdPdf.Tests}/LocalizationParityTests.cs (99%) rename KillerPDF.Tests/KillerPDF.Tests.csproj => MmdPdf.Tests/MmdPdf.Tests.csproj (98%) rename {KillerPDF.Tests => MmdPdf.Tests}/OcrCatalogTests.cs (91%) rename {KillerPDF.Tests => MmdPdf.Tests}/OutlineDestinationTests.cs (99%) rename {KillerPDF.Tests => MmdPdf.Tests}/PdfBurnRotationTests.cs (99%) rename {KillerPDF.Tests => MmdPdf.Tests}/PdfFontStyleTests.cs (95%) rename {KillerPDF.Tests => MmdPdf.Tests}/PdfScrubTests.cs (94%) rename {KillerPDF.Tests => MmdPdf.Tests}/PdfTextSizeTests.cs (99%) rename {KillerPDF.Tests => MmdPdf.Tests}/PerspectiveWarpTests.cs (95%) rename {KillerPDF.Tests => MmdPdf.Tests}/ProtocolRegistrarTests.cs (54%) rename {KillerPDF.Tests => MmdPdf.Tests}/SearchServiceTests.cs (96%) rename {KillerPDF.Tests => MmdPdf.Tests}/ShortcutTableTests.cs (99%) rename {KillerPDF.Tests => MmdPdf.Tests}/SignatureStoreTests.cs (97%) rename {KillerPDF.Tests => MmdPdf.Tests}/TextFormatterTests.cs (96%) rename {KillerPDF.Tests => MmdPdf.Tests}/TextRunServiceTests.cs (95%) rename {KillerPDF.Tests => MmdPdf.Tests}/WheelPageFlipGateTests.cs (96%) rename KillerPDF.csproj => MmdPdf.csproj (91%) rename KillerPDF.pdf => MmdPdf.pdf (100%) rename KillerPDF.sln => MmdPdf.sln (91%) rename Packaging/{KillerLauncher/KillerLauncher.csproj => MmdPdfLauncher/MmdPdfLauncher.csproj} (95%) rename Packaging/{KillerLauncher => MmdPdfLauncher}/Program.cs (95%) rename Packaging/{KillerLauncher => MmdPdfLauncher}/app.manifest (91%) delete mode 100644 Resources/kp-icon.ico delete mode 100644 Resources/kp-icon.png create mode 100644 Resources/mmd-icon.ico create mode 100644 Resources/mmd-icon.png create mode 100644 Services/PdfRedactText.cs delete mode 100644 Themes/98SE.xaml delete mode 100644 Themes/Accents/98SE/Blue.xaml delete mode 100644 Themes/Accents/98SE/Green.xaml delete mode 100644 Themes/Accents/98SE/Orange.xaml delete mode 100644 Themes/Accents/98SE/Purple.xaml delete mode 100644 Themes/Accents/98SE/Red.xaml delete mode 100644 Themes/Accents/98SE/Teal.xaml delete mode 100644 Themes/Accents/Black/Blue.xaml delete mode 100644 Themes/Accents/Black/Orange.xaml delete mode 100644 Themes/Accents/Black/Purple.xaml delete mode 100644 Themes/Accents/Black/Red.xaml delete mode 100644 Themes/Accents/Black/Teal.xaml delete mode 100644 Themes/Accents/Dark/Blue.xaml delete mode 100644 Themes/Accents/Dark/Orange.xaml delete mode 100644 Themes/Accents/Dark/Purple.xaml delete mode 100644 Themes/Accents/Dark/Red.xaml delete mode 100644 Themes/Accents/Dark/Teal.xaml delete mode 100644 Themes/Accents/Light/Blue.xaml delete mode 100644 Themes/Accents/Light/Orange.xaml delete mode 100644 Themes/Accents/Light/Purple.xaml delete mode 100644 Themes/Accents/Light/Red.xaml delete mode 100644 Themes/Accents/Light/Teal.xaml delete mode 100644 Themes/Black.xaml delete mode 100644 Themes/Blood.xaml delete mode 100644 Themes/Cyanotic.xaml delete mode 100644 Themes/Dark.xaml delete mode 100644 Themes/Decay.xaml delete mode 100644 Themes/Delirium.xaml delete mode 100644 Themes/Ectoplasm.xaml delete mode 100644 Themes/Greed.xaml delete mode 100644 Themes/Light.xaml create mode 100644 Themes/MMD.xaml delete mode 100644 Themes/Malaise.xaml delete mode 100644 Themes/Mourning.xaml delete mode 100644 Themes/Sepulchre.xaml rename choco/{killerpdf.nuspec => mmdpdf.nuspec} (78%) diff --git a/App.xaml b/App.xaml index 1ece774..8bd8211 100644 --- a/App.xaml +++ b/App.xaml @@ -1,12 +1,12 @@ - + xmlns:local="clr-namespace:MmdPdf"> - + Segoe UI, Microsoft JhengHei UI, Nirmala UI - - ./Fonts/#Typewriter - a602 (dead postman 2004) ./Fonts/#Typewriter - a602 (dead postman 2004) @@ -158,7 +158,7 @@ ran 139 / 157 / 174 / 188 against an unshadowed 220, so it was still at ~85% of its travel when the window edge cut it off. Blur 16 (the family value) completes the falloff inside 8px. If the gutter is ever widened, the blur can grow with it. - Opacity stays at 0.78 rather than the family 0.6: KillerPDF's card is usually + Opacity stays at 0.78 rather than the family 0.6: MmdPdf's card is usually filled edge to edge by a WHITE page, so the boundary is a near-full-range value jump and the family opacity is swallowed by it - the right gutter needs more depth, and a lower opacity left a hard edge on the gradient. (2026-07-31) --> diff --git a/App.xaml.cs b/App.xaml.cs index 06b8c78..0e6545a 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -15,10 +15,10 @@ using System.Windows.Input; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Threading; -using KillerPDF.Services; +using MmdPdf.Services; using Microsoft.Win32; -namespace KillerPDF +namespace MmdPdf { public partial class App : Application { @@ -26,15 +26,15 @@ namespace KillerPDF // Paths // ============================================================ - private static readonly string AppName = "KillerPDF"; - // The public portable file remains KillerPDF.exe. Once installed, shortcuts launch the + private static readonly string AppName = "MmdPdf"; + // The public portable file remains MmdPdf.exe. Once installed, shortcuts launch the // loose-file application directly so installed startup never pays launcher/extraction cost. - private static readonly string ExeName = "KillerPDF.App.exe"; + private static readonly string ExeName = "MmdPdf.App.exe"; private static readonly string InstallDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", AppName); private static readonly string InstallExe = Path.Combine(InstallDir, ExeName); - private static readonly string LegacyUserInstallExe = Path.Combine(InstallDir, "KillerPDF.exe"); + private static readonly string LegacyUserInstallExe = Path.Combine(InstallDir, "MmdPdf.exe"); private static readonly string FileIconPath = Path.Combine(InstallDir, "pdf-file.ico"); private static readonly string StartMenuDir = Path.Combine( @@ -49,7 +49,7 @@ namespace KillerPDF private static readonly string MachineInstallDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), AppName); private static readonly string MachineInstallExe = Path.Combine(MachineInstallDir, ExeName); - private static readonly string LegacyMachineInstallExe = Path.Combine(MachineInstallDir, "KillerPDF.exe"); + private static readonly string LegacyMachineInstallExe = Path.Combine(MachineInstallDir, "MmdPdf.exe"); private static readonly string MachineFileIconPath = Path.Combine(MachineInstallDir, "pdf-file.ico"); private static readonly string MachineStartMenuDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms), AppName); @@ -148,7 +148,7 @@ namespace KillerPDF // Headless CLI commands (see Features/Cli/CliRunner.cs; --batch-resave in // BatchRunner.cs). Checked before the single-instance mutex so CLI runs work // while a GUI instance is open, never forward to it, and never show a window. - if (KillerPDF.Features.CliRunner.TryRunCli(e.Args, out int cliExit)) + if (MmdPdf.Features.CliRunner.TryRunCli(e.Args, out int cliExit)) { Shutdown(cliExit); return; @@ -206,8 +206,8 @@ namespace KillerPDF // Single-instance IPC (mutex + named pipe) // ============================================================ - private const string MutexName = @"Local\KillerPDF.SingleInstance"; - private const string PipeName = "KillerPDF.OpenPipe"; + private const string MutexName = @"Local\MmdPdf.SingleInstance"; + private const string PipeName = "MmdPdf.OpenPipe"; private Mutex? _instanceMutex; private void StartPipeServer() @@ -215,7 +215,7 @@ namespace KillerPDF var t = new System.Threading.Thread(RunPipeServer) { IsBackground = true, - Name = "KillerPDF-IPC", + Name = "MmdPdf-IPC", }; t.Start(); } @@ -355,7 +355,7 @@ namespace KillerPDF var win = new Window { - Title = CrashText("Str_Crash_Title", "KillerPDF - Unexpected Error"), + Title = CrashText("Str_Crash_Title", "MmdPdf - Unexpected Error"), Width = 680, Height = 520, MinWidth = 480, @@ -388,7 +388,7 @@ namespace KillerPDF titleBar.Children.Add(xBtn); titleBar.Children.Add(new TextBlock { - Text = CrashText("Str_Crash_Title", "KillerPDF - Unexpected Error"), + Text = CrashText("Str_Crash_Title", "MmdPdf - Unexpected Error"), Foreground = dimText, FontSize = 12, VerticalAlignment = VerticalAlignment.Center, @@ -517,7 +517,7 @@ namespace KillerPDF $"```\n{stack}\n```\n\n" + $"_Log folder: `{CrashReporter.LogDir}`_"); Process.Start(new ProcessStartInfo( - $"https://github.com/SteveTheKiller/KillerPDF/issues/new?title={title}&body={body}") + $"https://github.com/SteveTheKiller/MmdPdf/issues/new?title={title}&body={body}") { UseShellExecute = true }); } catch { } @@ -628,7 +628,7 @@ namespace KillerPDF { var sb = new StringBuilder(); var ver = Assembly.GetExecutingAssembly().GetName().Version; - sb.AppendLine($"KillerPDF v{ver?.ToString(3)}"); + sb.AppendLine($"MmdPdf v{ver?.ToString(3)}"); sb.AppendLine($"Time : {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); sb.AppendLine($"OS : {Environment.OSVersion}"); sb.AppendLine(); @@ -654,11 +654,11 @@ namespace KillerPDF catch { return false; } } - /// True when KillerPDF is already installed machine-wide. + /// True when MmdPdf is already installed machine-wide. internal static bool MachineInstallExists() => File.Exists(MachineInstallExe) || File.Exists(LegacyMachineInstallExe); - /// True when KillerPDF is already installed for the current user. + /// True when MmdPdf is already installed for the current user. internal static bool UserInstallExists() => File.Exists(InstallExe) || File.Exists(LegacyUserInstallExe); @@ -678,7 +678,7 @@ namespace KillerPDF if (!runningMachine && !runningUser) return; string other = runningMachine ? "per-user" : "all-users"; - if (MessageBox.Show($"KillerPDF is installed twice. Remove the other {other} copy now?\n\nYour settings will not be removed.", + if (MessageBox.Show($"MmdPdf is installed twice. Remove the other {other} copy now?\n\nYour settings will not be removed.", $"{AppName} installation conflict", MessageBoxButton.YesNo, MessageBoxImage.Warning) != MessageBoxResult.Yes) return; if (runningMachine) @@ -706,15 +706,15 @@ namespace KillerPDF try { Directory.Delete(MachineStartMenuDir, recursive: false); } catch { } UnregisterFileHandler(Registry.LocalMachine); Services.ProtocolRegistrar.Unregister(Registry.LocalMachine); - try { Registry.LocalMachine.DeleteSubKeyTree(@"Software\KillerPDF"); } catch { } + try { Registry.LocalMachine.DeleteSubKeyTree(@"Software\MmdPdf"); } catch { } try { Registry.LocalMachine.DeleteSubKeyTree( - @"Software\Microsoft\Windows\CurrentVersion\Uninstall\KillerPDF"); } catch { } + @"Software\Microsoft\Windows\CurrentVersion\Uninstall\MmdPdf"); } catch { } try { if (Directory.Exists(MachineInstallDir)) Directory.Delete(MachineInstallDir, true); } catch { } SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero); } /// - /// Installs KillerPDF, offers to set it as the default PDF handler, then relaunches from + /// Installs MmdPdf, offers to set it as the default PDF handler, then relaunches from /// the installed location. Returns false if the install did not happen, so the caller can /// put the portable badge back rather than leaving the user with a half-finished state. /// @@ -730,8 +730,8 @@ namespace KillerPDF { KillerDialog.Show(Current.MainWindow, Current.TryFindResource("Str_Dlg_OneInstallOnly") as string ?? - "KillerPDF is already installed for everyone on this computer. Update that installation, or uninstall it before choosing a per-user install. KillerPDF will not create two installed copies.", - Current.TryFindResource("Str_Dlg_InstallTitle") as string ?? "Install KillerPDF", + "MmdPdf is already installed for everyone on this computer. Update that installation, or uninstall it before choosing a per-user install. MmdPdf will not create two installed copies.", + Current.TryFindResource("Str_Dlg_InstallTitle") as string ?? "Install MmdPdf", MessageBoxButton.OK, MessageBoxImage.Information); return false; } @@ -770,7 +770,7 @@ namespace KillerPDF // directly, the same way Uninstall() does. var res = KillerDialog.Show(null, Current.TryFindResource("Str_Dlg_SetDefaultPdfMsg") as string - ?? "Would you like to set KillerPDF as your default PDF viewer?", + ?? "Would you like to set MmdPdf as your default PDF viewer?", AppName, MessageBoxButton.YesNo); if (res == MessageBoxResult.Yes) Process.Start(new ProcessStartInfo("ms-settings:defaultapps") @@ -793,7 +793,7 @@ namespace KillerPDF { try { - string? path = Environment.GetEnvironmentVariable("KILLERPDF_LAUNCHER_PATH"); + string? path = Environment.GetEnvironmentVariable("MMDPDF_LAUNCHER_PATH"); return !string.IsNullOrWhiteSpace(path) && File.Exists(path) ? Path.GetFullPath(path) : null; } catch { return null; } @@ -846,13 +846,13 @@ namespace KillerPDF try { if (Directory.Exists(InstallDir)) Directory.Delete(InstallDir, true); } catch { } try { - using var key = Registry.CurrentUser.OpenSubKey(@"Software\KillerPDF", writable: true); + using var key = Registry.CurrentUser.OpenSubKey(@"Software\MmdPdf", writable: true); key?.DeleteValue("Installed", throwOnMissingValue: false); key?.DeleteValue("InstallPath", throwOnMissingValue: false); } catch { } try { Registry.CurrentUser.DeleteSubKeyTree( - @"Software\Microsoft\Windows\CurrentVersion\Uninstall\KillerPDF", + @"Software\Microsoft\Windows\CurrentVersion\Uninstall\MmdPdf", throwOnMissingSubKey: false); } catch { } } @@ -865,7 +865,7 @@ namespace KillerPDF /// Machine-wide install. Runs elevated with no UI by definition, so the exit code is the /// only signal a deployment tool - or RunElevatedSilentInstall - gets back. /// - /// File associations are registered in HKLM so every account sees KillerPDF in Open With + /// File associations are registered in HKLM so every account sees MmdPdf in Open With /// and Default apps. Windows still leaves the actual default choice to each user. /// private static void DoSilentInstall() @@ -914,19 +914,19 @@ namespace KillerPDF /// internal static readonly string TempDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "KillerPDF", "Temp"); + "MmdPdf", "Temp"); private static readonly List _sessionTemps = []; /// - /// Creates a tracked temp path of the form killerpdf_<tag>_<guid>.pdf - /// under %LOCALAPPDATA%\KillerPDF\Temp\. + /// Creates a tracked temp path of the form mmdpdf_<tag>_<guid>.pdf + /// under %LOCALAPPDATA%\MmdPdf\Temp\. /// All registered paths are deleted when CleanupSessionTemps() is called. /// internal static string MakeTempFile(string tag) { try { Directory.CreateDirectory(TempDir); } catch { } - var path = Path.Combine(TempDir, $"killerpdf_{tag}_{Guid.NewGuid():N}.pdf"); + var path = Path.Combine(TempDir, $"mmdpdf_{tag}_{Guid.NewGuid():N}.pdf"); lock (_sessionTemps) _sessionTemps.Add(path); return path; } @@ -943,7 +943,7 @@ namespace KillerPDF } /// - /// Deletes killerpdf_*.pdf files left over from previous crashed sessions. + /// Deletes mmdpdf_*.pdf files left over from previous crashed sessions. /// Sweeps both the current TempDir and the legacy %TEMP% location. /// Locked files (still open by another instance) are silently skipped. /// @@ -953,7 +953,7 @@ namespace KillerPDF try { if (Directory.Exists(TempDir)) - foreach (var f in Directory.GetFiles(TempDir, "killerpdf_*.pdf")) + foreach (var f in Directory.GetFiles(TempDir, "mmdpdf_*.pdf")) try { File.Delete(f); } catch { } } catch { } @@ -961,7 +961,7 @@ namespace KillerPDF // Legacy %TEMP% location - sweep once for users upgrading from older builds try { - foreach (var f in Directory.GetFiles(Path.GetTempPath(), "killerpdf_*.pdf")) + foreach (var f in Directory.GetFiles(Path.GetTempPath(), "mmdpdf_*.pdf")) try { File.Delete(f); } catch { } } catch { } @@ -971,7 +971,7 @@ namespace KillerPDF { try { - using var key = Registry.CurrentUser.OpenSubKey(@"Software\KillerPDF\Settings"); + using var key = Registry.CurrentUser.OpenSubKey(@"Software\MmdPdf\Settings"); return key?.GetValue(name) as string; } catch { return null; } @@ -981,7 +981,7 @@ namespace KillerPDF { try { - using var key = Registry.CurrentUser.CreateSubKey(@"Software\KillerPDF\Settings"); + using var key = Registry.CurrentUser.CreateSubKey(@"Software\MmdPdf\Settings"); key.SetValue(name, value); } catch { /* best-effort */ } @@ -991,23 +991,23 @@ namespace KillerPDF { try { - using var key = Registry.CurrentUser.OpenSubKey(@"Software\KillerPDF\Settings", writable: true); + using var key = Registry.CurrentUser.OpenSubKey(@"Software\MmdPdf\Settings", writable: true); key?.DeleteValue(name, throwOnMissingValue: false); } catch { /* best-effort */ } } /// - /// Wipes all persisted KillerPDF state: settings (registry), downloaded OCR language packs, the + /// Wipes all persisted MmdPdf state: settings (registry), downloaded OCR language packs, the /// native OCR cache, and temp files. Best-effort - files locked this session (e.g. loaded native /// DLLs) are skipped and clear on the next restart. The user's actual PDFs are never touched. /// internal static void ClearAllData() { - try { Registry.CurrentUser.DeleteSubKeyTree(@"Software\KillerPDF\Settings", throwOnMissingSubKey: false); } catch { } + try { Registry.CurrentUser.DeleteSubKeyTree(@"Software\MmdPdf\Settings", throwOnMissingSubKey: false); } catch { } string localKp = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "KillerPDF"); + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MmdPdf"); TryDeleteDir(Path.Combine(localKp, "tessdata")); // downloaded language packs + bundled English TryDeleteDir(Path.Combine(localKp, "ocr")); // native Tesseract cache TryDeleteDir(TempDir); // temp working files @@ -1015,7 +1015,7 @@ namespace KillerPDF // Legacy temp PDFs that may linger in %TEMP%. try { - foreach (var f in Directory.GetFiles(Path.GetTempPath(), "killerpdf_*.pdf")) + foreach (var f in Directory.GetFiles(Path.GetTempPath(), "mmdpdf_*.pdf")) try { File.Delete(f); } catch { } } catch { } @@ -1079,7 +1079,7 @@ namespace KillerPDF private static bool IsInstalled() { - using var key = Registry.CurrentUser.OpenSubKey(@"Software\KillerPDF"); + using var key = Registry.CurrentUser.OpenSubKey(@"Software\MmdPdf"); if (key is null) return false; return key.GetValue("Installed") is int i && i == 1; } @@ -1089,7 +1089,7 @@ namespace KillerPDF using var key = Registry.CurrentUser.OpenSubKey( @"Software\Microsoft\Windows\Shell\Associations\FileAssociations\.pdf\UserChoice"); return key?.GetValue("ProgId") is string progId && - progId.Equals("KillerPDF.pdf", StringComparison.OrdinalIgnoreCase); + progId.Equals("MmdPdf.pdf", StringComparison.OrdinalIgnoreCase); } // ============================================================ @@ -1215,7 +1215,7 @@ namespace KillerPDF { Text = alreadyInstalled ? "A newer version is available. Install it or run without updating." - : "Install KillerPDF on this computer, or run it without installing.", + : "Install MmdPdf on this computer, or run it without installing.", Foreground = Brushes.White, TextWrapping = TextWrapping.Wrap, Margin = new Thickness(0, 0, 0, 16) @@ -1427,7 +1427,7 @@ namespace KillerPDF var titleText = new TextBlock { - Text = $"About KillerPDF", + Text = $"About MmdPdf", Foreground = fg, VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(12, 0, 0, 0), FontSize = 13, FontWeight = FontWeights.SemiBold }; @@ -1503,7 +1503,7 @@ namespace KillerPDF }; var cardContent = new StackPanel(); cardContent.Children.Add(MakeRow("VERSION", $"v{version}", fgDim, accent, - onClick: () => OpenUrl($"https://github.com/SteveTheKiller/KillerPDF/releases/tag/v{version}"))); + onClick: () => OpenUrl($"https://github.com/SteveTheKiller/MmdPdf/releases/tag/v{version}"))); cardContent.Children.Add(MakeRow("PUBLISHER", sigInfo, fgDim, fg)); cardContent.Children.Add(MakeRow("THUMBPRINT", thumbInfo, fgDim, fg, mono, wrap: true)); cardContent.Children.Add(MakeRow("EXE SHA256", sha256, fgDim, fg, mono, wrap: true)); @@ -1521,9 +1521,9 @@ namespace KillerPDF okBtn.Margin = new Thickness(0, 12, 0, 0); okBtn.Click += (_, __) => dlg!.Close(); - // KillerPDF logo - clickable link to product site + // MmdPdf logo - clickable link to product site var logo = new TextBlock { FontSize = 22, FontWeight = FontWeights.Bold, Margin = new Thickness(0, 0, 0, 4) }; - var logoHl = new Hyperlink(new Run("KillerPDF")) + var logoHl = new Hyperlink(new Run("MmdPdf")) { Foreground = accent, TextDecorations = null @@ -1539,7 +1539,7 @@ namespace KillerPDF Foreground = accent, TextDecorations = null }; - ktHl.Click += (_, _) => OpenUrl("https://killertools.net"); + ktHl.Click += (_, _) => OpenUrl("https://baobab-ts.com"); tagline.Inlines.Add(ktHl); tagline.Inlines.Add(new Run(".") { Foreground = fgDim }); @@ -1612,7 +1612,7 @@ namespace KillerPDF "Security check failed: pdfium.dll integrity verification failed.\n\n" + $"Expected: {BuildInfo.PdfiumSha256}\n" + $"Actual : {actual}\n\n" + - "The bundled PDF engine may have been tampered with. KillerPDF will exit.", + "The bundled PDF engine may have been tampered with. MmdPdf will exit.", $"{AppName} - Security", MessageBoxButton.OK, MessageBoxImage.Error); return false; } @@ -1638,7 +1638,7 @@ namespace KillerPDF { MessageBox.Show( "Installation refused: the running EXE does not carry a valid Authenticode " + - "signature.\n\nOnly signed builds of KillerPDF can be installed.", + "signature.\n\nOnly signed builds of MmdPdf can be installed.", AppName, MessageBoxButton.OK, MessageBoxImage.Error); return; } @@ -1679,7 +1679,7 @@ namespace KillerPDF { MessageBox.Show( "Couldn't write the installed copy at:\n" + InstallExe + - "\n\nClose any open KillerPDF window (and check Task Manager for KillerPDF.exe), " + + "\n\nClose any open MmdPdf window (and check Task Manager for MmdPdf.exe), " + "then run the installer again.", AppName, MessageBoxButton.OK, MessageBoxImage.Warning); return; @@ -1714,7 +1714,7 @@ namespace KillerPDF } /// - /// Register KillerPDF under either HKCU for a per-user install or HKLM for a machine-wide + /// Register MmdPdf under either HKCU for a per-user install or HKLM for a machine-wide /// install. This advertises the handler without changing any user's chosen PDF default. /// private static void RegisterFileHandler(RegistryKey root, string exePath, string iconPath) @@ -1725,42 +1725,42 @@ namespace KillerPDF : $"{exePath},0"; // ProgID definition - using (var k = root.CreateSubKey(@"Software\Classes\KillerPDF.pdf")) + using (var k = root.CreateSubKey(@"Software\Classes\MmdPdf.pdf")) k.SetValue("", "PDF Document"); using (var k = root.CreateSubKey( - @"Software\Classes\KillerPDF.pdf\DefaultIcon")) + @"Software\Classes\MmdPdf.pdf\DefaultIcon")) k.SetValue("", iconRef); using (var k = root.CreateSubKey( - @"Software\Classes\KillerPDF.pdf\shell\open\command")) + @"Software\Classes\MmdPdf.pdf\shell\open\command")) k.SetValue("", $"\"{exePath}\" \"%1\""); - // Associate .pdf extension - adds KillerPDF to the "Open with" list + // Associate .pdf extension - adds MmdPdf to the "Open with" list using (var k = root.CreateSubKey( @"Software\Classes\.pdf\OpenWithProgids")) - k.SetValue("KillerPDF.pdf", new byte[0], RegistryValueKind.None); + k.SetValue("MmdPdf.pdf", new byte[0], RegistryValueKind.None); // RegisteredApplications capability (used by Default Programs UI) using (var k = root.CreateSubKey( - @"Software\KillerPDF\Capabilities")) + @"Software\MmdPdf\Capabilities")) { k.SetValue("ApplicationName", AppName); k.SetValue("ApplicationDescription", "Lightweight PDF viewer and editor"); } using (var k = root.CreateSubKey( - @"Software\KillerPDF\Capabilities\FileAssociations")) - k.SetValue(".pdf", "KillerPDF.pdf"); + @"Software\MmdPdf\Capabilities\FileAssociations")) + k.SetValue(".pdf", "MmdPdf.pdf"); - // #183: without this the killerpdf:// handler never appears in Windows Settings > + // #183: without this the mmdpdf:// handler never appears in Windows Settings > // Default apps > Choose defaults by link type. Maps the scheme to its ProgID - // (Software\Classes\killerpdf, written by ProtocolRegistrar). + // (Software\Classes\mmdpdf, written by ProtocolRegistrar). using (var k = root.CreateSubKey( - @"Software\KillerPDF\Capabilities\UrlAssociations")) + @"Software\MmdPdf\Capabilities\UrlAssociations")) k.SetValue(Services.ProtocolRegistrar.Scheme, Services.ProtocolRegistrar.Scheme); using (var k = root.CreateSubKey(@"Software\RegisteredApplications")) - k.SetValue(AppName, @"Software\KillerPDF\Capabilities"); + k.SetValue(AppName, @"Software\MmdPdf\Capabilities"); // Tell the shell file associations have changed SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero); @@ -1768,12 +1768,12 @@ namespace KillerPDF private static void UnregisterFileHandler(RegistryKey root) { - try { root.DeleteSubKeyTree(@"Software\Classes\KillerPDF.pdf", false); } catch { } - try { root.DeleteSubKeyTree(@"Software\KillerPDF\Capabilities", false); } catch { } + try { root.DeleteSubKeyTree(@"Software\Classes\MmdPdf.pdf", false); } catch { } + try { root.DeleteSubKeyTree(@"Software\MmdPdf\Capabilities", false); } catch { } try { using var k = root.OpenSubKey(@"Software\Classes\.pdf\OpenWithProgids", writable: true); - k?.DeleteValue("KillerPDF.pdf", throwOnMissingValue: false); + k?.DeleteValue("MmdPdf.pdf", throwOnMissingValue: false); } catch { } try @@ -1852,7 +1852,7 @@ namespace KillerPDF RegisterFileHandler(registryRoot, exePath, iconPath); Services.ProtocolRegistrar.Register(registryRoot, exePath); - using (var key = registryRoot.CreateSubKey(@"Software\KillerPDF")) + using (var key = registryRoot.CreateSubKey(@"Software\MmdPdf")) { key.SetValue("Installed", 1); key.SetValue("InstallPath", exePath); @@ -1860,7 +1860,7 @@ namespace KillerPDF } using (var key = registryRoot.CreateSubKey( - @"Software\Microsoft\Windows\CurrentVersion\Uninstall\KillerPDF")) + @"Software\Microsoft\Windows\CurrentVersion\Uninstall\MmdPdf")) { key.SetValue("DisplayName", AppName); key.SetValue("DisplayVersion", Assembly.GetExecutingAssembly().GetName().Version?.ToString(3) ?? ""); @@ -1884,7 +1884,7 @@ namespace KillerPDF if (RelaunchMachineUninstallElevatedIfNeeded(machine)) return; var res = MessageBox.Show( - "Uninstall KillerPDF from this computer?", + "Uninstall MmdPdf from this computer?", $"{AppName} Uninstall", MessageBoxButton.YesNo, MessageBoxImage.Question); @@ -1896,10 +1896,10 @@ namespace KillerPDF try { File.Delete(DesktopLnk); } catch { } // Registry cleanup - try { Registry.CurrentUser.DeleteSubKeyTree(@"Software\KillerPDF"); } catch { } + try { Registry.CurrentUser.DeleteSubKeyTree(@"Software\MmdPdf"); } catch { } Services.ProtocolRegistrar.Unregister(); try { Registry.CurrentUser.DeleteSubKeyTree( - @"Software\Microsoft\Windows\CurrentVersion\Uninstall\KillerPDF"); } catch { } + @"Software\Microsoft\Windows\CurrentVersion\Uninstall\MmdPdf"); } catch { } UnregisterFileHandler(Registry.CurrentUser); // Machine-wide half. Only reachable when Add/Remove Programs launched the Program Files @@ -1911,13 +1911,13 @@ namespace KillerPDF try { Directory.Delete(MachineStartMenuDir, recursive: false); } catch { } UnregisterFileHandler(Registry.LocalMachine); Services.ProtocolRegistrar.Unregister(Registry.LocalMachine); // #183 - try { Registry.LocalMachine.DeleteSubKeyTree(@"Software\KillerPDF"); } catch { } + try { Registry.LocalMachine.DeleteSubKeyTree(@"Software\MmdPdf"); } catch { } try { Registry.LocalMachine.DeleteSubKeyTree( - @"Software\Microsoft\Windows\CurrentVersion\Uninstall\KillerPDF"); } catch { } + @"Software\Microsoft\Windows\CurrentVersion\Uninstall\MmdPdf"); } catch { } } // Self-delete: deferred via cmd batch so the EXE can exit first - string bat = Path.Combine(Path.GetTempPath(), "killerpdf_uninstall.bat"); + string bat = Path.Combine(Path.GetTempPath(), "mmdpdf_uninstall.bat"); File.WriteAllText(bat, "@echo off\r\n" + "ping -n 3 127.0.0.1 >nul\r\n" + @@ -1929,7 +1929,7 @@ namespace KillerPDF UseShellExecute = true }); - MessageBox.Show(Application.Current.TryFindResource("Str_Dlg_Uninstalled") as string ?? "KillerPDF has been uninstalled.", AppName, + MessageBox.Show(Application.Current.TryFindResource("Str_Dlg_Uninstalled") as string ?? "MmdPdf has been uninstalled.", AppName, MessageBoxButton.OK, MessageBoxImage.Information); } } diff --git a/BuildInfo.cs b/BuildInfo.cs index 937db5a..92697c1 100644 --- a/BuildInfo.cs +++ b/BuildInfo.cs @@ -1,4 +1,4 @@ -namespace KillerPDF +namespace MmdPdf { /// /// Build-time constants written or verified by release.ps1. diff --git a/CHANGELOG.md b/CHANGELOG.md index e158d62..5167e77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,17 @@ # Changelog -All notable changes to KillerPDF are documented here. +All notable changes to MmdPdf are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [1.7.5] - 2026-08-22 -KillerPDF 1.7.5 is a small maintenance release that closes several visible annotation, scrolling, shortcut, theme, and localization regressions. It keeps the faster scrolling introduced in 1.7.4, makes Transform trustworthy with freshly placed text, and gives the text annotation toolbar a cleaner two-row layout. +MmdPdf 1.7.5 is a small maintenance release that closes several visible annotation, scrolling, shortcut, theme, and localization regressions. It keeps the faster scrolling introduced in 1.7.4, makes Transform trustworthy with freshly placed text, and gives the text annotation toolbar a cleaner two-row layout. ### Added - Shift+mouse wheel now scrolls wide pages horizontally, using the same scrolling path as a tilt wheel (#209, thanks Ryokoxx). - Ctrl+B, Ctrl+I and Ctrl+U now bold, italicize and underline while you are editing a text box. They were listed in the shortcuts for weeks without ever being wired up. -- Hungarian OCR completes the twelve-language OCR catalog, so every language available for the KillerPDF interface now has a matching downloadable recognition model. +- Hungarian OCR completes the twelve-language OCR catalog, so every language available for the MmdPdf interface now has a matching downloadable recognition model. ### Changed - The text annotation toolbar now uses a deliberate two-row layout: font above size, text color above fill color, and text opacity above fill opacity. It is taller but substantially narrower, with each lower control aligned beneath its corresponding upper control instead of leaving Fill Opacity stranded on an accidental wrapped row. @@ -35,7 +35,7 @@ KillerPDF 1.7.5 is a small maintenance release that closes several visible annot ## [1.7.4] - 2026-08-21 -KillerPDF 1.7.4 keeps the convenience of one portable download while installing as a normal multi-file application, cutting initial startup time substantially. This release also fixes annotation rotation, form fields on comma-decimal locales, installation scope, and a range of viewer, dialog, and localization problems. Hungarian localization and page image export are included as well. +MmdPdf 1.7.4 keeps the convenience of one portable download while installing as a normal multi-file application, cutting initial startup time substantially. This release also fixes annotation rotation, form fields on comma-decimal locales, installation scope, and a range of viewer, dialog, and localization problems. Hungarian localization and page image export are included as well. ### Added - "Export page as image" on the Pages panel's right-click menu, including multi-page selections (#207, thanks 1mk3r). @@ -45,7 +45,7 @@ KillerPDF 1.7.4 keeps the convenience of one portable download while installing - The page badge fires on grid scrolling and names the visible span (#197, thanks Ryokoxx). ### Changed -- KillerPDF now remains one portable download while installing as a normal multi-file application. The portable EXE carries one compressed, verified payload and cleans up its temporary files after use; installed shortcuts launch the inner app directly, avoiding Costura extraction and reducing measured first startup by about 40% on the development machine (#189, thanks ags1234). The new package is also roughly 34% smaller than the previous woven EXE. +- MmdPdf now remains one portable download while installing as a normal multi-file application. The portable EXE carries one compressed, verified payload and cleans up its temporary files after use; installed shortcuts launch the inner app directly, avoiding Costura extraction and reducing measured first startup by about 40% on the development machine (#189, thanks ags1234). The new package is also roughly 34% smaller than the previous woven EXE. - Builds no longer risk the net48 CS8336 attribute collision introduced by compiler-generated polyfills (PR #218, thanks Ryokoxx). ### Fixed @@ -55,7 +55,7 @@ KillerPDF 1.7.4 keeps the convenience of one portable download while installing - Print, flatten, image export, and thumbnails no longer draw a form field twice when its stored appearance disagrees with the regenerated one. - Installation scope is now guarded end to end: a per-user install cannot sit beside an all-users install, existing dual installs are detected with an offer to remove the inactive copy, converting to all-users removes the older per-user copy, and machine-wide uninstall requests administrator access instead of reporting success after permission failures. - The Open dialog no longer crashes where Explorer's Quick Access cannot be read, such as under Wine and CrossOver; the pinned folders and drives still list (#210, thanks Ximelay). -- Opening a PDF from Explorer while KillerPDF is still starting no longer crashes; the file now opens once the window is ready (#202, thanks tgv123456). +- Opening a PDF from Explorer while MmdPdf is still starting no longer crashes; the file now opens once the window is ready (#202, thanks tgv123456). - Dropping a damaged PDF on the Pages panel now offers the same repair the Open dialog offers, instead of silently ignoring the file (#203, thanks 1mk3r). - After an install relaunch or split-pane session restore, the sidebar now attaches the active pane's thumbnail cache before the first visible frame instead of remaining blank until the user clicks a pane. - Snapping, maximizing, or restoring the window keeps the split panes' proportions, and a sidebar you closed stays closed when a tab loads its document. @@ -88,7 +88,7 @@ KillerPDF 1.7.4 keeps the convenience of one portable download while installing ## [1.7.2] - 2026-08-15 -KillerPDF 1.7.2 completes the split-pane viewer refactor and builds on it with seven new themes, Polish localization, book layout, Levels, expanded print controls, per-pane night mode, and a substantial round of rendering, memory, form, and interface fixes. +MmdPdf 1.7.2 completes the split-pane viewer refactor and builds on it with seven new themes, Polish localization, book layout, Levels, expanded print controls, per-pane night mode, and a substantial round of rendering, memory, form, and interface fixes. ### Added - Added 98SE, Ectoplasm, Decay, Mourning, Sepulchre, Delirium, and Malaise themes. @@ -120,8 +120,8 @@ KillerPDF 1.7.2 completes the split-pane viewer refactor and builds on it with s - Rotating a page that was opened with a non-zero /Rotate no longer swaps its MediaBox on save, which permanently clipped the content. Fixed in the vendored PdfSharpCore, whose landscape media-box flip fired on read pages (#184, thanks terada-d). - Documents opened from Explorer get keyboard focus immediately, so arrows and Page Up/Down work without clicking the window first, and horizontal scrolling from a touchpad or tilt wheel now pans the document (#196, thanks Subjuntivos). - Double-click text editing now maps PostScript font names (ArialMT, TimesNewRomanPSMT, Helvetica) to the installed Windows family, so edited text keeps its font instead of falling back to the default (#187, thanks fo-bo). -- Machine-wide installs register the killerpdf:// handler for all users, and it now appears in Default apps under link types (#183, thanks adeit). -- Themes are entirely owned by the KillerPDF repository again. The project no longer imports a private sibling `KillerUI` folder or overlays its resources at runtime, so a standalone clone contains every theme resource it builds and displays. +- Machine-wide installs register the mmdpdf:// handler for all users, and it now appears in Default apps under link types (#183, thanks adeit). +- Themes are entirely owned by the MmdPdf repository again. The project no longer imports a private sibling `MmdPdfUI` folder or overlays its resources at runtime, so a standalone clone contains every theme resource it builds and displays. - Completed the PDF viewer extraction so split panes keep independent documents, tabs, pages, tools, selections, and sidebar positions. - Various UI and theme consistency tweaks, including clearer Black-theme surfaces and controls, consistent floating-bar borders, legible accent buttons, and balanced film grain across the themes. @@ -131,19 +131,19 @@ KillerPDF 1.7.2 completes the split-pane viewer refactor and builds on it with s ### Added - Transform can now correct trapezoidal perspective distortion in pages photographed at an angle. Turn on perspective correction, drag four corner handles onto the photographed page outline, and Apply converts that quadrilateral into a straight rectangular page at the full transform resolution. The correction composes with rotation, deskew, scaling, and flipping in the same operation (#175, thanks 1mk3r). -- KillerPDF now registers a `killerpdf://` link handler for the current user, laying the app-side foundation for the planned Chrome extension. A `killerpdf://open?url=...` link can hand a public HTTPS PDF to KillerPDF whether the app is closed or already running; downloads are size-limited and rejected unless their contents begin as a PDF. The registration refreshes itself when the executable moves. -- Open and Save dialogs now return to the last folder successfully used for that kind of operation, unless the caller deliberately supplies another starting folder. The places rail also brings in the user's pinned Windows Explorer Quick Access folders alongside KillerPDF's own editable pins, while avoiding duplicate entries (#178, thanks sheafitzek). +- MmdPdf now registers a `mmdpdf://` link handler for the current user, laying the app-side foundation for the planned Chrome extension. A `mmdpdf://open?url=...` link can hand a public HTTPS PDF to MmdPdf whether the app is closed or already running; downloads are size-limited and rejected unless their contents begin as a PDF. The registration refreshes itself when the executable moves. +- Open and Save dialogs now return to the last folder successfully used for that kind of operation, unless the caller deliberately supplies another starting folder. The places rail also brings in the user's pinned Windows Explorer Quick Access folders alongside MmdPdf's own editable pins, while avoiding duplicate entries (#178, thanks sheafitzek). ### Fixed - Fit Width and Fit Page are now remembered as the preferred fit for subsequently opened PDFs, so users on smaller screens no longer have to switch from Fit Page every time, thanks Thomas. -- Owner-restricted encrypted PDFs with malformed linearization tables now pass through KillerPDF's tolerant PDFium cleanup instead of being retried through PdfSharp's fragile read-only parser. This fixes the array-index error that prevented the Fritzbox 4060 manual from opening, thanks Thomas. -- Reopening a PDF no longer reapplies a raw zoom saved for a different window or monitor size, which could make the document appear enormous or tiny. KillerPDF keeps the saved page and view mode but fits the document to the current window, with Grid returning to a predictable three-column layout. Perspective correction's corner handles now retain their drag capture across child controls and release reliably, and applying the correction immediately redraws the edited page even when the current zoom does not change. +- Owner-restricted encrypted PDFs with malformed linearization tables now pass through MmdPdf's tolerant PDFium cleanup instead of being retried through PdfSharp's fragile read-only parser. This fixes the array-index error that prevented the Fritzbox 4060 manual from opening, thanks Thomas. +- Reopening a PDF no longer reapplies a raw zoom saved for a different window or monitor size, which could make the document appear enormous or tiny. MmdPdf keeps the saved page and view mode but fits the document to the current window, with Grid returning to a predictable three-column layout. Perspective correction's corner handles now retain their drag capture across child controls and release reliably, and applying the correction immediately redraws the edited page even when the current zoom does not change. - Multi-line highlights now follow the reading direction of Persian, Arabic, Hebrew, and other right-to-left text. The first selected line extends left from the starting point and the last line extends right to the ending point, while left-to-right documents keep their existing behavior. Direction is detected per line, so mixed-language pages work without a document-wide setting (#170, thanks playerbhr). -- Installing KillerPDF for everyone now registers its PDF handler for the whole computer instead of writing it into the elevated administrator's personal registry. Every account can now find KillerPDF in Open With and Default apps, with the shared registration pointing at the Program Files copy; each user still chooses their own PDF default (#176, thanks adeit). +- Installing MmdPdf for everyone now registers its PDF handler for the whole computer instead of writing it into the elevated administrator's personal registry. Every account can now find MmdPdf in Open With and Default apps, with the shared registration pointing at the Program Files copy; each user still chooses their own PDF default (#176, thanks adeit). - The keyboard-shortcut list now uses the available window width instead of squeezing both halves into a narrow fixed card. Longer translated descriptions have room to remain visible, wrap cleanly on smaller windows, and sit level with the shortcut text in both columns (#177, thanks Mr-Update). - The mouse wheel now moves the file picker's multi-column list horizontally, so folders and files beyond the right edge can be reached without dragging the bottom scrollbar. The folder tree's wheel works too, scrolling vertically normally and horizontally while Shift is held. The shared picker fix applies to Open, Save, image import, signatures, certificates, and every other file-selection flow; icon and details views keep their normal vertical wheel scrolling. -- Text annotations, highlights, stamps, ink, and filled form fields already stored in a PDF now appear in KillerPDF and survive printing, flattening, image export, page transforms, thumbnails, and repair rasterization (#141, thanks zenfas). PDFium does not paint annotation appearance streams unless explicitly requested, so every pixel-producing path silently omitted them. Enabling Docnet's annotation flag was not safe because it creates and destroys a form-fill environment while its page remains in use, corrupting PDFium state and crashing on a later native call. KillerPDF now renders through its direct PDFium layer, owns the form callback memory for its full native lifetime, paints both ordinary annotations and interactive widget appearances, then immediately closes the form, page, and one-shot document together. The reporter's five-page D&D Beyond file from #179 now exports and flattens with its filled values and multiline fields intact, without the native teardown crash (#179, thanks hsnopi). -- Annotations and stamps now save in the right position on PDFs that already carry a native page rotation when they are first opened (#169, thanks terada-d). The 1.7.0 fix read only KillerPDF's temporary rotation map, but that map is not populated until a page operation performs a temporary save and reload, so annotating an already rotated file and saving it immediately still treated the page as unrotated. Burn-in now falls back to the page's own `/Rotate` value, every newly opened document clears the previous document's temporary rotation map, and saving removes a malformed CropBox that extends outside its MediaBox instead of preserving contradictory portrait and landscape dimensions. Tests cover the reported invalid page boxes and preservation of a valid inset crop. +- Text annotations, highlights, stamps, ink, and filled form fields already stored in a PDF now appear in MmdPdf and survive printing, flattening, image export, page transforms, thumbnails, and repair rasterization (#141, thanks zenfas). PDFium does not paint annotation appearance streams unless explicitly requested, so every pixel-producing path silently omitted them. Enabling Docnet's annotation flag was not safe because it creates and destroys a form-fill environment while its page remains in use, corrupting PDFium state and crashing on a later native call. MmdPdf now renders through its direct PDFium layer, owns the form callback memory for its full native lifetime, paints both ordinary annotations and interactive widget appearances, then immediately closes the form, page, and one-shot document together. The reporter's five-page D&D Beyond file from #179 now exports and flattens with its filled values and multiline fields intact, without the native teardown crash (#179, thanks hsnopi). +- Annotations and stamps now save in the right position on PDFs that already carry a native page rotation when they are first opened (#169, thanks terada-d). The 1.7.0 fix read only MmdPdf's temporary rotation map, but that map is not populated until a page operation performs a temporary save and reload, so annotating an already rotated file and saving it immediately still treated the page as unrotated. Burn-in now falls back to the page's own `/Rotate` value, every newly opened document clears the previous document's temporary rotation map, and saving removes a malformed CropBox that extends outside its MediaBox instead of preserving contradictory portrait and landscape dimensions. Tests cover the reported invalid page boxes and preservation of a valid inset crop. - Filled form fields now generate complete appearance streams, including the required stream length, multiline layout, and WinAnsi text encoding (#180, thanks Ryokoxx). This keeps entered values visible and readable in PDF viewers that strictly validate field appearances, resolving the damaged-file warning, missing line breaks, and replaced punctuation reported in #179 (#179, thanks hsnopi). - Double-clicking bold or italic PDF text to edit it no longer turns the replacement into regular text (#182, thanks fo-bo). PDF text usually carries its face styling inside the embedded font name, such as `Helvetica-BoldOblique`, rather than as separate bold and italic properties. The detector cleaned those suffixes off to find the font family, then explicitly reset both style flags before opening the editor, so the formatting was lost before the first keystroke. Font detection now separates the family from its bold and italic face, applies both to the live edit box, and carries them into the replacement annotation when it is committed. Focused tests cover subset font names and regular, bold, italic, and combined faces. - Clicking a page no longer crashes with "'∞' is not a valid value for property 'Height'" (#181, thanks lachlan-00). The page click rebuilds every annotation and form overlay, and malformed geometry could reach a WPF Width or Height property without being checked. WPF refuses NaN and infinity, so one bad form rectangle or a legacy saved signature with zero canvas dimensions took down the whole viewer during the redraw. Form rectangles and every sized annotation are now checked before they reach WPF; invalid form widgets are skipped, old signature dimensions fall back to the standard canvas size, and the render layer has a final guard for malformed persisted annotations. @@ -154,12 +154,12 @@ KillerPDF 1.7.2 completes the split-pane viewer refactor and builds on it with s ## [1.7.0] - 2026-08-01 -KillerPDF 1.7.0 introduces split panes, with two documents side by side in one window. It also replaces every stock Windows file dialog, adds a themed system menu and picture-aware night mode, saves non-Latin scripts correctly, and places annotations accurately on rotated pages. +MmdPdf 1.7.0 introduces split panes, with two documents side by side in one window. It also replaces every stock Windows file dialog, adds a themed system menu and picture-aware night mode, saves non-Latin scripts correctly, and places annotations accurately on rotated pages. ### Added - Split pane: F10 shows two documents side by side in one window. Each pane is a card of its own, and the focused one carries an accent ring so it is obvious which pane the toolbar, sidebar and page list are acting on. Click either pane to move focus. The boundary between them has a handle on each side: grab the left one to size the left pane or the right one to size the right. Neither pane can be squeezed below a readable width. F10 closes the split again, and the rail button's icon follows along: a pane pushed out will open, while one pulled back in will close. Each pane has its own tab strip, but the shared toolbar, sidebar, and page list follow whichever pane has focus. Drag a tab from one pane's strip to the other to move it across. On a maximized or snapped window, F10 splits the space evenly instead of squeezing the second pane to its minimum. -- Every Open and Save dialog is KillerPDF's own now, instead of the stock Windows one: the same themed window as the rest of the app, with a places rail, a folder tree, list/icon/details views, sortable columns, pinnable folders and recent locations. That covers opening and saving PDFs, merging, extracting pages, flatten, image export, image import, signature and certificate picking, OCR output and the zip export - including picking several files at once where that applies. Shared with the other Killer Tools apps, so the file dialog looks and behaves the same across the family. -- Install for everyone on this computer. The Install button on the portable badge now opens a confirmation with two choices: add a desktop shortcut (on by default, as before) and install for all users (off by default because it needs an administrator). An all-users install puts KillerPDF in Program Files with a Start menu entry for every account, and removes the per-user copy so there is a single entry in Add/Remove Programs rather than two. Declining the administrator prompt leaves the app running portable exactly as it was. A `/silent` switch performs the machine-wide install with no interface for winget, Chocolatey, and RMM deployment. This matches Killendar and KillerShell. PDF file associations are still registered only for the current account; an all-users install does not change what PDFs open with for anyone else. +- Every Open and Save dialog is MmdPdf's own now, instead of the stock Windows one: the same themed window as the rest of the app, with a places rail, a folder tree, list/icon/details views, sortable columns, pinnable folders and recent locations. That covers opening and saving PDFs, merging, extracting pages, flatten, image export, image import, signature and certificate picking, OCR output and the zip export - including picking several files at once where that applies. Shared with the other Killer Tools apps, so the file dialog looks and behaves the same across the family. +- Install for everyone on this computer. The Install button on the portable badge now opens a confirmation with two choices: add a desktop shortcut (on by default, as before) and install for all users (off by default because it needs an administrator). An all-users install puts MmdPdf in Program Files with a Start menu entry for every account, and removes the per-user copy so there is a single entry in Add/Remove Programs rather than two. Declining the administrator prompt leaves the app running portable exactly as it was. A `/silent` switch performs the machine-wide install with no interface for winget, Chocolatey, and RMM deployment. This matches Killendar and KillerShell. PDF file associations are still registered only for the current account; an all-users install does not change what PDFs open with for anyone else. - "Confirm before opening links" is back, on the About card beside the recent-files toggle. It asks before a link in a PDF opens in your browser, and it is off by default so links stay immediate unless you want the check. The prompt's own "Don't ask again" now simply switches the same option off, so the two can no longer disagree. The setting had no home after the Settings panel was dissolved; About is where the safety and data-hygiene controls live. - Ctrl+Shift+W closes every tab except the current one, alongside Close Tab on the tab's right-click menu - both now line their keyboard shortcuts up in a real column instead of each item sizing its own. - Right-clicking the title bar (or Alt+Space) shows a themed system menu that matches the app instead of the stock white Windows one. Same items, same behavior, in all ten languages. @@ -171,16 +171,16 @@ KillerPDF 1.7.0 introduces split panes, with two documents side by side in one w - The Settings panel and its gear are gone: every section moved to where the thing it configures lives, matching the rest of the Killer Tools apps. Theme and language are flyouts on new rail buttons (below the night-mode moon, with a ? button for the shortcuts overlay); the theme flyout stays open across a pick so themes can be compared. - Toolbar appearance is a right-click menu on the toolbar itself, and it is two independent choices now instead of one list of five: icon size (small/large) and text placement (none/beside/under/text only) - so large icons with captions is finally possible. Fresh installs default to large icons with text underneath; existing installs keep their setting. Ctrl+Shift+1-6 pick the options directly. - Internal: the codebase has been reorganized into the Killer Tools family layout - document logic in service classes, the About/CLI/OCR/search features behind controllers, the window partials under Shell/. Every moved function is verbatim and no behavior change is intended; the repo root now holds only the entry files. -- New app icon. The old document icon with the red bar across the bottom now marks PDF *files*, so a KillerPDF window and a PDF sitting in a folder are no longer the same picture. Explorer caches icons aggressively, so a PDF may keep showing the old art until the cache refreshes. +- New app icon. The old document icon with the red bar across the bottom now marks PDF *files*, so a MmdPdf window and a PDF sitting in a folder are no longer the same picture. Explorer caches icons aggressively, so a PDF may keep showing the old art until the cache refreshes. - View mode is a rail button wearing four view tiles, one per layout: click for a flyout (each mode with its F-key beside it), roll the wheel over it to step through the views, or press F9 to jog from the keyboard - F5-F8 still jump straight to one, and Ctrl+, is retired. All the new shortcuts are on the F1 overlay, in all ten languages. - Internal: the tab strip and split-pane drag/focus model were rewritten to match KillerShell's implementation, the family's reference for both, replacing the original hand-built version. - The sidebar's left/right choice sits at the bottom of the sidebar's right-click menu, which now opens from any part of the sidebar; Ctrl+Shift+B flips the side, pairing with Ctrl+B's collapse. - The content pane's border is a shade lighter in every theme, so the edge between the pane and the chrome reads more clearly - the same value the other Killer Tools apps use. -- The prompt offering to make KillerPDF your default PDF viewer is translated now; it was English-only in every interface language. -- The sidebar's page list fades into the background at its top and bottom edges while there are pages scrolled past them - the same treatment KillerShell's folder tree and the killerpdf.net sidebar use. Each fade ramps in over its own height as a row slides under it, so nothing pops, and neither shows when the list is flush at that end. +- The prompt offering to make MmdPdf your default PDF viewer is translated now; it was English-only in every interface language. +- The sidebar's page list fades into the background at its top and bottom edges while there are pages scrolled past them - the same treatment KillerShell's folder tree and the baobab-ts.com sidebar use. Each fade ramps in over its own height as a row slides under it, so nothing pops, and neither shows when the list is flush at that end. ### Fixed -- Japanese and other non-Latin text no longer saves as empty boxes (#168, thanks terada-d). The editor is a Windows text box, which quietly borrows glyphs from any installed font, so what you type always looks right; the save path resolved a single font and wrote a box for every character that font lacked. Two things were wrong. Nearly every CJK font on Windows ships as a collection file (Yu Gothic, MS Gothic, Meiryo, YaHei, JhengHei), and the save path could not read collections at all. Even picking a Japanese font by hand did not help. Nothing checked whether the chosen font could carry the text either. KillerPDF now reads collection fonts, and when your font cannot render something it picks one that can, preferring the same faces Windows itself falls back to. Your own font is always used when it covers the text. This affects Bengali, Korean, Chinese, Thai, Arabic and Indic scripts too, and applies to page numbers and watermarks as well as placed text. Embedded fonts are subset, so a line of Japanese adds tens of KB to the file rather than the whole typeface. If nothing installed can draw a character, KillerPDF now says so when the text is placed and lists the unsupported characters. This rare case can happen when one box contains two non-Latin scripts or the PC has no font for the requested script. +- Japanese and other non-Latin text no longer saves as empty boxes (#168, thanks terada-d). The editor is a Windows text box, which quietly borrows glyphs from any installed font, so what you type always looks right; the save path resolved a single font and wrote a box for every character that font lacked. Two things were wrong. Nearly every CJK font on Windows ships as a collection file (Yu Gothic, MS Gothic, Meiryo, YaHei, JhengHei), and the save path could not read collections at all. Even picking a Japanese font by hand did not help. Nothing checked whether the chosen font could carry the text either. MmdPdf now reads collection fonts, and when your font cannot render something it picks one that can, preferring the same faces Windows itself falls back to. Your own font is always used when it covers the text. This affects Bengali, Korean, Chinese, Thai, Arabic and Indic scripts too, and applies to page numbers and watermarks as well as placed text. Embedded fonts are subset, so a line of Japanese adds tens of KB to the file rather than the whole typeface. If nothing installed can draw a character, MmdPdf now says so when the text is placed and lists the unsupported characters. This rare case can happen when one box contains two non-Latin scripts or the PC has no font for the requested script. - Punctuation shortcuts work on keyboard layouts that need Shift for those characters (#153, thanks Mr-Update). Shortcuts were matched by key position, which is a US-layout assumption: on a German keyboard "?" lives on Shift+ss and "=" on Shift+0, so Ctrl+? and Ctrl+= pressed keys the app was not listening for, and the extra Shift broke the match a second time. Zoom and the shortcuts overlay now respond to the key that TYPES the character, whatever position it occupies, so they work on German, French, Nordic and other layouts rather than being fixed one at a time. The shortcuts overlay also prints the spelling that is right for the keyboard in use instead of always showing the US one. - Annotations and stamps are no longer burned into the wrong frame on a rotated page (#169, thanks terada-d for a report that diagnosed it down to the line). A page's rotation is deliberately kept outside the working document, so the canvas you draw on is in the rotated frame while the save path writes into the page's own unrotated one - and the save path was never told the angle. Anything placed on a quarter-turned page came out rotated 90 degrees from where you put it, offset, and scaled on swapped axes, which also squeezed text boxes narrow enough to wrap after almost every character. Stamps had the same fault, so page numbers and watermarks landed in the wrong corner and disagreed with their own preview. The rotation now travels with the burn, in the editor and in the background flatten that print uses. - The app-size readout parked itself on the status bar. Rolling the wheel over the logo wrote "App size N%" into the footer behind a short hold, which existed so the chrome resize could not stomp the message with its own page and zoom status the same frame. When that hold expired nothing repainted the line, so the readout stayed put until the next page change, tool switch or open happened to write over it. It is transient now. Each notch rewrites the readout and restarts a five second timer, and the status line goes back to what it was showing before the first notch when the timer expires. The hold is unchanged and still only covers the same-frame stomp. If something else wrote a status after the hold lapsed the restore is skipped, so a real message is never replaced by a stale one. @@ -196,10 +196,10 @@ KillerPDF 1.7.0 introduces split panes, with two documents side by side in one w ## [1.6.6] - 2026-07-23 -KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects form fields that appeared in the wrong place on non-A4 documents. It also remaps tool hotkeys, adds Remove Password, and includes several menu, keyboard, and interface improvements. +MmdPdf 1.6.6 is primarily a bug fix release. Most importantly, it corrects form fields that appeared in the wrong place on non-A4 documents. It also remaps tool hotkeys, adds Remove Password, and includes several menu, keyboard, and interface improvements. ### Added -- Remove Password in the Save dropdown (#149, thanks dmantisk): saves the open document back over the original with its password protection dropped - available whenever the file needed a password (or carried owner restrictions) to open. KillerPDF already strips encryption at open time because the editing pipeline cannot modify encrypted files in place, so every save has always written an unprotected PDF; this makes that behavior a visible, deliberate action, and regular saves of a previously protected file now say so in the status bar instead of dropping the password silently. In all ten languages. +- Remove Password in the Save dropdown (#149, thanks dmantisk): saves the open document back over the original with its password protection dropped - available whenever the file needed a password (or carried owner restrictions) to open. MmdPdf already strips encryption at open time because the editing pipeline cannot modify encrypted files in place, so every save has always written an unprotected PDF; this makes that behavior a visible, deliberate action, and regular saves of a previously protected file now say so in the status bar instead of dropping the password silently. In all ten languages. ### Changed - Tool hotkey remap - the digits again mirror the toolbar left to right, with Shapes slotted in (breaks some muscle memory; the letter keys are unchanged): V = Select (the Photoshop / Illustrator / Figma convention; its old digit went to Text), 1 = Text, 2 = Highlight, 3 = Line, 4 = Shapes, 5 = Draw, 6 = Image, 7 = Signature, 8 = Crop, 9 = Transform, 0 = Stamp. The toolbar buttons reorder to match (Highlight now before Line, Shapes between Line and Draw), and the Shapes tool has a keyboard shortcut for the first time. The shortcuts overlay (both views), tooltips, and the help page follow. @@ -255,8 +255,8 @@ KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects fo - Keyboard view in the shortcuts overlay (F1): a visual keyboard with every bound key lit and color-coded by category. Toggle LIST / KEYBOARD in the header (the choice sticks), click a layer or hold Ctrl / Shift / Alt to preview it, and hover a lit key for its action. Follows the active theme and language. - More conventions from the big viewers: Home / End jump to the first / last page, Ctrl+1 / Ctrl+2 / Ctrl+3 set actual size / fit width / fit page, and the Menu key or Shift+F10 opens the right-click menu at the current selection (keyboard accessibility). - Japanese OCR language (`jpn`), downloadable on demand like the rest - the OCR language list now covers the same nine languages as the interface. -- Command-line batch mode: `KillerPDF.exe --batch-resave [--log report.csv] [--quiet]` resaves a single PDF or a whole folder tree headlessly through the standard open/save pipeline, with per-file OK/SKIP/FAIL reporting. Built for the validation harness. -- Standards-conformance validation harness (`validation/`): `Compare-VeraPDF.ps1` diffs two veraPDF batch reports (corpus baseline vs a `--batch-resave` output tree) and flags any file whose validation outcome a KillerPDF save changed. Verifies that saving through KillerPDF does not degrade PDF/A conformance. +- Command-line batch mode: `MmdPdf.exe --batch-resave [--log report.csv] [--quiet]` resaves a single PDF or a whole folder tree headlessly through the standard open/save pipeline, with per-file OK/SKIP/FAIL reporting. Built for the validation harness. +- Standards-conformance validation harness (`validation/`): `Compare-VeraPDF.ps1` diffs two veraPDF batch reports (corpus baseline vs a `--batch-resave` output tree) and flags any file whose validation outcome a MmdPdf save changed. Verifies that saving through MmdPdf does not degrade PDF/A conformance. ### Changed - Shortcut remap: About moved from F2 to F12, and Document Info moved from F12 to F4 (Ctrl+D also works, matching Acrobat/Foxit/Sumatra's Document Properties). F2 now renames the selected bookmark in the Outline panel, the Windows rename convention. Settings gained F9 (Ctrl+, also works, the VS Code / Windows Terminal convention), and F3 / Shift+F3 step to the next / previous search match from anywhere (F3 opens search when it isn't). Pressing a dialog shortcut while the shortcuts overlay is open dismisses the overlay first. The shortcuts overlay and the help page keyboard map follow. @@ -267,7 +267,7 @@ KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects fo ### Fixed - Resaving a PDF no longer reduces its PDF/A conformance. The PDF library (PdfSharpCore, MIT) is now vendored under third_party/ with six patches: no Producer/Creator stamping into an imported document's Info dictionary, no /ModDate rewrite at open, no transparency /Group injected into every page, stream /Length now always matches the spec's byte count (empty streams included), boolean values written as the spec's lowercase true/false keywords, and the debug-only verbose file layout removed. Found by the new veraPDF validation harness across a 2,900-file corpus. -- Intermittent hard crash (native heap corruption) while scrolling or clicking through a document, most visible on annotation-heavy pages: KillerPDF's direct PDFium calls (link extraction, encryption stripping) could land at the same moment as a background page render inside PDFium, which is single-threaded. Every direct call now holds the same lock the render path uses. Diagnosed from a 1.6.3 crash dump showing two threads inside PDFium at once. +- Intermittent hard crash (native heap corruption) while scrolling or clicking through a document, most visible on annotation-heavy pages: MmdPdf's direct PDFium calls (link extraction, encryption stripping) could land at the same moment as a background page render inside PDFium, which is single-threaded. Every direct call now holds the same lock the render path uses. Diagnosed from a 1.6.3 crash dump showing two threads inside PDFium at once. - Saving a PDF that carries a digital signature kept the old signature value even though any edit breaks its digest (which must cover the entire file), so strict validators rejected the result. Saves now strip dead signature values and the matching /Perms entry; the signature fields themselves are kept. - Saving over the open file failed with "being used by another process" on PDFs whose pages carry annotations but no links readable by the primary parser (typically fillable forms): the cached PDFium link handle was holding the file open. It is now released before every save (#129, thanks Peter5164). - Opening a PDF whose page tree parses to zero pages crashed Continuous view with an out-of-range page index; it is now guarded (#130, thanks demo1866). @@ -300,7 +300,7 @@ KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects fo - Japanese (ja-JP) interface translation, selectable from the language picker (#118, thanks coolvitto). ### Changed -- Footer/status bar tightened to match the killerpdf.net statusbar: 4px shorter with larger text, and the corner grip dots now stay visible when the window is maximized or snapped. +- Footer/status bar tightened to match the baobab-ts.com statusbar: 4px shorter with larger text, and the corner grip dots now stay visible when the window is maximized or snapped. - Ctrl+scroll zooming is smooth: each wheel notch zooms by a constant 10% ratio, the view scales instantly while the wheel is moving, and the crisp high-resolution re-render happens once when the wheel rests. Precision touchpads glide proportionally. - Up / Down arrows now scroll the view like the mouse wheel, flipping pages at the top or bottom edge. Left / Right and PgUp / PgDn remain hard page jumps. - Status-bar and dialog messages that were still shown in English now follow the selected language across all nine locales. @@ -314,7 +314,7 @@ KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects fo ## [1.6.1] - 2026-07-01 ### Added -- On quit with documents open, KillerPDF asks whether to reopen them next launch, with a "remember my choice" option (#105). +- On quit with documents open, MmdPdf asks whether to reopen them next launch, with a "remember my choice" option (#105). - Enter and Esc now confirm and cancel dialogs (#111). - Right-clicking the Open, Save, and OCR toolbar buttons opens their dropdown menu (#109, thanks Ryokoxx). - Copies and custom Scale in the print dialog are numeric fields with an up/down spinner, arrow-key and wheel stepping (#109, thanks Ryokoxx). @@ -385,7 +385,7 @@ KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects fo ## [1.5.1] - 2026-06-14 ### Fixed -- PDFs that opened fine in browsers and Acrobat/Foxit but failed in KillerPDF with "Unexpected EOF" now open. PdfSharpCore rejected them during parsing; KillerPDF now falls back to re-saving the file losslessly through PDFium (which reads them) and opening that copy (Issue #72). +- PDFs that opened fine in browsers and Acrobat/Foxit but failed in MmdPdf with "Unexpected EOF" now open. PdfSharpCore rejected them during parsing; MmdPdf now falls back to re-saving the file losslessly through PDFium (which reads them) and opening that copy (Issue #72). - Files opened from UNC / network shares (including the WSL `\\wsl$` filesystem) are now copied to a local temp before opening, avoiding partial-read failures on network filesystems. - Grid view now renders every page, and tiles stream in progressively as they render instead of blocking until the whole document is done. Grid was previously capped at the first 26 pages, so longer documents stopped loading partway through. - Ctrl+Scroll in grid view no longer re-renders every page when the zoom is already at its limit (the column count cannot change), which made large documents reload pointlessly. @@ -419,8 +419,8 @@ KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects fo - Settings and keyboard shortcut overlay borders widened to 2px for better visibility. - Text tool size value is now interpreted as points. A size of 14 renders and exports as roughly 14pt instead of about 5pt of internal render units. - Placing an image now switches to the Select tool with the image selected, so you can immediately drag to reposition or use the corner handle to resize instead of the next click reopening the image picker (matching signature placement). -- Extracted SignatureStore and SearchService into Services/ with unit tests (KillerPDF.Tests). -- Encrypted PDF temp files written to `%LOCALAPPDATA%\KillerPDF\Temp\` instead of `%TEMP%`. +- Extracted SignatureStore and SearchService into Services/ with unit tests (MmdPdf.Tests). +- Encrypted PDF temp files written to `%LOCALAPPDATA%\MmdPdf\Temp\` instead of `%TEMP%`. - Reopens last file on startup; ESC closes the app when no overlay is active (Issue #69). - Grid view mode moved from a toolbar toggle to the Settings panel alongside Theme and Language. Four modes: Single Page, Continuous, Two-Page, Grid. Selection persists across sessions. - Switching to Single or Two-Page view fits the page to the window, Continuous opens fit-to-width, and Grid opens at its column-fit default, rather than carrying the previous mode's zoom level. @@ -441,10 +441,10 @@ KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects fo ## [1.4.3] - 2026-06-08 ### Fixed -- Encrypted PDFs (owner-restricted RC4) no longer fail with "Unexpected token 'xref'" when rotating pages. PdfSharpCore can silently produce a broken cross-reference entry after saving encrypted files; KillerPDF now pipes the file through PDFium to repair the XRef and retries the open automatically. +- Encrypted PDFs (owner-restricted RC4) no longer fail with "Unexpected token 'xref'" when rotating pages. PdfSharpCore can silently produce a broken cross-reference entry after saving encrypted files; MmdPdf now pipes the file through PDFium to repair the XRef and retries the open automatically. - Page view now fits to page after a rotation so the full rotated page is visible without manual rezoom. -- Mailto and other link annotations with visible borders (e.g. colored rectangles that looked like strikethroughs) no longer render those borders in saved PDFs. KillerPDF strips `/AP`, `/C`, and `/BS` from link annotations and sets an invisible border on save. -- Right-click a link annotation to remove it from the PDF entirely ("Remove Link from PDF"). Previously, clearing annotations only removed the KillerPDF overlay; the native PDF link remained active. +- Mailto and other link annotations with visible borders (e.g. colored rectangles that looked like strikethroughs) no longer render those borders in saved PDFs. MmdPdf strips `/AP`, `/C`, and `/BS` from link annotations and sets an invisible border on save. +- Right-click a link annotation to remove it from the PDF entirely ("Remove Link from PDF"). Previously, clearing annotations only removed the MmdPdf overlay; the native PDF link remained active. - Right-click a mailto link to copy just the email address; right-click an http/https link to copy the URL. --- @@ -508,14 +508,14 @@ KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects fo - Sidebar page list no longer shows empty space after the last page. The list now ends at the final page entry with no trailing dead zone. ### Changed -- Theme updated to match killertools.net: accent green changed from `#4ade80` to `#1ea54c`, backgrounds shifted to `#333333`/`#3a3a3a`, sidebar darkened to `#222222`, toolbar and title bar at `#222222`. Film grain overlay added to the main content area. Footer text lightened for readability. +- Theme updated to match baobab-ts.com: accent green changed from `#4ade80` to `#1ea54c`, backgrounds shifted to `#333333`/`#3a3a3a`, sidebar darkened to `#222222`, toolbar and title bar at `#222222`. Film grain overlay added to the main content area. Footer text lightened for readability. - Sidebar scroll is now handled by an outer ScrollViewer wrapping the page list, allowing the list to size to its content rather than stretching to fill the panel height. ## [1.3.2] - 2026-05-11 ### Fixed - Windows Program Compatibility Assistant popup on first launch. Added an app manifest declaring Windows 10/11 compatibility, which suppresses PCA when the app writes to uninstall registry keys. -- "Set as default PDF viewer" prompt now only appears if KillerPDF is not already the default handler. Previously showed on every install/update regardless. +- "Set as default PDF viewer" prompt now only appears if MmdPdf is not already the default handler. Previously showed on every install/update regardless. - "Set as default PDF viewer" prompt now uses the dark KillerDialog instead of a native Windows message box. ## [1.3.1] - 2026-05-11 @@ -556,8 +556,8 @@ KillerPDF 1.6.6 is primarily a bug fix release. Most importantly, it corrects fo ## [1.2.0] - 2026-04-24 ### Added -- Self-installing EXE. Running the downloaded binary now shows an Install / Run dialog. Install copies the EXE to `%LOCALAPPDATA%\Programs\KillerPDF\` (no UAC required), creates Start Menu and optional Desktop shortcuts, registers as a PDF file handler, and adds an uninstall entry to Add/Remove Programs. Uninstall self-deletes via a deferred batch file. Running a newer version from outside the install path shows an Update prompt instead. -- Command-line file argument support so file associations work: `KillerPDF.exe "file.pdf"` opens the file directly. +- Self-installing EXE. Running the downloaded binary now shows an Install / Run dialog. Install copies the EXE to `%LOCALAPPDATA%\Programs\MmdPdf\` (no UAC required), creates Start Menu and optional Desktop shortcuts, registers as a PDF file handler, and adds an uninstall entry to Add/Remove Programs. Uninstall self-deletes via a deferred batch file. Running a newer version from outside the install path shows an Update prompt instead. +- Command-line file argument support so file associations work: `MmdPdf.exe "file.pdf"` opens the file directly. - Password-protected PDF support. Opening an encrypted PDF now prompts for the password instead of showing a generic error. The decrypted copy is held in a temp file for the session so all rendering and editing works normally. - Save Flattened PDF (photo icon in toolbar). Rasterizes every page at 150 DPI via PDFium and writes them as embedded images into a new PDF, producing a fully uneditable document. Pending annotations are burned in before rasterization. diff --git a/Controls/Anim.cs b/Controls/Anim.cs index ae4e424..e5959b4 100644 --- a/Controls/Anim.cs +++ b/Controls/Anim.cs @@ -14,7 +14,7 @@ using System.Windows.Media.Animation; // THIS IS THE CANONICAL COPY (consolidated 2026-08-08). Every app carries a byte-identical // copy of this file - only the namespace line differs - so a diff against this file IS the // drift check. It replaced five copies that had each grown a different subset: the kit shipped -// no fade-out at all, so KillerNotes invented FadeOutAndClose and KillerPDF invented +// no fade-out at all, so KillerNotes invented FadeOutAndClose and MmdPdf invented // FadeOut(element, done) independently, while KillerScan, KillerShell and Killendar closed // every dialog with no fade. When something here needs to change, change it HERE first, then // re-copy into every app. @@ -34,10 +34,10 @@ using System.Windows.Media.Animation; // - FadeOut(element, done): fades a named element and runs a callback. For a dialog that must // hold its DialogResult until after the fade: assigning DialogResult is itself a close // request, and WPF resets DialogResult to null whenever a close is canceled, so such a -// dialog records the result, fades, and assigns it in the callback (see KillerPDF's +// dialog records the result, fades, and assigns it in the callback (see MmdPdf's // FileDialog.OnClosing). // ============================================================ -namespace KillerPDF.Controls +namespace MmdPdf.Controls { internal static class Anim { diff --git a/Controls/ColorPickerDialog.cs b/Controls/ColorPickerDialog.cs index 89d4458..7104807 100644 --- a/Controls/ColorPickerDialog.cs +++ b/Controls/ColorPickerDialog.cs @@ -9,7 +9,7 @@ using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; -namespace KillerPDF +namespace MmdPdf { /// /// A small, themed RGB color picker: saturation/value square + hue strip, RGB and HTML-hex inputs, @@ -50,7 +50,7 @@ namespace KillerPDF private static string L(string key) => Application.Current.TryFindResource(key) as string ?? key; public ColorPickerDialog(Window? owner, Color initial) { - Title = "KillerPDF - " + L("Str_Color_Name"); + Title = "MmdPdf - " + L("Str_Color_Name"); Width = 300; SizeToContent = SizeToContent.Height; DialogChrome.Configure(this, owner); @@ -359,7 +359,7 @@ namespace KillerPDF box.Padding = new Thickness(4, 0, 4, 0); return box; } - // A crosshair/target glyph drawn in vectors, to match the KillerPDF look. + // A crosshair/target glyph drawn in vectors, to match the MmdPdf look. private UIElement CrosshairIcon() { var g = new Grid { Width = 14, Height = 14 }; diff --git a/Controls/DialogChrome.cs b/Controls/DialogChrome.cs index cacbc67..e125eda 100644 --- a/Controls/DialogChrome.cs +++ b/Controls/DialogChrome.cs @@ -5,10 +5,10 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Effects; -namespace KillerPDF +namespace MmdPdf { // Chrome for modal dialog windows: Configure (borderless window setup), Frame (the rounded card + - // title bar + grain), and BuildTitleBar (the KillerPDF wordmark + red close button). + // title bar + grain), and BuildTitleBar (the MmdPdf wordmark + red close button). internal static class DialogChrome { // Keep generated dialog captions on the same close mark as the main window. @@ -25,7 +25,7 @@ namespace KillerPDF // Builds the title bar. // win - the window being chromed (used for DragMove on the whole bar) // owner - supplies the themed brushes + the ChromeCloseButton style (pass the window's owner) - // fullTitle - the complete title, e.g. "KillerPDF - Transform"; the "KillerPDF" part becomes the + // fullTitle - the complete title, e.g. "MmdPdf - Transform"; the "MmdPdf" part becomes the // wordmark and the remainder (" - Transform") is rendered in the courier title font // onClose - invoked when the red close button is clicked (e.g. set a result then Close()) public static Border BuildTitleBar(Window win, Window? owner, string? fullTitle, Action onClose) @@ -64,7 +64,7 @@ namespace KillerPDF Brush primary = shadow ? Brushes.Black : Brush(owner, "TextBrush", Brushes.White); Brush logo = shadow ? Brushes.Black : Brush(owner, "AccentLogo", Brushes.LimeGreen); Brush secondary = shadow ? Brushes.Black : Brush(owner, "MutedTextBrush", Brushes.Gray); - int kp = fullTitle?.IndexOf("KillerPDF", StringComparison.Ordinal) ?? -1; + int kp = fullTitle?.IndexOf("MmdPdf", StringComparison.Ordinal) ?? -1; if (kp >= 0) { // Killer + PDF in one TextBlock so the two sizes share a baseline (cohesive wordmark). @@ -72,7 +72,7 @@ namespace KillerPDF logoTb.Inlines.Add(new System.Windows.Documents.Run("Killer") { FontFamily = wordmark, FontWeight = FontWeights.Normal, FontSize = 16, Foreground = primary }); logoTb.Inlines.Add(new System.Windows.Documents.Run("PDF") { FontFamily = wordmarkPdf, FontWeight = FontWeights.Bold, FontSize = 20.8, Foreground = logo }); sp.Children.Add(logoTb); - string after = fullTitle![(kp + "KillerPDF".Length)..]; + string after = fullTitle![(kp + "MmdPdf".Length)..]; if (!string.IsNullOrEmpty(after)) sp.Children.Add(new TextBlock { Text = after, FontFamily = UiKit.MonoFont, FontSize = 14, Foreground = secondary, VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(4, 1, 0, 0) }); } @@ -88,7 +88,7 @@ namespace KillerPDF { title.Children.Add(new TextBlock { - Text = fullTitle ?? "KillerPDF", FontFamily = Value(owner, "ChromeFontFamily", new FontFamily("Tahoma")), + Text = fullTitle ?? "MmdPdf", FontFamily = Value(owner, "ChromeFontFamily", new FontFamily("Tahoma")), FontSize = 11, FontWeight = FontWeights.Bold, Foreground = Brush(owner, "ChromeTextBrush", Brushes.White), VerticalAlignment = VerticalAlignment.Center }); diff --git a/Controls/DocumentInfoDialog.cs b/Controls/DocumentInfoDialog.cs index 9489724..e99b794 100644 --- a/Controls/DocumentInfoDialog.cs +++ b/Controls/DocumentInfoDialog.cs @@ -5,7 +5,7 @@ using System.Windows; using System.Windows.Controls; using PdfSharpCore.Pdf; -namespace KillerPDF +namespace MmdPdf { // Read/edit the PDF Document Info dictionary (Title, Author, Subject, Keywords, Creator). Themed via // DialogChrome, no preview pane. Producer/dates/structure are shown read-only. @@ -19,7 +19,7 @@ namespace KillerPDF public DocumentInfoDialog(Window owner, PdfDocument doc, string? filePath) { _doc = doc; - Title = "KillerPDF - " + L("Str_DocInfo_Suffix"); + Title = "MmdPdf - " + L("Str_DocInfo_Suffix"); Width = 460; SizeToContent = SizeToContent.Height; UseLayoutRounding = true; @@ -56,7 +56,7 @@ namespace KillerPDF row.Margin = new Thickness(0, 16, 0, 0); body.Children.Add(row); - Content = DialogChrome.Frame(this, Owner, "KillerPDF - " + L("Str_DocInfo_Suffix"), + Content = DialogChrome.Frame(this, Owner, "MmdPdf - " + L("Str_DocInfo_Suffix"), () => { DialogResult = false; Close(); }, body); Loaded += (_, _2) => _title.Focus(); diff --git a/Controls/ExportImagesDialog.cs b/Controls/ExportImagesDialog.cs index 9d663b5..9dcad7d 100644 --- a/Controls/ExportImagesDialog.cs +++ b/Controls/ExportImagesDialog.cs @@ -1,7 +1,7 @@ using System.Windows; using System.Windows.Controls; -namespace KillerPDF +namespace MmdPdf { // Export pages as images (#132): PNG/JPEG + DPI + page range, themed via DialogChrome like // Document Info. The destination and base file name are picked afterwards with the standard @@ -21,7 +21,7 @@ namespace KillerPDF /// (#207) opens the same dialog scoped to the clicked page(s), still editable. public ExportImagesDialog(Window owner, string presetRange = "") { - Title = "KillerPDF - " + L("Str_ExportImg_Suffix"); + Title = "MmdPdf - " + L("Str_ExportImg_Suffix"); // Width follows the caption. "Export Pages as Images" is 22 characters in en-US and // up to 35 translated, which ran the title under the close button at a fixed 380 (#223). MinWidth = 380; @@ -68,7 +68,7 @@ namespace KillerPDF row.Margin = new Thickness(0, 8, 0, 0); body.Children.Add(row); - Content = DialogChrome.Frame(this, Owner, "KillerPDF - " + L("Str_ExportImg_Suffix"), + Content = DialogChrome.Frame(this, Owner, "MmdPdf - " + L("Str_ExportImg_Suffix"), () => { Confirmed = false; Close(); }, body); Loaded += (_, _2) => _dpi.Focus(); diff --git a/Controls/FileDialog.xaml b/Controls/FileDialog.xaml index 48ebb4b..ed04040 100644 --- a/Controls/FileDialog.xaml +++ b/Controls/FileDialog.xaml @@ -4,11 +4,11 @@ and Open/Save behavior. The property surface deliberately mirrors the Win32 dialogs (Title, Filter, FilterIndex, FileName, InitialDirectory, DefaultExt, ...) so a call site changes by one word. --> -Open or Save. Picked at construction; changes the accept button and the rules. public enum FileDialogMode { Open, Save } @@ -1261,14 +1261,14 @@ namespace KillerPDF.Controls if (OverwritePrompt && File.Exists(full)) { - // Killendar asks this through its own ConfirmDialog. KillerPDF already has a + // Killendar asks this through its own ConfirmDialog. MmdPdf already has a // themed confirm (KillerDialog) that every other prompt in the app uses, so // this goes through that instead of importing a second one - two dialogs that // ask the same kind of question is exactly how a UI starts to look stitched // together. Same question, same buttons, one implementation. var answer = KillerDialog.Show(this, string.Format(Loc("Str_Dlg_OverwriteMsg"), Path.GetFileName(full)), - "KillerPDF", MessageBoxButton.YesNo, MessageBoxImage.Warning); + "MmdPdf", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (answer != MessageBoxResult.Yes) { FileNameBox.Focus(); return; } } } diff --git a/Controls/FlyoutPlacement.cs b/Controls/FlyoutPlacement.cs index b92503a..d7e17cd 100644 --- a/Controls/FlyoutPlacement.cs +++ b/Controls/FlyoutPlacement.cs @@ -2,11 +2,11 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; -namespace KillerPDF +namespace MmdPdf { /// /// Where every flyout opens: the bottom corner of the content pane beside the rail. - /// (From KillerUI/Shell/FlyoutPlacement.cs - the family flyout standard.) + /// (From MmdPdfUI/Shell/FlyoutPlacement.cs - the family flyout standard.) /// /// That rail-adjacent corner is the answer because of what bounds it, and all three matter: /// - it is INSIDE the window, so a flyout never hangs over the desktop; diff --git a/Controls/FolderTree.cs b/Controls/FolderTree.cs index 38f2f52..422bb85 100644 --- a/Controls/FolderTree.cs +++ b/Controls/FolderTree.cs @@ -11,7 +11,7 @@ using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; -namespace KillerPDF.Controls +namespace MmdPdf.Controls { // ═══════════════════════════════════════════════════════════ // FOLDER TREE - the file dialog's left pane, below places diff --git a/Controls/KillerDialog.cs b/Controls/KillerDialog.cs index a287656..9e38f14 100644 --- a/Controls/KillerDialog.cs +++ b/Controls/KillerDialog.cs @@ -10,9 +10,9 @@ using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using System.Windows.Shapes; -using KillerPDF.Services; +using MmdPdf.Services; -namespace KillerPDF +namespace MmdPdf { // ============================================================ // Themed dialog - replaces MessageBox for dark-UI consistency @@ -34,7 +34,7 @@ namespace KillerPDF public static MessageBoxResult Show( Window? owner, string message, - string title = "KillerPDF", + string title = "MmdPdf", MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxImage image = MessageBoxImage.None, bool fadeClose = true, @@ -76,9 +76,9 @@ namespace KillerPDF CornerRadius = new CornerRadius(5, 5, 0, 0) }; titleBar.MouseLeftButtonDown += (_, e) => { if (e.ButtonState == MouseButtonState.Pressed) win.DragMove(); }; - // When the title is just "KillerPDF", render it as the main window's wordmark - "Killer" + // When the title is just "MmdPdf", render it as the main window's wordmark - "Killer" // in the primary text color and "PDF" in the green logo accent, bold, with a soft shadow. - if (title == "KillerPDF") + if (title == "MmdPdf") { var wm = new StackPanel { Orientation = Orientation.Horizontal }; var wmTb = new TextBlock { VerticalAlignment = VerticalAlignment.Center }; @@ -216,7 +216,7 @@ namespace KillerPDF string message, string[] labels, int accentIndex = 0, - string title = "KillerPDF") + string title = "MmdPdf") { int result = -1; @@ -238,7 +238,7 @@ namespace KillerPDF var titleBar = new Border { Background = Application.Current.TryFindResource("UseDialogCaption") is true ? UiKit.Brush("TitleBarBrush") : Brushes.Transparent, Padding = new Thickness(16, 10, 16, 10) }; titleBar.MouseLeftButtonDown += (_, e) => { if (e.ButtonState == MouseButtonState.Pressed) win.DragMove(); }; - if (title == "KillerPDF") + if (title == "MmdPdf") { var wmTb = new TextBlock { VerticalAlignment = VerticalAlignment.Center }; wmTb.Inlines.Add(new System.Windows.Documents.Run("Killer") { FontFamily = UiKit.WordmarkFont, FontWeight = FontWeights.Normal, FontSize = 15, Foreground = R("TextBrush") }); @@ -308,7 +308,7 @@ namespace KillerPDF Window? owner, string message, string checkboxText, - string title = "KillerPDF", + string title = "MmdPdf", MessageBoxButton buttons = MessageBoxButton.OKCancel, MessageBoxResult? defaultResult = null) { @@ -358,7 +358,7 @@ namespace KillerPDF bool closeTabs = check1Initial; bool remember = check2Initial; - var win = new Window { Title = "KillerPDF", Width = 380, SizeToContent = SizeToContent.Height }; + var win = new Window { Title = "MmdPdf", Width = 380, SizeToContent = SizeToContent.Height }; // fade:false - the app's own fade-out follows immediately on confirm; two fades // back-to-back read as lag (same reasoning as the unsaved-changes prompt). DialogChrome.Configure(win, owner, fade: false); @@ -376,7 +376,7 @@ namespace KillerPDF var root = new StackPanel(); - // Title bar: the wordmark, exactly like Show()'s "KillerPDF" branch. + // Title bar: the wordmark, exactly like Show()'s "MmdPdf" branch. var titleBar = new Border { Background = Application.Current.TryFindResource("UseDialogCaption") is true ? UiKit.Brush("TitleBarBrush") : Brushes.Transparent, @@ -391,7 +391,7 @@ namespace KillerPDF wm.Children.Add(wmTb); titleBar.Child = wm; if (Application.Current.TryFindResource("UseDialogCaption") is true) - titleBar = DialogChrome.BuildTitleBar(win, owner, "KillerPDF", () => win.Close()); + titleBar = DialogChrome.BuildTitleBar(win, owner, "MmdPdf", () => win.Close()); titleBar.Height = Application.Current.TryFindResource("DialogTitleBarHeight") is double titleHeight ? titleHeight : double.NaN; root.Children.Add(titleBar); @@ -504,7 +504,7 @@ namespace KillerPDF // Enter anywhere in the field submits. pw.KeyDown += (_, e) => { if (e.Key == Key.Enter) { result = pw.Password; win.Close(); } }; - win.Content = DialogChrome.Frame(win, owner, "KillerPDF", CloseCancel, body); + win.Content = DialogChrome.Frame(win, owner, "MmdPdf", CloseCancel, body); win.Loaded += (_, _2) => pw.Focus(); win.ShowDialog(); return result; diff --git a/Controls/Picker.cs b/Controls/Picker.cs index 5ab6ebf..266cc2e 100644 --- a/Controls/Picker.cs +++ b/Controls/Picker.cs @@ -1,6 +1,6 @@ using System; -namespace KillerPDF.Controls +namespace MmdPdf.Controls { // Row and place models for FileDialog. public sealed class PickerPlace(string label, string path, bool pinned = false) diff --git a/Controls/PickerStyles.xaml b/Controls/PickerStyles.xaml index 861342a..69ba293 100644 --- a/Controls/PickerStyles.xaml +++ b/Controls/PickerStyles.xaml @@ -13,8 +13,8 @@ ============================================================ --> + xmlns:local="clr-namespace:MmdPdf.Controls" + xmlns:kui="clr-namespace:MmdPdf.Controls"> - - @@ -1139,7 +1139,7 @@ - + @@ -1165,24 +1165,24 @@ MouseWheel="LogoBar_MouseWheel" MouseLeftButtonDown="LogoBar_MouseLeftButtonDown"> - - - + - + @@ -1405,7 +1405,7 @@ from. Measured on the running app: the card's canvas is BgCanvas #3a3a3a (lum 58) and SurfaceBrush is #333333 (lum 51) - seven steps apart, so the 8px gutter read as the same gray as the card and the whole thing looked like one flat field with a hairline - in it, shadow and all. KillerShell gets its lift from PaneBrush #3a3a3a on + in it, shadow and all. MMD PDF gets its lift from PaneBrush #3a3a3a on BackgroundBrush #1c1c1c, thirty steps; this is the identical relationship, and it also matches the sidebar and footer, which already paint BackgroundBrush. The sidebar and the card both paint over this, so only the exposed gutter changes. --> @@ -1418,10 +1418,10 @@ shrinks to 24px (the toggle strip width). --> @@ -1521,7 +1521,7 @@ Foreground="{DynamicResource MutedTextBrush}" Margin="2,0,0,0"/> - @@ -2086,138 +2086,11 @@ -