PDFMarkdownNotes

PDF highlights to Markdown: quotations, notes and sources

October 16, 2026 · Oyren AI Team (AI-written)

PDF highlights to Markdown: quotations, notes and sources

Recommendation: The export route depends on where a highlight is stored: inside the PDF file, in a reference manager such as Zotero, or in a workspace such as Oyren. Each route should end in the same Markdown note, with a source header, a checked quotation, a page reference and a separately labelled observation.

Mind map of three export routes from PDF highlights to a Markdown note: embedded in the PDF, stored in Zotero, or saved in an Oyren workspace

Where a highlight is stored

A highlight that looks the same on screen can live in three different places, and each one needs a different export:

Storage locationHow to tellExport route
Inside the PDF fileThe highlight still shows after the file is opened in a second readerA script that reads PDF annotations (PyMuPDF below)
Zotero libraryThe highlight shows only in Zotero's built-in readerZotero's note from annotations, then Markdown export
Oyren workspaceThe highlight is listed in the document's highlights panelA note assembled from the saved passages

Zotero stores annotations made in its own reader in its database, not in the PDF, according to the Zotero PDF reader documentation. A copy of that PDF sent to a colleague therefore carries none of those highlights. The reverse also happens: highlights drawn in another reader are written into the file as standard annotation objects, and Zotero shows them as read-only imported annotations.

Embedded highlights with PyMuPDF

A highlight stored inside the PDF is an annotation object of subtype Highlight. It marks a region of the page, not a string of text. The script has to read back the words under that region:

import pymupdf

doc = pymupdf.open("paper.pdf")
for page in doc:
    for annot in page.annots(types=[pymupdf.PDF_ANNOT_HIGHLIGHT]):
        quote = page.get_textbox(annot.rect).strip()
        comment = annot.info.get("content", "")
        print(f"> {quote}\n\nPDF page {page.number + 1}. {comment}\n")

Each call does one job:

  • page.annots(types=[pymupdf.PDF_ANNOT_HIGHLIGHT]): returns only highlight annotations on that page and skips underlines, ink and sticky notes.
  • annot.rect: the rectangle that encloses the whole highlight.
  • page.get_textbox(rect): returns the page text inside that rectangle.
  • annot.info["content"]: the comment typed into the highlight's popup, or an empty string.
  • page.number + 1: PyMuPDF counts pages from 0, so the script adds 1 to print the page number shown by a PDF reader.

The rectangle has one known limit. A highlight that covers the end of one line and the start of the next has a rectangle that spans both full lines, so get_textbox can return words that were never highlighted. The annot.vertices property holds one quadrilateral per highlighted line and gives a tighter result when that matters. Either way, the output is a draft that needs the quotation check below. The PyMuPDF annotation documentation lists the other annotation properties.

A page with no text layer, such as a scanned page, returns an empty string here. The text selection troubleshooting guide covers that case.

Zotero annotations to Markdown

In Zotero, annotations are turned into a note first and the note is then exported. The Zotero 6 announcement describes both steps:

  1. Add Note from Annotations (right-click the PDF item in the library) creates a child note with every highlight as a quotation, followed by a citation and a link back to the PDF page.
  2. Export Note (right-click the note) offers Markdown as an output format.

The exported links use the zotero:// scheme and open only on a computer with Zotero installed. The citation text next to each quotation still shows author, year and page when the link does not open, so the note stays readable on its own.

Oyren highlights as a manual note

Oyren lists a document's saved highlights in its highlights panel. Selecting a highlight returns to its position in the PDF. The panel has no bulk Markdown export, so the note is assembled by hand: the passages needed for the current question are copied into a workspace note beside the document, each with its page.

This route takes longer per passage than an automatic export. It fits a reading session where three or four passages matter, rather than a whole annotated paper. The PDF-to-note workflow guide shows how a document, a reviewed note and follow-up tasks connect in one workspace.

Note structure

All three routes should produce the same note shape. Each part has one job and one check:

Mind map of the five parts of a highlight note: source header, quoted passage, location, observation and open question

# Notes on the example paper

Source: Example Author, Example Paper Title, 2024, arXiv:0000.00000

> The method assumes that inputs are drawn from a single distribution.

Location: PDF page 8, printed page 6, Methods
Observation: the result is only shown for one input distribution.
Question: does the appendix test mixed distributions?

This template is illustrative and does not quote a real paper. The fields work as follows:

  • Source: written once at the top of the file. Individual quotations then only need a location.
  • Blockquote (>): holds the source's exact words and nothing else.
  • Location: gives both the PDF page (the number a reader's page box shows) and the printed page (the number in the paper's footer) when they differ. Citations use the printed page. Navigation uses the PDF page.
  • Observation: an interpretation in the note-taker's words, labelled so it is never read as a quotation.
  • Question: unfinished work. Keeping it on its own line stops it from turning into a claim in a later draft.

When a note grows, passages can be regrouped under headings that match the research question, such as definitions, evidence and limitations. Each passage keeps its location line when it moves.

Quotation checks before use

Exported highlight text is a draft of the quotation, not the quotation itself. Text extracted from a PDF often differs from the page in predictable ways:

DifferenceExample in extracted textCorrection
Line-end hyphenationdistri- butionRejoin as distribution if the hyphen was only a line break
Ligaturesfinite written with a single fi characterReplace with the separate letters fi so search finds the word
Line breaksA sentence split over several linesJoin into one paragraph
Notationx2 where the page shows x squaredRewrite from the page, for example x^2 or $x^2$
Neighbouring wordsExtra words from the line above or belowTrim to the highlighted span

Each correction should restore what the page shows. An unclear character stays marked as unclear in the note rather than being guessed from context. For scanned sources the extracted text comes from OCR, so a comparison with the page image is required before quoting. The scanned PDF guide covers reviewed OCR notes in Oyren, and the PDF OCR to Markdown Notes feature keeps the corrected text next to the original document.

Frequently asked questions

Why does a highlight disappear when the PDF is opened in another reader?

The highlight was stored by the first application, not in the PDF. Zotero's built-in reader and most web workspaces keep annotations in their own database. Exporting the file with annotations, or exporting the notes, carries them out.

Why does the extracted quotation include words that were not highlighted?

The script read text inside the highlight's bounding rectangle, which spans whole lines when a highlight wraps. Reading the per-line annot.vertices quadrilaterals, or trimming the quotation by hand, fixes it.

Does a Markdown note need a full citation for every quotation?

No. A source header at the top of the file identifies the document once. Each quotation then needs only its page and section, which is enough to find the passage again.