A PDF content stream is a sequence of drawing operators that tells a renderer what to paint on a page and where. Text is not stored as paragraphs — it is stored as instructions like "set this font, move to this coordinate, show these glyphs". Editing a PDF means rewriting those instructions.
Why this happens
A word processor stores a document as flowing content: paragraphs, then a layout engine that decides where the words land when it renders. A PDF stores the opposite — the layout decisions have already been made and baked in. What remains is a set of instructions: set this font at this size, move the cursor to these coordinates, show these glyphs, move again.
That is the whole reason a PDF looks identical on every machine, and the whole reason editing one is awkward. There is no paragraph to retype, because there is no paragraph. There is a `Tj` operator holding some bytes, positioned by a text matrix. Change the words and nothing re-flows, because there is no flow to re-run.
It also explains the single most common failure in online PDF editors. Faced with a content stream, the easy move is to leave it alone and draw over it — a white rectangle, then a fresh text box on top. On screen it looks edited. In the file, the original operator is untouched and the old text is still there, selectable and searchable.
How Online PDF Edits handles it
We parse the page’s content stream into its operators, find the text-showing operator that draws the run you clicked, delete it, and write a replacement in its place. The rest of the stream is left exactly as it was, so every other element on the page is drawn by the same instructions as before your edit.
You can check this yourself without trusting us: export the file, select the line you changed, and copy it. If you get your new wording, the operator was replaced. If you get the old wording back, whatever tool you used painted over it.
The specifics
| Text-showing operators we handle | Tj, TJ, ’ and ” |
|---|---|
| What happens to the original operator | Deleted from the stream, not covered |
| What happens to the rest of the page | Left byte-identical |
| Multiple content streams per page | Not yet supported — reported, not guessed |
Limitations
- A page whose /Contents is an array of several streams is not supported yet; you get a clear error rather than a mangled file.
- We replace one run of text per edit. A content stream is not a document model, so there is no notion of “insert a paragraph and push the rest down”.
Don’t take our word for any of this. Edit the sample invoice, export it, then select the line you changed and copy it — you should get your new wording, not the old. Compare the export against the original and see what moved.
Every claim in this reference is written from the code that implements it, and every number is measured rather than estimated. The parts you can verify without trusting us are the ones we put in front of you.