Skip to main content

killerpdf-portable-editor

KillerPDF is a portable, single-EXE Windows PDF editor built with C#/WPF and PDFium — supports viewing, annotating, merging, splitting, signing, and printing PDFs with no installer, account, or telemetry.

Zur Installation springen

Quellinformationen

Repository
reason-machines/trending-skills
Letzte Quellaktivität
20. April 2026 um 20:50
Erkannte Sprache von SKILL.md
Englisch
Sterne
82
Forks
15

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
killerpdf-portable-editor
description
KillerPDF is a portable, single-EXE Windows PDF editor built with C#/WPF and PDFium — supports viewing, annotating, merging, splitting, signing, and printing PDFs with no installer, account, or telemetry.
triggers
["edit a PDF in C# WPF","portable PDF editor Windows no installer","merge split PDF dotnet wpf","annotate PDF without Adobe","KillerPDF setup and usage","add text boxes signatures to PDF C#","PDF freehand drawing highlight overlay dotnet","build KillerPDF from source"]
# KillerPDF Portable PDF Editor Skill > Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection. KillerPDF is a single-EXE (~6 MB zipped), portable Windows PDF editor for .NET Framework 4.8. It renders PDFs via PDFium (Docnet.Core), supports inline text editing, annotations, freehand drawing, highlights, signatures, merge/split, full-text search, and printing — all without Adobe, accounts, or telemetry. --- ## What KillerPDF Does | Capability | Details | |---|---| | Rendering | High-quality PDFium rendering via Docnet.Core | | Annotation | Text boxes, freehand draw, highlight overlays | | Editing | Inline text editing with font matching | | Pages | Merge multiple PDFs, split selected pages, drag-and-drop reorder | | Signatures | Draw/save reusable signatures, click to place | | Search | Full-text search with highlighting, drag-select to copy | | Print | Annotations flattened into output | | Distribution | Single EXE, no runtime, no admin rights | --- ## Getting the Binary ```powershell # Download latest prebuilt release Invoke-WebRequest -Uri "https://github.com/SteveTheKiller/KillerPDF/releases/latest/download/KillerPDF.zip" -OutFile "KillerPDF.zip" Expand-Archive -Path "KillerPDF.zip" -DestinationPath ".\KillerPDF" .\KillerPDF\KillerPDF.exe ``` No installer, no admin rights required. Just unzip and run. --- ## Building from Source ### Requirements - Windows 10/11 x64 - .NET 8 SDK or later (to build; output targets .NET Framework 4.8) - Git ### Clone and Build ```powershell git clone https://github.com/SteveTheKiller/KillerPDF.git cd KillerPDF dotnet publish -c Release ``` Output lands in `bin/Release/net48/publish/`. The publish step produces: - `KillerPDF.exe` — single Costura-bundled executable - `KillerPDF-<version>-src.zip` — GPL3 corresponding source archive ### Project Structure ``` KillerPDF/ ├── App.xaml / App.xaml.cs # Application entry, theming ├── MainWindow.xaml / .cs # Primary WPF window, toolbar, page canvas ├── PdfDocument.cs # PDFium wrapper (Docnet.Core), load/save/render ├── PageViewModel.cs # Page data binding, annotation layer ├── AnnotationCanvas.cs # Custom Canvas for drawing/annotation ├── SignatureManager.cs # Save/load/place signatures ├── MergeWindow.xaml / .cs # Merge multiple PDFs UI ├── SplitWindow.xaml / .cs # Page selection and split UI ├── SearchPanel.xaml / .cs # Full-text search UI ├── PrintHelper.cs # Flatten annotations and print ├── Models/ │ ├── Annotation.cs # Base annotation model │ ├── TextBoxAnnotation.cs │ ├── DrawingAnnotation.cs │ └── HighlightAnnotation.cs └── Resources/ └── Icons/ # SVG/PNG toolbar icons ``` --- ## Key Dependencies ```xml <!-- KillerPDF.csproj (simplified) --> <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net48</TargetFramework> <UseWPF>true</UseWPF> <AssemblyName>KillerPDF</AssemblyName> </PropertyGroup> <ItemGroup> <!-- PDFium rendering --> <PackageReference Include="Docnet.Core" Version="2.6.0" /> <!-- Single-EXE bundling --> <PackageReference Include="Costura.Fody" Version="5.7.0" /> <PackageReference Include="Fody" Version="6.8.0" /> </ItemGroup> </Project> ``` --- ## Core Patterns and Code Examples ### Opening and Rendering a PDF Page ```csharp using Docnet.Core; using Docnet.Core.Models; using System.Windows.Media.Imaging; using System.Runtime.InteropServices; public class PdfDocument : IDisposable { private IDocLib _docLib; private IDocReader _docReader; private readonly string _filePath; public int PageCount { get; private set; } public void Open(string filePath, string password = "") { _filePath = filePath; _docLib = DocLib.Instance; _docReader = string.IsNullOrEmpty(password) ? _docLib.GetDocReader(filePath, new PageDimensions(1080, 1920)) : _docLib.GetDocReader(filePath, password, new PageDimensions(1080, 1920)); PageCount = _docReader.GetPageCount(); } public BitmapSource RenderPage(int pageIndex, double dpi = 150) { using var pageReader = _docReader.GetPageReader(pageIndex); int width = pageReader.GetPageWidth(); int height = pageReader.GetPageHeight(); var rawBytes = pageReader.GetImage(); // BGRA byte array var bitmap = new WriteableBitmap(width, height, dpi, dpi, System.Windows.Media.PixelFormats.Bgra32, null); bitmap.WritePixels( new System.Windows.Int32Rect(0, 0, width, height), rawBytes, width * 4, 0); bitmap.Freeze(); return bitmap; } public string GetPageText(int pageIndex) { using var pageReader = _docReader.GetPageReader(pageIndex); return pageReader.GetText(); } public void Dispose() { _docReader?.Dispose(); _docLib?.Dispose(); } } ``` ### Annotation Model Hierarchy ```csharp // Models/Annotation.cs public abstract class Annotation { public Guid Id { get; } = Guid.NewGuid(); public int PageIndex { get; set; } public System.Windows.Rect Bounds { get; set; } public double Opacity { get; set; } = 1.0; public abstract UIElement ToUIElement(); public abstract void FlattenToPdfPage(PdfPage page); } // Models/TextBoxAnnotation.cs public class TextBoxAnnotation : Annotation { public string Text { get; set; } = ""; public string FontFamily { get; set; } = "Arial"; public double FontSize { get; set; } = 12; public System.Windows.Media.Color Color { get; set; } = System.Windows.Media.Colors.Black; public override UIElement ToUIElement() { var tb = new TextBox { Text = Text, FontFamily = new System.Windows.Media.FontFamily(FontFamily), FontSize = FontSize, Foreground = new System.Windows.Media.SolidColorBrush(Color), Background = System.Windows.Media.Brushes.Transparent, BorderThickness = new Thickness(0), AcceptsReturn = true, Width = Bounds.Width, Height = Bounds.Height, Opacity = Opacity, }; Canvas.SetLeft(tb, Bounds.X); Canvas.SetTop(tb, Bounds.Y); return tb; } public override void FlattenToPdfPage(PdfPage page) { // Write text at PDF coordinates using PdfSharp or iTextSharp // KillerPDF uses PDFium for reading and a lightweight writer for output } } // Models/HighlightAnnotation.cs public class HighlightAnnotation : Annotation { public System.Windows.Media.Color HighlightColor { get; set; } = System.Windows.Media.Colors.Yellow; public override UIElement ToUIElement() { var rect = new System.Windows.Shapes.Rectangle { Fill = new System.Windows.Media.SolidColorBrush( System.Windows.Media.Color.FromArgb( (byte)(Opacity * 128), HighlightColor.R, HighlightColor.G, HighlightColor.B)), Width = Bounds.Width, Height = Bounds.Height, }; Canvas.SetLeft(rect, Bounds.X); Canvas.SetTop(rect, Bounds.Y); return rect; } public override void FlattenToPdfPage(PdfPage page) { /* flatten */ } } ``` ### Freehand Drawing on the Annotation Canvas ```csharp // AnnotationCanvas.cs — custom WPF Canvas public class AnnotationCanvas : Canvas { private Polyline _currentStroke; private List<Point> _points = new(); public System.Windows.Media.Color PenColor { get; set; } = System.Windows.Media.Colors.Red; public double PenThickness { get; set; } = 2.0; public bool IsDrawingMode { get; set; } protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { if (!IsDrawingMode) return; _points.Clear(); _currentStroke = new Polyline { Stroke = new SolidColorBrush(PenColor), StrokeThickness = PenThickness, StrokeLineJoin = PenLineJoin.Round, StrokeStartLineCap = PenLineCap.Round, StrokeEndLineCap = PenLineCap.Round, }; Children.Add(_currentStroke); CaptureMouse(); AddPoint(e.GetPosition(this)); } protected override void OnMouseMove(MouseEventArgs e) { if (!IsDrawingMode || _currentStroke == null || e.LeftButton != MouseButtonState.Pressed) return; AddPoint(e.GetPosition(this)); } protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { if (!IsDrawingMode || _currentStroke == null) return; ReleaseMouseCapture(); // Commit stroke as DrawingAnnotation var ann = new DrawingAnnotation { Points = _points.ToList(), Color = PenColor, Thickness = PenThickness }; AnnotationCommitted?.Invoke(this, ann); _currentStroke = null; } private void AddPoint(Point p) { _points.Add(p); _currentStroke.Points.Add(p); } public event EventHandler<DrawingAnnotation> AnnotationCommitted; } ``` ### Signature Manager ```csharp // SignatureManager.cs public class SignatureManager { private readonly string _sigDir; public SignatureManager() { // Signatures stored next to EXE — portable, no AppData _sigDir = Path.Combine( Path.GetDirectoryName( System.Reflection.Assembly.GetExecutingAssembly().Location)!, "Signatures"); Directory.CreateDirectory(_sigDir); } // Save ink strokes as PNG public void Save(string name, RenderTargetBitmap bitmap) { var encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmap)); using var fs = File.OpenWrite(Path.Combine(_sigDir, name + ".png")); encoder.Save(fs); } // Load all saved signatures public IEnumerable<(string Name, BitmapImage Image)> LoadAll() { foreach (var file in Directory.EnumerateFiles(_sigDir, "*.png")) { var img = new BitmapImage(new Uri(file)); img.Freeze(); yield return (Path.GetFileNameWithoutExtension(file), img); } } // Place signature as Image UIElement on canvas public Image PlaceSignature(BitmapImage sigImage, Point position, double scale = 1.0) { var img = new Image { Source = sigImage, Width = sigImage.PixelWidth * scale, Height = sigImage.PixelHeight * scale, Opacity = 0.9, }; Canvas.SetLeft(img, position.X); Canvas.SetTop(img, position.Y); return img; } } ``` ### Merging PDFs ```csharp // MergeWindow.xaml.cs (core merge logic) public static void MergePdfs(IEnumerable<string> inputPaths, string outputPath) { // KillerPDF uses PDFium C++ API via P/Invoke or a lightweight wrapper // Conceptual pattern using PdfSharp (or equivalent internal helper): using var output = new PdfDocument(); // PdfSharp or internal writer foreach (var path in inputPaths) { using var input = PdfReader.Open(path, PdfDocumentOpenMode.Import); for (int i = 0; i < input.PageCount; i++) output.AddPage(input.Pages[i]); } output.Save(outputPath); } ``` ### Splitting Pages ```csharp public static void SplitPages(string inputPath, IEnumerable<int> pageIndices, string outputPath) { using var input = PdfReader.Open(inputPath, PdfDocumentOpenMode.Import); using var output = new PdfDocument(); foreach (var idx in pageIndices) output.AddPage(input.Pages[idx]); output.Save(outputPath); } ``` ### Full-Text Search ```csharp // SearchPanel.xaml.cs public List<(int PageIndex, System.Windows.Rect Rect)> Search( string query, PdfDocument doc) { var results = new List<(int, System.Windows.Rect)>(); var docLib = DocLib.Instance; using var reader = docLib.GetDocReader(doc.FilePath, new PageDimensions(1080, 1920)); for (int i = 0; i < reader.GetPageCount(); i++) { using var page = reader.GetPageReader(i); var text = page.GetText(); if (!text.Contains(query, StringComparison.OrdinalIgnoreCase)) continue; // Get character bounding boxes for highlighting var chars = page.GetCharacters(); // Match positions and build highlight Rects // (KillerPDF uses character-level positions from PDFium) int idx = text.IndexOf(query, StringComparison.OrdinalIgnoreCase); while (idx >= 0 && idx + query.Length <= chars.Count) { var first = chars[idx]; var last = chars[idx + query.Length - 1]; var rect = new System.Windows.Rect( first.Box.Left, first.Box.Top, last.Box.Right - first.Box.Left, last.Box.Bottom - first.Box.Top); results.Add((i, rect)); idx = text.IndexOf(query, idx + 1, StringComparison.OrdinalIgnoreCase); } } return results; } ``` ### Printing with Flattened Annotations ```csharp // PrintHelper.cs public static void PrintDocument(BitmapSource[] renderedPages, string docTitle) { var pd = new PrintDialog(); if (pd.ShowDialog() != true) return; var doc = new FixedDocument(); foreach (var page in renderedPages) { var pageContent = new PageContent(); var fixedPage = new FixedPage { Width = pd.PrintableAreaWidth, Height = pd.PrintableAreaHeight, }; var img = new Image { Source = page, Width = pd.PrintableAreaWidth, Height = pd.PrintableAreaHeight, Stretch = System.Windows.Media.Stretch.Uniform, }; fixedPage.Children.Add(img); ((IAddChild)pageContent).AddChild(fixedPage); doc.Pages.Add(pageContent); } var xpsWriter = PrintQueue.CreateXpsDocumentWriter( pd.PrintQueue); xpsWriter.Write(doc); } // Flatten annotations: render page + annotation canvas to BitmapSource public static BitmapSource FlattenPage(BitmapSource pdfPageBitmap, AnnotationCanvas canvas, int width, int height) { var visual = new DrawingVisual(); using (var ctx = visual.RenderOpen()) { ctx.DrawImage(pdfPageBitmap,
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen