A Python tool to convert PDF/SVG files to Xournal++ format (.xopp).
- Converts vector PDFs (GoodNotes, OneNote, Xournal++, LaTeX, ...) to editable Xournal++ objects.
- Attempts to convert raster-only PDFs into editable Xournal++ objects by vectorizing their contents. The original pixmap is embedded in a seperate layer. For Samsung Notes files, first convert them to vector PDFs using sdocx2pdf.
- Converts SVGs using Inkscape (first transforms the SVG into a PDF) to editable Xournal++ objects. The conversion is currently somewhat unreliable.
- Two handwriting modes:
- filled (default): ink outlines rendered as filled area strokes
- line (
--line): ink outlines reduced to a centerline stroke via ellipse centroid heuristic embedded bitmap preserved as background layer, re-vectorized via skeletonization into an editable stroke layer
- Extracts and embeds text spans with font mapping
- Extracts and embeds bitmaps
- Repairs LaTeX diacritic sequences (ä, ö, ü, …) incorrectly extracted by PyMuPDF
- Detects and filters some background grid/dots automatically in separate layer
- Optionally embeds invisible OCR text for full-text search in Xournal++ in white in separate layer
- Appends pages to existing
.xoppfiles
- Python 3.9+
- PyMuPDF (
fitz) — PDF parsing and text extraction - OpenCV (
cv2) — image processing for raster PDFs - NumPy (
numpy) — numerical operations - scikit-image (
skimage) — skeletonization of raster strokes
- Inkscape — required for SVG input conversion
Download and run pdf2xopp.py .
python3 ./pdf2xopp.py [-h] [--append FILE.xopp] [--line] [--include-background] [--include-ocr] [--debug N] input.pdf
or (after chmod +x ./pdf2xopp.py)
./pdf2xopp.py [-h] [--append FILE.xopp] [--line] [--include-background] [--include-ocr] [--debug N] input.pdf
| Option | Description |
|---|---|
--append FILE.xopp |
Append pages to an existing .xopp file (created if missing) |
--line |
Use centerline mode for handwriting strokes |
--include-background |
Keep background grid lines as a separate layer |
--include-ocr |
Embed invisible OCR text for search indexing in white in a separate layer |
--debug N |
Enable debug output at verbosity level N |
-
Because the program code is AI-generated, it is quite possible that everything is somewhat clunky and not very elegant. However, the code works more or less fine for my applications. Feel free to send me any improvement suggestions.
-
Font mapping: Font name extraction depends on PDF metadata. PDFs converted via CUPS (
cupspdf) lose font metadata; text may be rendered with incorrect fonts. Use the original source PDF (e.g. directly from LaTeX) for best results. -
Diacritic repair: The built-in diacritic repair covers the most common LaTeX extraction artifacts, but edge cases may remain depending on the PDF producer and font encoding used.
-
Vector graphics: Xournal++ has limited support for complex vector graphics. Gradients, clipping paths, transparency, and advanced fill patterns cannot be represented faithfully as Xournal++ strokes. Such elements may appear incomplete, distorted, or missing in the converted file.
This program is free software licensed under the GNU General Public License v3.0 (or later).
See LICENSE for the full license text.
Third-party components and their licenses are listed in NOTICE.
| Package | License |
|---|---|
| PyMuPDF | GNU AGPL 3.0 |
| OpenCV | Apache 2.0 |
| NumPy | BSD 3-Clause |
| scikit-image | BSD 3-Clause |
| Inkscape | GNU GPL 2.0+ |