Skip to content

feat(bindings): apply pdf annotations from every binding - #850

Merged
andiwand merged 3 commits into
mainfrom
feat/pdf-annotate-bindings
Sep 6, 2026
Merged

feat(bindings): apply pdf annotations from every binding#850
andiwand merged 3 commits into
mainfrom
feat/pdf-annotate-bindings

Conversation

@andiwand

@andiwand andiwand commented Sep 6, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Phase 6, the last of docs/design/pdf-annotation.md. Stacked on #849.

binding surface
python PdfFile.annotate(annotations) -> bytes
java PdfFile.annotate(String) -> byte[]
swift / ObjC PdfFile.annotate(_:) throws -> Data
wasm handle.annotate(annotations) -> Uint8Array

Plus the annotate capability on FileTypeCapabilities in all four.

Each returns the annotated bytes rather than writing a file — none of these callers has a filesystem the caller would want written to, and the wasm one least of all. That matches how save() already works in wasm and python.

Fixtures

Each binding needed a pdf to test against, and each builds one the way its neighbours build theirs — inline, with the cross-reference offsets computed rather than hardcoded, so no test data is fetched. Four small generators: python conftest.py, java TestFiles, swift Fixture, wasm helper.mjs.

Each suite then checks the same three things: the source comes back as a prefix of the result (the incremental update is visible from the outside), the annotation is in what follows, and a payload this build does not understand is refused with that binding's error type.

All four built and run

  • python — 75 tests pass (4 new)
  • JNI — 56 tests pass, up from 53. The new test class had to be listed in jni/CMakeLists.txt; without that it compiles into nothing and the suite silently stays at 53, which is what happened on the first run here.
  • wasm — 42 node tests pass (3 new), built through the emscripten toolchain
  • Apple — both macOS slices built, xcframework assembled, 34 XCTest cases pass (3 new)

Changelog entry extended to name the bindings and odr.annotation.


That completes the plan in docs/design/pdf-annotation.md, whose status is now landed.

@andiwand
andiwand force-pushed the feat/pdf-annotation-browser branch from 91216ac to 98f28b0 Compare September 6, 2026 16:03
Base automatically changed from feat/pdf-annotation-browser to main September 6, 2026 16:09
@andiwand
andiwand force-pushed the feat/pdf-annotate-bindings branch from 826bb02 to 86c6686 Compare September 6, 2026 16:09
andiwand and others added 2 commits September 6, 2026 18:10
`PdfFile.annotate` in python, java and swift, `annotate()` on the wasm handle,
and the `annotate` capability alongside them. Each returns the annotated bytes
rather than writing a file: none of these callers has a filesystem the caller
would want written to, and the wasm one least of all.

Each binding gets a minimal pdf fixture built the way its neighbours are —
computed cross-reference offsets, no file fetched — and tests that the source
comes back as a prefix of the result, that the annotation is in what follows,
and that a payload this build does not understand is refused.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018e3PEzyU2oAFSzsEoWsSmz
Every other binding call in `python/src` that does real work drops the GIL for
it and takes it back to build the `py::bytes`; `annotate` held it for the whole
parse and write, so a threaded caller stalled on it.

Apple: hands the annotated bytes straight to `NSData` through a new
`to_nsdata(const std::string &)` rather than wrapping them in an
`istringstream` for the stream overload to drain into another
`ostringstream` — three copies of the whole file for nothing. The stream
overload now ends in the same place.

Java: one `assertArrayEquals` for the copied prefix instead of an assertion
per byte, and the xref entry's terminator written as the byte the format
states rather than `%n` and a platform-separator replace.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147n68S7LNAv9KynLaGgXN4
Eight lines had grown around three separate things. The api and its bindings
are one entry, `odr.annotation` in the rendered view another, each the length
of its neighbours.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147n68S7LNAv9KynLaGgXN4
@andiwand
andiwand merged commit 7f53179 into main Sep 6, 2026
25 checks passed
@andiwand
andiwand deleted the feat/pdf-annotate-bindings branch September 6, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant