Claude
Skills
Sign in
Back

killerpdf-portable-editor

Included with Lifetime
$97 forever

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.

Writing & Docs

What this skill does


# 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 (!IsDrawingMo

Related in Writing & Docs