Skip to content
MarcoLombardoDevPublic

About

Offline desktop PDF editor for viewing, editing, annotating, redacting, and reorganising documents. Supports PDF forms and converts XFA/LiveCycle forms into ordinary fillable PDFs, with text, images, annotations, page management, watermarks, and no cloud or telemetry.

Topics

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

📄 Orion — PDF Editor for Desktop

License: AGPL v3 Commercial Licence Available Python 3.10+ CI

An offline PDF viewer, editor, annotator and page organiser. Read documents, add things to them, annotate them, reorganise their pages — then save a normal PDF that any other reader can open.

🔒 No account. No server. No cloud. No telemetry. Everything happens on your machine, and your original file is never touched until you press Save. 💼 Commercial or redistribution use (including OEM)? See COMMERCIAL-LICENSE.md, or write to marco.lombardo@gmail.com.


Screenshots

Light theme — the editor with the tool palette and the properties panel Dark theme — the same document
Orion, light theme Orion, dark theme

A converted form. This document is an XFA form: everywhere else it opens as a page saying "if this message is not eventually replaced…". Orion rebuilt it as an ordinary PDF, and on the canvas every part of it is an object — the fields, the captions, the headings — so three labels can be selected and lined up like anything else.

A converted XFA form in Orion, with its fields and captions as objects


Table of Contents

  1. What Orion is
  2. Features
  3. Download
  4. Installation from source
  5. Usage
  6. How it works
  7. Requirements
  8. Development
  9. Testing
  10. Building a standalone executable
  11. Troubleshooting
  12. Scope and limitations
  13. License & Commercial Licensing
  14. Contributing
  15. Disclaimer

What Orion is

Orion is a desktop application for working on PDF documents: read them, add things to them, annotate them, and reorganise their pages — then save a normal PDF that any other reader can open.

It is not a wrapper around a web service. Everything happens on your machine, and your original file is never touched until you press Save.

It also opens the documents that nothing else will. An XFA form — the kind that shows "if this message is not eventually replaced…" in every browser and most readers — is rebuilt as an ordinary PDF you can fill in, with a summary that states plainly what came across and what could not. On the page afterwards there is nothing you cannot pick up: its fields, its captions and its headings are all objects.

Features

Viewing

  • Open, close and reopen recent documents
  • Continuous multi-page view with page thumbnails
  • First / previous / next / last page, and go-to-page
  • Zoom in and out, an exact zoom percentage, fit page and fit width
  • Full-document text search with highlighted results

Editing

  • Text — click or drag to place a text box, then edit it in place. Font, size, bold, italic, underline, colour, alignment, line spacing, opacity, position, size and rotation. Written as real, selectable, searchable PDF text.

  • Images — insert PNG, JPEG and WEBP, with aspect-ratio locking, opacity and free rotation. Drag an image file onto the page to place it.

  • Shapes — rectangle, ellipse, line and arrow, with stroke colour and width, fill colour, opacity and rotation.

  • Annotations — highlight, underline and strikeout that snap to the document's own text lines, freehand drawing, comments and sticky notes. All written as standard PDF annotations, so other readers understand them.

  • Redaction — drag a box over anything that must not survive. The covered content is deleted from the saved page, not hidden behind a rectangle.

  • XFA forms — the LiveCycle forms that open as "if this message is not eventually replaced…" everywhere else. Orion reads the form out of the file, works out the layout the way an XFA viewer would, and writes an ordinary PDF with real, fillable fields: text, numbers, dates, tick boxes, either/or groups and drop-downs, keeping position, size, font, value, options, required and read-only, along with the rows already in a repeating table.

    A form that was filled in and saved comes back as it was filled in: every row of every table with its own values, the sections a script had revealed, dates and amounts in the form's own format, long tables continued onto the next page with their headings repeated, and page numbers in the footer.

    Print, save and reset buttons still work — through the actions PDF has for them, not through carried-over script. The rest of a form's programming (calculations, rules, sections that grow on demand) cannot come across, and the summary afterwards says so in as many words: appearance and behaviour are reported as two separate figures, never averaged into one flattering number. The original file is never touched.

    No XFA script is ever executed — not while parsing, analysing or converting — and nothing a document points at is fetched or opened.

  • Watermarks and page numbers — stamp a word across a run of pages, or number them from a Page {n} of {total} template, in any of six positions. Both are real text, and ordinary objects afterwards.

Working with objects

  • Select one or many; drag-select; Ctrl/Cmd-click to extend a selection
  • Move, resize from eight handles, and rotate freely (hold Shift to snap)
  • Arrow keys nudge, Shift+arrows nudge further
  • Align a selection left, right, top or bottom — everything moves to the outermost edge already in the selection, and nothing is resized
  • Cut, copy, paste and duplicate — including between two Orion windows
  • Bring to front and send to back, on one object or a whole selection
  • Form fields are objects too. The fields of any PDF form — converted or not — can be selected, moved, resized and deleted, and they keep everything that makes them fields: name, options, required, read-only, tooltip. The widget in the file is moved rather than rebuilt.
  • The page's own text can be made movable, from the button under Pan on the tool palette: every line becomes a text box where it already is. A converted form arrives that way, because Orion drew those words itself.
  • Unlimited, per-action undo and redo

Pages

  • Insert a blank page, duplicate, delete
  • Reorder by dragging thumbnails
  • Rotate 90°, 180° or 270°
  • Import pages from another PDF
  • Extract pages into a new PDF
  • Split a document every N pages or by explicit page ranges
  • Merge several PDFs, in an order you choose

Files

  • Save and Save As, written atomically so an interrupted save cannot damage your document
  • Export pages as PNG or JPEG, from 72 to 600 DPI
  • Read and edit the document's title, author, subject and keywords
  • Crash recovery: unsaved work is snapshotted separately from your PDF
  • Light and dark themes
  • English and Italian, switched from the menu without a restart. An Italian desktop gets Italian on a first run; everything else gets English
  • A command palette (Ctrl/Cmd+Shift+P) that searches every command by name

Download

Standalone builds for Windows, macOS and Linux are attached to every release:

Platform File
Windows (x64) Orion-<version>-windows-x64.zip
macOS (Apple silicon) Orion-<version>-macos-arm64.zip
Linux (x64) Orion-<version>-linux-x64.tar.gz

Each archive is built on that platform's own runner — PyInstaller does not cross-compile, so nothing here is emulated or claimed for a platform that was not actually built. Unpack and run: no installation, and no Python needed.

Every archive unpacks to a single Orion/ folder holding the program, a start script beside it, and the checksum that script checks:

Windows macOS Linux
the program Orion.exe Orion.app Orion
start it with start.cmd start.command start.sh
what that checks Orion.exe.sha256 Orion.sha256 Orion.sha256

Start it through the script. It recomputes the program's digest and compares it against the one recorded when the archive was built, then hands over. A truncated download and a half-finished unpack both produce something that looks like a working program until it isn't; this is where they get caught, with one sentence, instead of somewhere further in. If the two disagree the script stops and says so rather than launching.

The program is still there and still starts on its own — the script only checks first. ORION_SKIP_VERIFY=1 turns the check off for anyone who has changed the executable on purpose.

Windows and macOS will warn on first launch

These builds carry no code-signing certificate. A certificate costs money every year and identifies a legal entity; Orion is one person's project given away under the AGPL, and the certificate is the one part of shipping software that cannot be done for nothing. So the operating system has no publisher to check, and says so.

On Windows, Microsoft Defender SmartScreen shows "Windows protected your PC" and offers only Don't run. Click More info, then Run anyway.

On macOS, Gatekeeper refuses to open an app from an unidentified developer. Right-click it and choose Open, or run xattr -dr com.apple.quarantine Orion.app.

Neither warning means anything is wrong with the file. Both mean the same thing: nobody has paid to put a name on it.

Check the download instead. Every release lists the SHA-256 of each archive, as the build machine produced it, under Checksums in the release notes. Compute your copy's and compare:

Get-FileHash .\Orion-1.0.0-windows-x64.zip -Algorithm SHA256      # Windows
sha256sum Orion-1.0.0-linux-x64.tar.gz                             # Linux
shasum -a 256 Orion-1.0.0-macos-arm64.zip                          # macOS

That is a weaker guarantee than a signature — it proves the file was not altered between the build and your disk, not who wrote it — but it is the part a signature would give you that can be given for free, and it is what the warning is actually asking about.

Those are the digests worth checking, and the Orion.sha256 inside the archive is not a substitute for them. A checksum that travels with the file it describes can only tell you the file is undamaged: whoever could replace the one could replace the other. The digests on the release page arrive by a different route, which is the entire reason they are worth anything — and why they are printed there rather than offered as three more downloads.

If your antivirus or EDR flags it

An unsigned executable that arrived from the internet, was built by PyInstaller and has never been seen before is, on paper, the profile of something worth looking at. Corporate endpoint tools score exactly that and some will quarantine Orion on sight.

What Orion does about it is refuse to make the case worse where it has a choice. It carries a full Windows version resource, so the file says what it is and who wrote it rather than declining to answer. It is not packed — no UPX. Its launcher hashes the executable with PowerShell's Get-FileHash rather than borrowing certutil, which is on every living-off-the-land list there is. And it names the graphics backend it wants instead of asking Windows about your display adapter, a question it has no use for the answer to.

One thing it does do, and from 1.9.0 it is new. The release is a single executable rather than a folder of files, which means that on every launch it unpacks itself into a temporary folder and runs the copy. Self-extraction followed by process creation is a behaviour worth flagging in general, and an endpoint agent is right to notice it. It was a deliberate trade — every product in this family ships as one file now, and the reason is consistency for the people who use more than one of them, not anything technical. If your organisation's tooling quarantined Orion before, this makes that more likely rather than less, and 1.8.0 remains on the releases page as a folder build.

What remains beyond that is inherent to the shape of the thing: it is a compiled Python program, so it has the section names PyInstaller gives it and imports the functions CPython and Qt import. Those are observations, not findings.

If something still trips, the useful things to send are the detection name, the engine that raised it, and the indicators listed against it. All of it is reproducible from source — the whole point of the licence is that you do not have to take the binary's word for anything.

Installation from source

Orion needs Python 3.10 or newer.

git clone https://github.com/MarcoLombardoDev/Orion.git
cd Orion
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -e .
orion

Or without installing:

pip install -r requirements.txt
python -m orion

Open a document straight away with orion path/to/file.pdf, and check the build with orion --version.

Linux system packages

PySide6 needs a few shared libraries that some minimal images omit:

sudo apt install libegl1 libgl1 libxkbcommon0 libdbus-1-3 libfontconfig1

Usage

Open a PDF, pick a tool from the palette on the left, and work on the page. The panel on the right shows the properties of whatever is selected, and the thumbnails on the left reorder pages by dragging.

A full walkthrough — including every keyboard shortcut — is in docs/USER_GUIDE.md.

The shortcuts you will use most:

Ctrl/Cmd + O Open
Ctrl/Cmd + S Save
Ctrl/Cmd + Shift + S Save As
Ctrl/Cmd + Z / Ctrl/Cmd + Y Undo / Redo
Ctrl/Cmd + C / V / X / D Copy / Paste / Cut / Duplicate
Ctrl/Cmd + F Find
Ctrl/Cmd + 1 / 2 / 0 Fit page / Fit width / 100%
V H T I R O L A P N Pick a tool
Delete Delete the selection
Esc Cancel the current operation

How it works

Architecture

UI  (orion/ui)            Qt widgets, the canvas, the panels
        │
Commands (orion/commands) undo/redo — deltas, not snapshots
        │
Document (orion/document) Document · Page · Text/Image/Shape/Annotation
        │
PDF engine (orion/pdf)    reader · renderer · writer · operations
        │
pypdfium2 · pypdf · reportlab · Pillow

The rule the whole design follows: the UI never manipulates the PDF file. It edits an in-memory document model; the file is read for rendering and written only when you save. That is what makes undo cheap, autosave a serialisation, and your original file safe.

orion/document, orion/commands and orion/utils do not import Qt at all, so the model is testable without a display. CI proves it rather than trusting the convention: a job installs every dependency except PySide6 and imports those layers.

The full reasoning, the coordinate system, and the known technical risks are in docs/ARCHITECTURE.md.

Where files are stored

Orion keeps nothing beside your documents. Settings, the recent-files list and crash recovery snapshots live in the platform's own application-data directory (%APPDATA% on Windows, ~/Library/Application Support on macOS, $XDG_CONFIG_HOME on Linux). A recovery snapshot is written next to that state, never over your PDF.

Requirements

  • Python 3.10 or newer (source install only — the released builds bundle their own)
  • A desktop environment; on Linux, the shared libraries listed under Installation from source
Dependency Purpose
PySide6 ≥ 6.6 The interface
pypdfium2 ≥ 4.30 Rendering pages, extracting and searching text
pypdf ≥ 4.0 Assembling documents, page operations, annotations
reportlab ≥ 4.0 Drawing added text, shapes and images
Pillow ≥ 10.0 Image decoding for inserted pictures

Development

pip install -e ".[dev]"
ruff check orion tests       # lint

docs/DEVELOPMENT.md covers the layout, the conventions and how to add a new object type or tool. CONTRIBUTING.md covers the contribution process.

Testing

pytest                       # the whole suite, GUI tests included

The GUI tests drive the real widgets, so they need a display. On a headless machine set QT_QPA_PLATFORM=offscreen:

QT_QPA_PLATFORM=offscreen pytest

CI runs the suite on Linux, Windows and macOS, on Python 3.10 and 3.12, plus a lint job and the Qt-free-layers check described under How it works.

Building a standalone executable

pip install . pyinstaller
pyinstaller --noconfirm --clean orion.spec

The result lands in dist/Orion/ — dist/Orion.app as well, on macOS. It is native to whatever machine built it: PyInstaller does not cross-compile, so a Windows .exe needs Windows, a Mach-O binary needs macOS, and an ELF binary needs Linux.

Without three machines, .github/workflows/release.yml is the way to get all three. Push a v* tag, or run the workflow by hand from the Actions tab and give it the tag: it builds on windows-latest, macos-latest and ubuntu-latest, smoke-tests every bundle with --version before publishing it, and attaches one archive per platform to the release.

Troubleshooting

Symptom Cause and fix
ImportError mentioning libEGL or libxkbcommon on Linux The Qt shared libraries are missing — install the packages under Linux system packages.
The application starts and immediately exits on a headless machine There is no display. Set QT_QPA_PLATFORM=offscreen for tests; the editor itself needs a real one.
Antivirus or a corporate EDR quarantines Orion Unsigned, PyInstaller-built and new: see If your antivirus or EDR flags it.
Windows SmartScreen or macOS Gatekeeper blocks the download Expected: the builds are unsigned. See Windows and macOS will warn on first launch.
Text added to a page is not selectable in another reader Only text placed with the Text tool is written as real PDF text. Freehand ink and comments are annotations by design.
A saved file looks different in another viewer Report it with the source document attached, if you can share it — differences between PDF writers are the kind of bug worth a test.

Scope and limitations

Orion 1.0 deliberately stops at a solid, offline editor.

Not yet, but planned:

  • Several documents open at once, in tabs
  • Embedding arbitrary TrueType fonts in text objects (1.0 uses the base-14 PDF fonts)
  • Optional OCR through Tesseract, as a separate module
  • Filling in form fields from Orion. Their geometry is already editable — a field can be moved, resized and deleted — but typing a value into one is a reader's job for now.
  • Reflowing the original text of a PDF. A line, or a whole page, can be taken over and retyped where it stands; what is not there is a word processor's idea of a paragraph that rewraps as you type.

Explicitly out of scope, permanently: AI features, cloud sync, accounts, telemetry.

License & Commercial Licensing

Orion is open-source software released under the GNU Affero General Public License v3.0 (AGPL-3.0).

Copyright © 2026 Marco Lombardo.

The free build is the whole product. Every feature documented above is in it. There is no paid edition, no feature gate, no licence key, no seat limit and no phone-home. If AGPL-3.0 works for you, you are done reading — Orion is yours to use.

What AGPL-3.0 Means for You

Use Case Allowed? Obligation
Internal use, any number of machines and users ✅ Yes None
Modify it and keep the changes to yourself ✅ Yes None
Fork and publish on GitHub ✅ Yes Must stay AGPL-3.0
Redistribute it, modified or not, under AGPL-3.0 ✅ Yes Must ship the source
Deploy a modified version as a network service ✅ Yes Must publish the source of your modified version
Integrate into a closed-source product used internally ⚠️ Restricted Requires a Commercial licence
Offer as a proprietary SaaS without sharing source ❌ Not under AGPL Requires a Redistribution licence
Embed it in, or ship it inside, a product you sell to third parties ❌ Not under AGPL Requires a Redistribution licence

The dividing line is one rule: AGPL-3.0 is free as long as the source stays open.

Commercial Licensing

The commercial offer removes the copyleft obligation, and nothing else. It splits into two branches that answer different questions — Commercial, sized by how big the organisation using Orion internally is, and Redistribution, needed whenever the software (or a derivative) reaches third parties, regardless of size:

Community         AGPL-3.0, free
Commercial        Small (1–49 employees) · Medium (50–249) · Large (250–999) · Enterprise (1,000+ / group)
Redistribution    Standard · Enterprise
Tier Price Perpetual Scope
Community Free — Everything Orion does, under AGPL-3.0. Unlimited internal use.
Commercial — Small €900 / year €2,700 1–49 employees, internal use, one legal entity.
Commercial — Medium €1,800 / year €5,400 50–249 employees, internal use, one legal entity.
Commercial — Large €3,200 / year €9,600 250–999 employees, internal use, one legal entity.
Commercial — Enterprise from €5,500 / year — 1,000+ employees, or a Corporate Group scope.
Redistribution — Standard €2,900 / year €8,700 Embed it in a product you sell, or ship it to customers.
Redistribution — Enterprise from €10,000 / year — Large-scale distribution — worldwide, high volume, or OEM.

A perpetual licence is three times the annual rate of the same tier, bought once, covering the major version current at purchase. Both Enterprise tiers are negotiated per case instead.

The same commitments apply at every paid tier:

  • Email support is always included — 5 business days at Commercial Small down to 2 at either Enterprise tier. It is never sold separately to a paying customer.
  • Custom development is never included, at any tier. It is available on request and quoted separately, per project, at a fixed price agreed before work starts (indicative day rate: €500 / day).
  • No retroactive price rise, cancel any time. Versions released during your term stay licensed to you.
  • 50% off for organisations under 10 employees and €1M revenue. Free commercial licences for non-profits, academia and published research — ask.

A Commercial licence, below Enterprise, covers exactly one legal entity: it does not automatically extend to other companies in the same group, and it does not include redistribution, OEM or embedding rights — those need a Redistribution licence on top. Prices are per licensed legal entity, excluding VAT. Seats are never counted. Full terms, the Employee Count and Corporate Group definitions, and the third-party component review: COMMERCIAL-LICENSE.md.

⚠️ One dependency is not permissively licensed. PySide6 is offered under LGPL-3.0, GPL-2.0 or GPL-3.0. A commercial licence to Orion covers Orion's own code and cannot relicense it: its terms stay between you and The Qt Company. Everything else — the PDF engine included — is BSD, MIT or Apache. The full table is in §11, and every component in a build is inventoried in THIRD-PARTY-LICENSES.md.

How to get in touch

Everything commercial — buying a licence, asking for a quote, commissioning custom development, or checking whether you need a licence at all (the answer is often no) — goes to one address:

marco.lombardo@gmail.com — Marco Lombardo

Please keep GitHub Issues for bugs and feature requests, not for licensing.

Contributing

Contributions are welcome. All contributors must agree to the Contributor License Agreement (CLA) before a Pull Request can be merged. The CLA grants the Project Owner the right to dual-license contributions under AGPL-3.0 and commercial terms — this is what makes the dual-licensing model sustainable.

To agree to the CLA: include I have read and agree to the Contributor License Agreement (CLA.md). in your Pull Request description.

Practical expectations:

  • Orion is an offline desktop application. Contributions adding network access, accounts, telemetry, analytics, cloud storage or a licensing system will not be merged, however well written.
  • orion/document, orion/commands and orion/utils must stay Qt-free; CI proves it by importing them without PySide6 installed.
  • Every bug fix arrives with a test that fails without the fix.
  • Bump the version in pyproject.toml and orion/__init__.py, and add a CHANGELOG.md entry.

CONTRIBUTING.md covers the process in full, and docs/DEVELOPMENT.md the layout and conventions.

Disclaimer

Orion edits and rewrites PDF documents. It never touches your original file until you press Save, and Save As leaves it alone entirely — but no safety net replaces your own backups, and a PDF written by any tool can differ from the original in ways a viewer does not show.

Before editing something irreplaceable:

  1. work on a copy, or use Save As rather than Save,
  2. reopen the result and check it in a second reader,
  3. keep an independent backup of the original.

The software is provided "as is", without warranty of any kind, as set out in sections 15 and 16 of the AGPL-3.0. The authors accept no liability for data loss or for any damage arising from its use.


Copyright © 2026 Marco Lombardo. Licensed under AGPL-3.0 — commercial licensing available.

About

Offline desktop PDF editor for viewing, editing, annotating, redacting, and reorganising documents. Supports PDF forms and converts XFA/LiveCycle forms into ordinary fillable PDFs, with text, images, annotations, page management, watermarks, and no cloud or telemetry.

Topics

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages