Subtitle Edit can convert image-based subtitle formats to text using OCR.

Open-source OCR engine with language packs.
Built-in trainable OCR engine.
.nocr database in the OCR folder, ready to pick from the database list<name>.nocr.bak in the OCR folder. Also available in seconv as seconv optimize-nocr <database.nocr><i>i</i>t. The tagged part is italic and the rest upright, whatever the surrounding word is, so an italic line comes out as <i>... i</i>t<i>?</i> instead of nested tags. This works the same in Binary OCRBinary image comparison engine, listed as Binary image compare in the engine dropdown.
Built-in OCR on macOS using Apple’s Vision framework.
Cloud-based OCR using Google Lens (free, but capped).
Cloud-based OCR using Google Cloud Vision API.
Local LLM-based OCR via an Ollama server (e.g. with a vision model).
http://localhost:11434/api/chatLocal LLM-based OCR using a llama.cpp-compatible server. Subtitle Edit can download llama.cpp and the model for you, or talk to a server you run yourself.
http://127.0.0.1:8080/v1/chat/completions*.gguf in the llama.cpp models folder together with its mmproj vision projector, named either mmproj-<file>.gguf or <file>-mmproj.gguf (the two naming schemes used on Hugging Face). A *.gguf without a projector next to it is not offered — it cannot see the imageLocal OCR engine with multiple model backends (free/open source).
q4_k model of about 2.31 GBq4_k and a higher-quality q8_0 model (from about 445 MB for GOT-OCR2 q4_k up to about 2.29 GB for Qwen3-VL-2B q8_0)Cloud-based OCR using Mistral API.
Local OCR engine, based on Paddle OCR 3.7 with the PP-OCRv6 recognition models.
paddleocr 3.7 or newer - older versions do not know the PP-OCRv6 model names.After OK, the matching video is opened as well (unless auto-opening the video is turned off in the settings): a container source (.mkv, .mp4, .ts) is opened as the video itself; for a stand-alone image subtitle (.sup, .sub/.idx, …) a video passed together with the file (drag and drop, command line) is used first, then the video the subtitle was last opened with, then a video file with the same name next to the subtitle.
When the OCR window opens, the OCR language for every engine - and through it the spell check dictionary - is pre-selected from the source’s declared language: the stream language in a VobSub .idx, the track language of a Matroska or MP4 subtitle track, or a language tag in the file name. Two file-name patterns are recognised: a bracketed ISO 639 code such as movie_track3_[dut].sup (the naming used by Subtitle Edit’s own Matroska track export; the last valid code wins), and a trailing dot-separated tag such as movie.nl.sub or movie.dut.forced.sub - the hi, sdh, cc and forced markers are skipped, only the last two remaining tokens are considered, three-letter codes must be lowercase, and hi is read as hearing impaired rather than Hindi. A detected language wins over the last-used one; a source without language information keeps the previous selection.
Checkboxes below the engine settings:
Toggle buttons above the image:
Right-click the subtitle list for:
Find… and Replace… (subtitle list or text box right-click menu, Ctrl+F / Ctrl+H) open the same Find and Replace windows as the main window, so text can be searched and fixed while the image is still next to it. A match selects its line and highlights the text in the text box. Replace all also updates the lines’ highlighted OCR text in the list.
The subtitle list’s right-click menu has Save all images with HTML index…. Pick a folder and
Subtitle Edit writes index.html plus images/0001.png, 0002.png, … — every subtitle bitmap
next to the text OCR produced for it, which is the quickest way to proof-read a run against the
originals.
The page is self-contained (no external css, js or fonts), so it opens straight off the file system. It follows the reader’s light/dark preference, with an Auto/Light/Dark override, and adds a text filter, an “only lines without text” filter for spotting images that produced nothing, a dark/light/checkerboard backdrop for the transparent bitmaps, click-to-zoom, and each line’s number, time codes, duration and image size.
| Shortcut | Action |
|---|---|
| Escape | Cancel OCR / Close window |
| Ctrl+G | Go to line number |
| Ctrl+F | Find |
| Ctrl+H | Replace (Cmd+Alt+F on macOS) |
| F3 / Shift+F3 | Find next / Find previous |
| Ctrl++ | Zoom in (images in grid) |
| Ctrl+- | Zoom out (images in grid) |
| F1 | Show help (default key, changeable) |
| Shortcut | Action |
|---|---|
| Ctrl+I | Toggle italic formatting |
| Ctrl+P | View selected image (use arrow keys to navigate) |
| Delete | Delete selected line(s) |
| Home | Jump to first line |
| End | Jump to last line |
| Double-click | Inspect line (nOCR/Binary OCR only) |
| Shortcut | Action |
|---|---|
| Enter | Jump to subtitle line containing the selected unknown word |
Note: All shortcuts can be customized. Go to Options → Shortcuts to view and change key bindings.
Before OCR, you can apply image pre-processing via the Image pre-processing toggle button in the OCR window (it shows as pressed while any pre-processing is active):
The settings are remembered between sessions and applied automatically the next time you open the OCR window. Reset in the Pre-processing window sets all options back to their defaults (all off, border size 2, darkness threshold 128).
Batch Convert can process image-based subtitle files with OCR. Subtitle Edit 5 includes Binary OCR in Batch Convert and can auto-detect several nOCR/Binary OCR settings such as language and pixels-are-space values.
For VobSub files, Batch Convert isolates the glyph color before OCR (on by default, configurable in the Batch Convert settings): the subpicture is rebuilt as a crisp black-on-white bitmap from pixel frequency, so outline and anti-alias colors no longer melt adjacent characters together.
For command-line workflows, see Command Line (seconv), which documents OCR engines and options for headless conversion.

When the OCR engine encounters uncertain characters, you can:
The unknown-words list in the OCR window has buttons for the selected word: Add to names list (case sensitive), Add to user dictionary, Add to OCR replace pairs and Google it.
Some of the choices in the unknown-word prompt are saved to disk and reused on later OCR runs; others only last as long as the OCR window is open.
| Choice | Remembered? | Stored in |
|---|---|---|
| Change all | Yes | {language}_OCRFixReplaceList.xml |
| Add to names list | Yes | {language}_names.xml |
| Add to user dictionary | Yes | {language}_user.xml |
| Skip once | No | — |
| Skip all | No — current OCR session only | — |
“Skip all” is deliberately temporary. It silences a word for the rest of the current OCR session and is forgotten when the OCR window closes, so a mis-click never has lasting consequences. If you want a word to be accepted permanently, use Add to user dictionary (or Add to names list for proper nouns) instead, and use Change all for a correction that should be applied automatically from now on.
Subtitle Edit uses language-specific XML files to automatically correct common OCR errors. These files are named {language}_OCRFixReplaceList.xml (e.g., eng_OCRFixReplaceList.xml for English) and are located in the Dictionaries folder.
See the example file: Dictionaries/eng_OCRFixReplaceList.xml
The OCR fix replacement list contains several sections that handle different types of corrections:
Replaces entire words that match exactly. This is the most common section for fixing OCR mistakes.
<WholeWords>
<Word from="tñere" to="there" />
<Word from="ri9ht" to="right" />
<Word from="0f" to="of" />
<Word from="alot" to="a lot" />
<Word from="becuase" to="because" />
</WholeWords>
Use cases:
0 → o, l → I)Replaces character sequences within words, always applied without spell checking.
<PartialWordsAlways>
<WordPart from="¤" to="o" />
<WordPart from="lVI" to="M" />
<WordPart from="IVl" to="M" />
</PartialWordsAlways>
Use cases:
Replaces entire lines that match exactly (including formatting tags).
<WholeLines>
<Line from="[chitte rs]" to="[chitters]" />
<Line from="Hil' it!" to="Hit it!" />
<Line from="<i>Hil' it!</i>" to="<i>Hit it!</i>" />
<Line from="ISIGHS]" to="[SIGHS]" />
</WholeLines>
Use cases:
Replaces text fragments within lines, always applied without spell checking.
<PartialLinesAlways>
<LinePart from="Apollo 1 3" to="Apollo 13" />
<LinePart from=",.," to="..." />
<LinePart from=" lt " to=" it " />
<LinePart from=" lf " to=" if " />
</PartialLinesAlways>
Use cases:
Replaces text fragments within lines (may be spell-checked).
<PartialLines>
<LinePart from=" /be " to=" I be " />
<LinePart from=" aren '1'" to=" aren't" />
<LinePart from=" aren'tyou" to=" aren't you" />
</PartialLines>
Uses regex patterns to fix errors, but only applies the replacement if the corrected word is in the dictionary.
<RegularExpressionsIfSpelledCorrectly>
<!-- Fix lowercase 'l' to uppercase 'I' if result is a valid word -->
<RegEx find="\bl([A-Z]+)\b" spellCheck="I$1" replaceWith="I$1" />
<RegEx find="\b([A-Z]+)l\b" spellCheck="$1I" replaceWith="$1I" />
<!-- Fix possessive forms: David's, there's -->
<RegEx find="\b([A-Z][a-z]+)['']s\b" spellCheck="$1" replaceWith="$1's" />
<RegEx find="\b([a-z]+)['']s\b" spellCheck="$1" replaceWith="$1's" />
<!-- Fix missing spaces: ofDavid → of David -->
<RegEx find="\bof([A-Z][a-z]+)\b" spellCheck="$1" replaceWith="of $1" />
<RegEx find="\bin([A-Z][a-z]+)\b" spellCheck="$1" replaceWith="in $1" />
<!-- Fix 'l' in brackets: [GRlNDlNG] → [GRINDING] -->
<RegEx find="\[([A-Z ]*)l([A-Z ]*)\]" spellCheck="[$1I$2]" replaceWith="[$1I$2]" />
</RegularExpressionsIfSpelledCorrectly>
Attributes:
find: The regex pattern to matchspellCheck: The text to check against the dictionary (use $1, $2 for capture groups)replaceWith: The replacement text if spell check passesreplaceAllFrom / replaceAllTo: Optional character replacement before spell checkingUse cases:
l to uppercase I (e.g., lTEM → ITEM)To add your own OCR fix rules:
Dictionaries/{language}_OCRFixReplaceList.xmlTips:
WholeWords for simple word replacementsRegularExpressionsIfSpelledCorrectly for pattern-based fixes where you want to verify the result is a real word