You can switch between workflows at any time — your map, variants and edits stay exactly as they are.
A variant is one content file of the same shared map. Copied text comes back marked review — a copy is never a claim that it is already translated.
existing region · detected proposal
On-device translation: checking…
Translation uses Chrome's built-in on-device model (chrome-ai — private, no key, but Chrome-only), a public LibreTranslate instance (default lt.dialectapp.org) or a custom URL; the public instances are community servers, so expect rate limits or the occasional outage. The manual copy-and-paste workflow always works.
Both language fields also pre-select the region toolbar. Auto source lets the provider detect the language (Chrome's on-device model needs a named one). Choosing a LibreTranslate server fills the URL field with that server's address — edit it freely to point anywhere; pick LibreTranslate (custom URL…) for a server that is not listed.
OCR runs entirely in this browser (Tesseract.js, Apache-2.0); the engine and language data download from jsDelivr on the first scanned extraction and are then cached. The OCR language follows the PDF/source language; Auto falls back to English. Table recognition remains out of MVP.
OCR is used by Improve ▸ Make this selectable, the region context menu’s Read with OCR, translation from page text, and Detect-and-extract. Detection alone never starts the OCR engine; scanned regions stay badged not selectable yet until a harvest runs.
Text box padding grows a detected region by that many points per side, so the polygon (and its mask) gains a margin and a text box — the region interior inset by the same amount — keeps the room the detector gave the text (0 = flush). It is applied when regions are detected, never when a text box is added; a region you drew yourself keeps exactly the shape you drew and its box is simply inset by the padding. Re-detection overlap threshold is the IoU at which a re-run treats a proposal as the same block: above it the conflict is reviewed (Replace / Don't add); containment always counts; match-and-identical proposals are left alone, so re-detecting an unchanged page changes nothing. Scanned-page detection picks the detector per page: Auto uses the text layer when the page has one and the CV detector when it does not; force either to override, per run. CV engine picks how the CV detector segments the bitmap: classical is dependency-free and instant; OpenCV.js is experimental and downloads ≈10 MB on first use (browser-cached, never at startup) to use OpenCV's adaptive threshold and morphology; it then falls back to classical with a status note if it cannot load. Both engines share the same structural text/image classifier, type-aware grouping and proposal contract; OpenCV currently matches, rather than beats, classical on the reference cover.
Fix/Translate PDFs, your way. Version 1.0.0 · spec revision 1.6
| Ctrl/Cmd+O | Open PDF (select the PDF + its .pmap map and .content.json variant together to load the whole project) |
| Ctrl/Cmd+S | Save the project: the shared .pmap map + the active .content.json variant. File ▸ Save map / Save content write just one of the two — the info panel says which half has unsaved changes |
| Ctrl/Cmd+F | Find & replace in the content the current workflow is editing: the active Translate content variant, or the Improve Selectable text variant. It searches every page of the loaded content, respects paragraph, list-item and table-cell boundaries, keeps character formatting, and supports a Regular expression mode and Match case. Replace all is one undo step; a zero-width regex match is ignored |
| Project on disk | A project is two files: a structure-only map.pmap (pages, region ids, polygons, locks) and one map.<language>.content.json per language/variant (backgrounds + content items, keyed by region id). The same map can back many variants; only one variant is active at a time. File ▸ New content variant… adds one (empty, or a copy flagged for review); File ▸ Open map or content… switches to one from disk. A v1.1 single-file map must be split first with tools/pmap-migrate.mjs |
| Browser refresh | The open PDF, its map and the active content variant are remembered in this browser (IndexedDB) and restored on reload — nothing is uploaded. File ▸ Forget saved session removes them and this PDF’s saved language/workflow choice |
| File ▸ Close PDF | Unloads the current PDF, map and content variant, clears this PDF’s saved browser session and per-document language/workflow choice, and returns to the empty editor. Other preferences are kept |
| Workflows | Translate and Improve are intents, not data states: one PDF, one map, one set of variants. The import question asks once; the header switcher changes the menus, labels and default variant without writing anything. Translate works in the target-language variant and returns there; Improve foregrounds the PDF-language variant, labelled Selectable text. The text you type in Improve is the same source text Translate reads. |
| Improve ▸ Export digitalized PDF… | Writes a copy named <stem>.digitalized.pdf with an invisible, selectable text layer over every region that holds text in the PDF-language variant. The source PDF is untouched and the page looks unchanged. Regions with no extracted text (including not selectable yet and figures) stay uncovered; the status bar reports how many. If the PDF-language variant is not loaded, the command first runs the normal extraction flow. |
| Status tags (Shift+D) | Toggles the on-page status tags (Shift+D). Text regions show their detector class (heading / text; a hand-drawn region reads text), plus has source text / selectable when the PDF-language variant already has content, or source text not readable / not selectable yet when it has none and OCR could not fill it. Detected figures stay untagged and keep their dashed outline. Ids stay visible when the tags are hidden; the tags are an inspection aid and never change the map or content. |
| Select regions not yet selectable | Improve ▸ Select regions not yet selectable (Shift+A in either lens) selects every text-convertible region on the current page that has no content in the PDF-language variant. Detected figures and filled regions are left out; regions whose source text is unreadable are included. |
| Improve ▸ Make this selectable… | Reads the PDF into the Selectable text variant: the text layer, or OCR for scanned and mixed-page regions with no usable selectable text when Preferences… ▸ OCR Service is on. Choose selected region(s), this page, or all pages. Regions that already hold content are skipped; detected figures are not OCR candidates. One undo step per run, and the source PDF is never modified. |
| Read with OCR (right-click) | On a region badged source text not readable / not selectable yet, right-click it in Region mode and choose Read with OCR: Tesseract reads only the right-clicked region, never the whole page or the rest of a multi-selection, and writes the result into the PDF-language variant as review-flagged text. OCR runs on-device and leaves the region waiting if it cannot read it. |
| Ctrl/Cmd+Z / Shift+Z (or Y) | Undo / Redo |
| Ctrl/Cmd+A | Region mode: select every region on the current page. Content mode: select every text and image item on the current page (use Delete/Backspace to remove them together). |
| Tab / Shift+Tab | Cycle mode forward / backward: Region → Content → Preview → Original → Region (also shown in the toolbar; Shift+Tab steps the ring back). Region mode is the geometry editor (draw / move / reshape / merge / split / lock / delete polygons); Content mode is the item editor (place and edit text and image items); Preview is the read-only reconstruction; Original selects the PDF's own text |
| T | Content mode: add a text item to the selected region — its dialog opens for typing, and the new box is fitted to the text when you finish (nothing cropped, no dead space). Enter starts a new line; Done (or Esc) keeps the text, Cancel discards it. The box is the region interior inset by the Text box padding set in Preferences… (default 4 pt), and adding a text box never changes the region's shape — the padding was applied when the region was detected (the detected polygon grows by it, so the mask gains the margin and the box keeps the room the detector gave the text). In Region mode T is inert: items are frozen there |
| Ctrl/Cmd+V | Content mode: paste a clipboard image as an image item in the selected region |
| Contextual toolbar | Shows only what matches the mode and the selection. Region mode: region actions (background, lock polygon; in Translate also the Source and Destination languages and Translate from page text; in Improve also the Source language and Make this selectable). Content mode: with a region selected — Add text, Add image, the same region actions; with an item selected — Resize to text, Bring to front / Send to back, Delete item (plus image fit / crop for an image). Text formatting lives inside the text box dialog, next to the text it formats |
| Text box dialog | Double-click a text box (or press T to add one) to open it. Its header holds the text tools: Bold / Italic / Underline / color / font / size / line / align / direction, plus H (heading) / • / 1. (lists) / ▦ (table). Formatting applies to the selected text only; with no selection it becomes the style of the next characters you type. Alignment applies to the current paragraph or cell. Line sets the line spacing of the whole box (a multiple of the font size, default 1.25): it is saved with the item, the box grows so no line is cropped, and table rows keep their own height. Inside a table cell, Tab/Shift+Tab move between cells, the column/row handles can be dragged to resize, and the table tool group appears (border color/width, add/remove row/column, column width, row height). The dialog is resizable (drag its bottom-right corner) and its text area is a free-form editor: it is as big as the dialog, not as big as the box, and it is for writing, editing and formatting only. Size the box on the page, where the box is — drag its corner handles in Edit mode (a new box is fitted to its text automatically), or use Resize to text / R to fit a box to the text it holds |
| Paste in a text box | Paste formatted text, RTL text or tables from Word / LibreOffice / Excel directly: HTML tables become table blocks, spreadsheet cells (tabs) become a table, and images become image items |
| Background | Set the region's fill color in the region toolbar. A region is masked (its color painted over the page) when it holds content or you gave it a non-default color — an all-default empty region stays transparent. The mask is previewed in both editing modes for every deselected region (items included) and exactly as Preview mode / the export render it; the region you are editing stays transparent, except that while the color picker has focus its own mask is shown so you can see the color you are choosing |
| 0 | Toggle overlay |
| Delete | Region mode: delete the picked vertex; else the selected region(s). Content mode: delete the selected item; inert on a region-only selection (deleting a polygon needs Region mode) |
| P | Add polygon (Region mode): toggle the drawing tool — click to add points, Enter/double-click to close, Esc cancels. While armed the cursor is a crosshair and a hint is shown. Inert in Content mode |
| L | Lock / unlock the selected region's polygon (both editing modes): a locked region can't be moved, reshaped, split, merged or deleted, but its text and image items stay fully editable. Locked regions are drawn dashed with a padlock, and their vertices stop showing handles. One undo step |
| I | Open the region background colour picker (both editing modes, whenever the background control is on screen — i.e. a region is selected): the same as clicking the Background swatch. The native picker's eyedropper samples a colour from anywhere on the page, so a region can be matched to the original. While the picker is open the selected region previews its mask, so the colour is visible live. Inert when no region is selected |
| Shift+D | Show or hide the source-text / selectability status tags on the page (the same as Improve ▸ Show selectability status) |
| Shift+A | Select every text-convertible region on the current page that has no source text / is not yet selectable (the same as Improve ▸ Select regions not yet selectable). Detected figures and filled regions are excluded; unreadable regions are included |
| D | Detect regions on this page (any mode; the same as Tools ▸ Detect regions on this page). A page with a text layer gets text regions from that layer plus figure proposals: raster image placements and painted vector drawings, unpadded and counted separately in the status bar. A scanned page is read with the built-in classical-CV detector (grayscale → adaptive threshold → morphology → connected components) and gets block proposals to trace. Preferences… ▸ Region Detection can force either detector for a run. A fresh figure is badged detected: image and drawn with a dashed outline until you edit it. Proposals only — nothing is confirmed automatically |
| R | Resize to text in page (Content mode): runs Resize to text on every text box of the page at once — one undo step, and no box keeps dead space. The fit first uses the line spacing (a tighter multiple of the font size, down to the minimum, when that is what brings the text inside the region), and only then grows a box past the polygon rather than crop the text: the region is then painted orange, because the polygon is what clips the overhang |
| Click empty space | Clear the whole selection — the selected region(s) and the selected content item — in either editing mode, so the panel returns to "Nothing selected". Hold Shift to keep the selection. (Use P/Tools ▸ Add polygon in Region mode to start a new polygon.) |
| Drag empty space | Rubber-band select. Region mode: the band picks regions, highlighting them live as it sweeps (hold Shift to add to the current selection). Content mode: with a region selected the band picks an item of that region (the topmost box under it); with nothing selected it picks regions, so a region can still be chosen to work in |
| Click a region | Region mode: grab & move it (when not mid-drawing); Shift-click toggles it in/out of a multi-region selection. Content mode: select it — the polygon is a read-only outline there, and it is how you choose the region that receives new items (hold Alt while dragging to move it) |
| Cursor tells you what a press grabs | Hovering the overlay shows, before you press, what the press will do: move (4-way arrow) = the region's face; a resize cursor (↕ / ↔ / ⤡) = the polygon line under the pointer, its axis perpendicular to that line (a horizontal line reads ↕); grab (hand) = a region vertex (the round blue dots); the square dark-grey corner handles belong to the text box / image and carry their own resize cursor. A locked region only selects, so it never shows the move cursor. In Content mode the polygon is a read-only outline: it shows the plain pointer, and only Alt brings the region's own cursor back |
| Orange region | A region whose text or image sticks out of its polygon is filled orange in Edit mode: the content is only drawn where the polygon is, so whatever overhangs is clipped. Resize to text / R never crop the text itself — it fits it with the line spacing, and grows the box past the polygon when even that is not enough — so orange means "enlarge or reshape this polygon, or shorten the text". The orange is an editing aid: it is not drawn in Preview mode and never reaches the export. |
| Alt/Option over a text box or image | The press goes to the region underneath instead of the item (the cursor switches to the region's own cursor while Alt is held) — useful when a box or image covers the region. In Region mode Alt keeps its other meanings inside a region: near a line it grabs that line, and on a vertex handle it grabs that vertex (the handle keeps its precedence). In Content mode Alt additionally makes the region movable by drag (one undo step, like a Region-mode move) but never unlocks vertex editing, merge/split or lock. Alt is never a delete, so reaching for the region can't destroy a vertex by accident |
| Click a text box | Content mode: select it — drag to move it, drag a corner handle to resize it (the whole content scales as a unit). A click never starts editing. Its corner handles are squares in dark grey, so they can't be confused with the round blue region vertices. In Region mode items are frozen: they are drawn as Preview mode draws them, but nothing is clickable |
| Double-click a text box | Content mode: open the text box dialog to edit its text (see Text box dialog above) |
| Drag vertex | Region mode: move a corner; handles appear only on selected regions and the picked vertex is highlighted — press Delete to remove it |
| Drag edge | Region mode: move a whole edge; adjacent edges stretch like threads |
| Double-click vertex | Region mode: snap that corner to a right angle (90°) |
| Ctrl+click vertex | Region mode: delete that vertex (Alt/Option is not a delete: it means "the region, not the item", so Alt+click on a vertex grabs and moves it instead). On macOS, where Ctrl+click is a secondary click, the same thing works as Ctrl+right-click on the vertex |
| Double-click edge | Region mode: insert a vertex at the click point |
| Drag inside region | Region mode: move the whole region (in Content mode, hold Alt to do the same) |
| Enter / double-click | Region mode: close polygon or finish split line |
| Esc | Cancel current draft (or close the text dialog) |
| Right-click region | Region mode: the full menu — Add text / Add image (which place the item and drop you into Content mode with it selected), copy underlying content as image / as text, translation commands in Translate, Read with OCR (only when the right-clicked region is source-unreadable / not yet selectable), lock the polygon, merge, split, or delete the region. Content mode: only Add text / Add image |
| Right-click vertex | Make that corner a right angle (90°) or delete the vertex |
| Shift+T | Translate from page text in Translate, or Make this selectable in Improve. Translate reads the PDF text layer under a region (or the whole multi-selection), translates it with the provider from Preferences…, and stores the result as a target text item flagged review; Improve reads the same source text into Selectable text as a review-flagged item. In Improve the language of the source text is the Source dropdown in the region toolbar — pick it there; no language prompt appears. A scanned or broken-encoding region is read with OCR when Preferences… ▸ OCR Service is on; if OCR cannot read it, the status says so and Copy underlying content as image is still available. The key is live only while the button is: it lives in the contextual region toolbar (Section 9b), so it does nothing unless a region is selected in an editing mode (Region or Content) with no item and no dialog open. T alone still adds an empty text box (Content mode) |
| Translate (source → target) | The region toolbar picks the source (Auto-detect lets a server provider detect it) and target languages. chrome-ai runs Chrome's built-in on-device model: free, private, no key — Chrome 138+ desktop, and the first use of each language pair downloads a model once (progress is shown in the status bar). It needs a named source language for Latin-script text, and supports neither Persian nor Urdu. In other browsers it reports itself unavailable and the other providers keep working. |
| Right-click content box | Content mode: Resize to text (make the box exactly big enough for its text — the fit tightens the line spacing when that brings the text inside the region, and grows the box past the polygon rather than crop the text, painting the region orange, since the polygon is what clips the overhang), Bring to front / Send to back (stacking order only, for a box with more than one item), or delete the content item |
| Shift+click | Region mode: multi-select regions (then Merge from the region context menu). Merge takes the union of all selected regions, overlapping or not — separate parts become one multi-part region — and every item keeps its own position |
Modes and page navigation live in the menu bar (the current mode is shown in the toolbar; only zoom stays on the toolbar; pages can also be picked from thumbnails).
In Region mode press P (or Tools ▸ Add polygon) then click points to draw a polygon, or click a region to grab & move it; clicking empty space deselects. Vertices and edges are always interactive there. In Content mode the polygons are read-only outlines: click one to choose where items go, then T adds text, Ctrl/Cmd+V pastes an image, and a box can be dragged, resized or double-clicked to edit — hold Alt to move the region instead. Original mode hides the overlay so you can select text from the PDF.
Workflow: choose Translate or Improve → map regions per page (Region mode) → fill in content (Content mode) → save the project (document.pmap + document.en.content.json).
A deselected region that already holds content is rendered just as Preview mode and the export render it — its background mask plus its content items; the region you are editing stays transparent so you always see the page you are working on.
Source PDF is never modified. Translation uses a public LibreTranslate instance (default lt.dialectapp.org, change it — URL included — in Preferences…); pick None (manual / external) there to copy the underlying content as an image, translate externally, and paste it back.
Fix/Translate PDFs, your way.
Version 1.0.0 · spec revision 1.6
PDFBandit fixes and translates PDFs your way: map a page once, then write or translate text into language variants and export a reconstructed or selectable PDF. The source PDF is never modified.
Projects use a shared .pmap map plus per-language .content.json variants. Your PDF, map and variants stay in this browser (IndexedDB); translation text goes only to the provider you choose, and OCR runs on-device.
Enter starts a new line, Tab moves between table cells. Done (or Esc) keeps the text, Cancel discards it. This dialog only writes, edits and formats — size the box on the page (its handles, or Resize to text / R).