AnnotatePDF by bishwaa
pendingby bishwaa
Native PDF highlighting with Foxit-level precision. Highlights are written directly into the PDF binary.
AnnotatePDF by bishwaa
AnnotatePDF by bishwaa is a premium Obsidian plugin that transforms Obsidian into a true academic PDF reader. It delivers Highlight Precision while writing true native PDF annotations directly into the .pdf binary file β making your highlights permanently portable across Adobe Acrobat, Foxit Reader, and any other standards-compliant PDF viewer.
π Key Features
1. Zero-Flicker Delayed Cache Engine
Traditional PDF annotation plugins that write directly to the file on every highlight cause Obsidian to violently reload and flicker the PDF viewer with each change. AnnotatePDF eliminates this completely.
When you highlight text, the plugin bypasses disk I/O entirely and injects a temporary CSS overlay directly onto your screen in 0 milliseconds. The true native annotations are batched into a high-speed memory queue. Only when you switch tabs, close the file, or close Obsidian will the plugin lock the PDF binary, write all queued highlights in a single pass, and save the file natively in the background β no flicker, no interruption.
2. Pixel-Perfect Highlight Alignment
AnnotatePDF uses a canvas-anchored coordinate engine to position highlights with surgical accuracy at any zoom level.
Standard approaches measure selection rects against the outer .page wrapper div, which includes CSS padding and Obsidian's drop-shadow β causing highlights to appear shifted or misaligned from the actual text. AnnotatePDF instead measures against the canvas element directly, which is the true rendering surface that PDF.js positions its text layer over. The result is highlights that sit perfectly on top of your selected text at every zoom level.
3. Character-Accurate Partial Line Selection
Selecting a few words from the middle or end of a line highlights exactly those words β nothing more.
PDF.js renders text as large span elements, sometimes covering an entire line in a single chunk. Standard web APIs (range.getClientRects()) return the bounding rect of the whole span when touched, causing partial selections to highlight the full line. AnnotatePDF uses a per-text-node sub-range engine β it walks every individual text node in the selection and builds a fresh sub-range for the exact selected characters within each node. This is the same character-level method browsers use internally to draw their own blue selection highlight.
4. Multi-Color Hotkey Support
Stop clicking through menus to change highlight colors. AnnotatePDF supports rapid hotkey-driven highlighting straight out of the box. Simply select text and press one of the global hotkeys:
| Key | Color | Default |
|---|---|---|
H | Primary | Yellow #ffff00 |
G | Secondary | Green #00ff00 |
J | Tertiary | Cyan #00ffff |
Configure your exact hex colors in the plugin settings.
5. Instant Native Deletion
Made a mistake? Select any text that overlaps a highlight and press Delete or Backspace.
- Unsaved highlights β instantly removed from the CSS layer with zero disk writes
- Saved highlights β the plugin reads the annotation directly from the PDF binary, locates it by position, and permanently removes it from the
/Annottree in a single atomic write
Deletion uses a dual-path matching system for maximum reliability:
- Exact NM match β fast O(1) lookup using the annotation's unique ID embedded in the PDF at write time
- Spatial fallback β overlap-based coordinate matching with Β±2pt floating-point tolerance, using the highlight's own stored rect (not the cursor rect), for annotations created or re-saved by external readers that strip custom fields
6. PDF as the Single Source of Truth
AnnotatePDF follows the same architecture as Foxit Reader: the PDF binary itself is the authoritative record of all annotations. There are no fragile sidecar JSON files or external databases that can fall out of sync.
When deleting a saved highlight, the plugin reads annotation metadata directly from the PDF binary via readAnnotationsFromPdf(). This means deletion works correctly even after:
- Obsidian restarts
- The file being opened and re-saved in Foxit or Acrobat
- The internal tracking cache being cleared or corrupted
7. Password-Protected PDF Handling
AnnotatePDF detects encrypted PDFs immediately and handles them gracefully:
- Instant feedback β attempting to highlight a password-protected PDF shows a
πnotice immediately at the keypress, before any work is queued - No error spam β detected encrypted files are added to a session blocklist. The flush loop skips them permanently, so you never see a flood of repeated error toasts after closing the file or restarting Obsidian
- Queue safety β the pending queue for an encrypted file is cleared on detection. Unlike file-lock failures (which keep the queue for retry), retrying an encrypted PDF is pointless, so all queued highlights are discarded cleanly
To annotate a previously blocked file after removing its password, use Reset Cache in plugin settings.
8. Background Locking Resilience
If your PDF is open in Adobe Acrobat or Foxit Reader simultaneously, those applications place an OS-level lock on the file preventing external writes. AnnotatePDF is immune to data loss in this scenario.
If the plugin detects a file lock during flush, it shows a specific β notice and refuses to clear the queue. Your highlights remain safely cached in Obsidian's persistent memory. Once you close the other application and switch tabs, the plugin resumes saving automatically.
Error types are handled distinctly:
| Scenario | Message | Queue |
|---|---|---|
| PDF open in another app | β File is locked by another app | Kept β retried on next flush |
| PDF is password-protected | π File is password-protected | Cleared β never retried |
| Unknown error | β οΈ Failed to save β check console | Kept |
9. Seamless Multi-Line Highlight Merging
When highlighting across multiple lines of wrapping text, the browser returns dozens of overlapping fragmented rectangles β one per text node fragment, per line. Overlapping rects cause uneven opacity densities that look unprofessional.
AnnotatePDF uses a line-merging engine that sorts all raw rects by baseline, groups them into lines by vertical proximity, and welds each line into a single clean bounding rectangle. The result is uniformly opaque highlight blocks across even the most complex multi-paragraph selections.
10. Crash-Safe Queue Persistence
All pending (unflushed) highlights and deletions are continuously serialized into Obsidian's data.json via syncPendingQueueToDisk(). If Obsidian is force-killed, crashes, or is closed via the OS X button before a flush can complete, your unsaved annotations are fully recovered on the next startup automatically.
βοΈ Installation
- Copy
main.js,manifest.json, andstyles.cssinto your vault at:.obsidian/plugins/annotate-pdf-bishwaa/ - Enable the plugin under Settings β Community Plugins.
- Configure your preferred author name, highlight colors, and opacity.
π Usage Workflow
- Open any
.pdffile in your Obsidian vault - Select text using your mouse cursor
- Press
H,G, orJto instantly deploy the highlight - Continue reading β your highlights are cached and safe
- Switch tabs or close the file β the plugin silently writes all annotations natively into the PDF binary in a single pass
To remove a highlight: select any text overlapping it and press Delete or Backspace.
βοΈ Settings
| Setting | Description |
|---|---|
| Author Name | Embedded in every annotation. Visible on hover in Foxit/Acrobat. |
| Primary Color | Hotkey H. Default: Yellow |
| Secondary Color | Hotkey G. Default: Green |
| Tertiary Color | Hotkey J. Default: Cyan |
| Highlight Opacity | Global alpha multiplier (0β100). Applied to all colors. |
| Reset Cache | Clears all pending queues, the JSON audit log, and the encrypted-file blocklist. Use this if you remove a password from a PDF and want to annotate it. |
ποΈ Architecture Overview
Keypress (H / G / J)
βββ SelectionExtractor canvas-anchored, per-text-node sub-ranges
βββ drawTemporaryCssOverlay 0ms visual feedback
βββ pendingHighlights queue persisted to data.json
Tab switch / file close
βββ flushCache() [concurrency-safe, _isFlushing guard]
βββ PdfAnnotator.applyBatchUpdatesToPdf()
βββ EncryptedPdfError β clear queue, add to blocklist
βββ LockedPdfError β keep queue, notify user
βββ success β clear queue, write JSON audit log
Delete / Backspace
βββ executeRemoveHighlight()
βββ pending queue? β remove CSS overlay, clear from queue
βββ saved in PDF? β PdfAnnotator.readAnnotationsFromPdf()
βββ exact NM match + spatial fallback
βββ applyBatchUpdatesToPdf()
π Compatibility
- Highlights are written as standard ISO 32000
/Highlightannotations - Fully visible and editable in Foxit Reader, Adobe Acrobat, PDF Expert, and all other standards-compliant readers
- Works on any PDF that is not password-protected
- Tested on Obsidian desktop (Windows, macOS, Linux)
Transform Obsidian into a true academic PDF reader β by bishwaa
Built with β€οΈ by Bishwaa Adhikarii, Nepalπ³π΅
If this plugin made your reading life better, I'd love to hear from you.
| π | Website β bishwaa.com.np |
| πΌ | LinkedIn β linkedin.com/in/iambishwaa |
| π | GitHub β github.com/iambishwaa |
| π¬ | Say thanks β pi@bishwaa.com.np |
If AnnotatePDF saved you time, a kind email or a β on GitHub goes a long way. Thank you for using it!
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.