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.
| Light theme — the editor with the tool palette and the properties panel | Dark theme — the same document |
![]() |
![]() |
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.
- What Orion is
- Features
- Download
- Installation from source
- Usage
- How it works
- Requirements
- Development
- Testing
- Building a standalone executable
- Troubleshooting
- Scope and limitations
- License & Commercial Licensing
- Contributing
- Disclaimer
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.
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
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.
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 # Windowssha256sum Orion-1.0.0-linux-x64.tar.gz # Linux
shasum -a 256 Orion-1.0.0-macos-arm64.zip # macOSThat 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.
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.
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 .
orionOr without installing:
pip install -r requirements.txt
python -m orionOpen a document straight away with orion path/to/file.pdf, and check the build with
orion --version.
PySide6 needs a few shared libraries that some minimal images omit:
sudo apt install libegl1 libgl1 libxkbcommon0 libdbus-1-3 libfontconfig1Open 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 |
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.
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.
- 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 |
pip install -e ".[dev]"
ruff check orion tests # lintdocs/DEVELOPMENT.md covers the layout, the conventions and how to add a new
object type or tool. CONTRIBUTING.md covers the contribution process.
pytest # the whole suite, GUI tests includedThe GUI tests drive the real widgets, so they need a display. On a headless
machine set QT_QPA_PLATFORM=offscreen:
QT_QPA_PLATFORM=offscreen pytestCI 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.
pip install . pyinstaller
pyinstaller --noconfirm --clean orion.specThe 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.
| 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. |
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.
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.
| 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 | 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.
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.
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.
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/commandsandorion/utilsmust 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.tomlandorion/__init__.py, and add aCHANGELOG.mdentry.
CONTRIBUTING.md covers the process in full, and
docs/DEVELOPMENT.md the layout and conventions.
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:
- work on a copy, or use Save As rather than Save,
- reopen the result and check it in a second reader,
- 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.


