Windows desktop OCR tool: screenshot, annotate, recognize text (PP-OCR / RapidOCR packs), long screenshot, screen recording, PDF workbench, ASR/TTS, optional translation, and optional local HTTP API.
Current version: 1.0.2
| Area | Description |
|---|---|
| Screenshot recognition | Region capture → text OCR or barcode/QR recognition according to the current result tab; keeps the selected tab; multi-monitor DXGI capture |
| Screenshot annotate | WeChat-style tools: rect / ellipse / arrow / pen / text, color dots, undo / save / confirm |
| Long screenshot | Pick a window → auto-scroll stitch → open in viewer (no OCR) |
| Screen recording | Window or region → HUD (move/resize region, draggable bar) → MP4 (x264/x265/AV1 via FFmpeg only) + optional system/mic audio |
| GIF recording | Same region flow → capture 24 fps → preview (output FPS, scale, palette) → silent GIF |
| Clipboard | Paste image and run OCR; copy image / text; menu/tray can switch on-capture copy mode (image / file / path) and re-copy the last screenshot |
| Overlay text | Text layer on the image; drag-select and copy |
| PDF workbench | Open PDF → page OCR → edit lines → export searchable PDF (invisible text layer) |
| ASR / TTS | Offline speech recognition (sherpa-onnx) and TTS (Sherpa + SAPI / WinRT system voices); install voices in-app |
| SAPI x86 helper | Sidecar x86host.exe (32-bit SAPI web only) for classic voices visible only in x86 processes |
| Devices | CPU · NVIDIA CUDA (GPU) · Intel / DirectML (iGPU); missing accel → CPU |
| Install features | In-app download of models and runtimes (CN mirrors when locale is Chinese) |
| Hotkeys | Toggle main window · snap annotate · snap OCR · voice input (configurable) |
| HTTP API | Local JSON API (default 127.0.0.1:1224) |
| CLI | Batch OCR, list models / SAPI voices, probe CUDA, multi-monitor snap test |
- Windows 10/11 (x64)
- .NET Framework 4.8 (runtime on end-user PCs)
- Build: Visual Studio / MSBuild with .NET Framework 4.8 targeting pack (or SDK that can build
net48WPF) - Optional: NVIDIA GPU + CUDA stack matching the ORT GPU package (
onnxgpu64) - Optional: DirectML-capable GPU for the “核显” device option (
onnxdml64) - Optional (screen record): FFmpeg 4.4 shared libraries under
ffmpeg64/next to the exe
OCR/
├── WpfOCR/ # Application source (WPF, net48, x64)
│ ├── Assets/
│ └── bin/Release/
│ ├── net48/ # Dev output (models / runtimes live here)
│ └── WpfOCR/ # Slim package: WpfOCR.exe + x86host.exe + managed deps
├── x86host/ # Standalone 32-bit SAPI web helper (x86host.exe only)
├── docs/ # README screenshots
├── scripts/publish-release.mjs
├── README.md
├── README.zh.md
├── CHANGELOG.md
└── AGENTS.md
Model packs and large native runtimes are not stored in source. Place or install them next to the executable:
WpfOCR/bin/Release/net48/
├── WpfOCR.exe
├── config.toml # created/updated at runtime
├── ocrmodels/ # OCR packs (rapid-ch, rapid-i18n, …)
├── asrmodels/ # ASR packs (optional)
├── ttsmodels/ # TTS voices (optional)
├── translatemodels/ # Translation ONNX (optional)
├── onnxcpu64/ # ONNX Runtime for CPU EP (on-demand install)
├── onnxgpu64/ # CUDA ORT + CUDA libs (optional)
├── onnxdml64/ # DirectML ORT (optional)
└── ffmpeg64/ # FFmpeg shared DLLs for record (optional)
Each OCR pack needs ONNX models + configs.txt (and dict/keys as required by the pack).
cd WpfOCR
dotnet build -c ReleaseRun:
./WpfOCR/bin/Release/net48/WpfOCR.exeA plain build does not ship models, onnxcpu64, full CUDA, or FFmpeg. Use Tools → Install features (or first-run wizard) inside the app.
Release builds also produce a small redistributable under WpfOCR\bin\Release\WpfOCR\:
- Includes:
WpfOCR.exe,x86host.exe(32-bit SAPI web), managed dependencies,wetext/(ITN), Assets, LICENSE. - Does not include: OCR/ASR/TTS models,
onnxcpu64/onnxgpu64/onnxdml64, OpenCV/Skia/PDFium/Sherpa natives,ffmpeg64. - End users install those via Install features (downloads from mirrors / NuGet CDN).
- Translation is not covered by the installer: place Opus-MT ONNX under
translatemodels/yourself if needed.
For local development with models and GPU already present, run bin\Release\net48\ instead.
node scripts/publish-release.mjsRuns Release build, then packs WpfOCR/bin/Release/WpfOCR/ into release/wpfocr_<version>.7z (requires 7-Zip on PATH). The release/ folder is gitignored.
- First launch may open the install wizard (defaults: OpenCV, ORT CPU, OCR
rapid-ch, first two ASR packs, FFmpeg; GPU/iGPU off). - Later: Tools → Install features
- Components: OpenCV, Skia, PDFium, Sherpa, ORT CPU (
onnxcpu64), OCR/ASR packs, CUDA, DirectML, FFmpeg. - Voices: TTS models with language filter; progress shows total batch size and downloaded bytes.
- Components: OpenCV, Skia, PDFium, Sherpa, ORT CPU (
- Using a feature that needs a missing package prompts to open the installer (e.g. OCR without any ORT → install
onnxcpu64).
| Runtime | Role | Typical size |
|---|---|---|
| onnxcpu64 | CPU ONNX Runtime (required for OCR if no GPU/iGPU ORT) | ~16 MB |
| onnxgpu64 | NVIDIA CUDA EP + CUDA/cuDNN (optional) | large |
| onnxdml64 | DirectML EP for iGPU (optional) | ~18 MB |
| OpenCV | Capture / image pipeline | ~61 MB |
| ffmpeg64 | Screen record encode/mux | ~72 MB |
Download prefers CN mirrors when UI or system locale is Chinese.
Optional env vars for local full libraries (do not commit secrets/paths into docs meant for others):
| Variable | Meaning |
|---|---|
WPF_OCR_CUDA_LIB |
Folder with full CUDA / onnxgpu64 DLLs |
WPF_OCR_FFMPEG_LIB |
Folder with FFmpeg 4.4 shared DLLs |
Settings are stored in config.toml beside the exe (also editable via Tools → Settings / Record options). The Settings window groups options into tabs: General, OCR, Hotkeys, Speech, Capture, API.
[ocr]
model_pack = "rapid-ch"
model_variant = "简体中文 mobile"
device = "Cpu" # Cpu | Gpu | IntelGpu
det_limit = 960
det_thresh = 0.3
det_box_thresh = 0.5
use_cls = true
[ui]
hotkey = "Ctrl+Alt+O" # show / hide main window
hotkey_snap = "Ctrl+Alt+Q" # screenshot annotate
hotkey_snap_ocr = "Ctrl+Alt+W" # screenshot + OCR
minimize_to_tray = true
capture_log = false # true → log/capture.log
ui_lang = "zh" # zh | en
[http]
http_enabled = true
http_host = "127.0.0.1"
http_port = 1224
service_mode = false # keep engine warm
[pdf]
pdf_invisible_text = true
pdf_dpi = 150 # internal raster DPI; page size follows original PDF
[record]
record_codec = "x264" # x264 | x265 | av1
record_fps = 24
record_crf = 28 # x264/x265 only, 0–51, higher = smaller
record_av1_crf = 56 # AV1 only, 0–63 (different scale; 56 ≈ half of x265 CRF28 size)
record_audio = true
record_audio_src = "Speakers" # Speakers | Mic | MicAndSpeakers
record_audio_kbps = 96
record_max_size = false
record_max_w = 1920
record_max_h = 1080
record_lock_aspect = true # lock aspect when resizing HUD region after Start (free before Start)
[asr]
asr_voice_mode = "stream" # stream = live; offline = record until hotkey stop, then one-shot ASR
asr_voice_polish = true # LLM polish for voice input (needs asr_llm_url + asr_llm_model)
asr_voice_split = true
asr_voice_split_sec = 5 # split only after this many seconds of silence (1–30); do not cut continuous speech
asr_live_mode = "stream" # stream | offline (offline splits on silence)
asr_live_polish = false # LLM polish each live-caption sentence
asr_live_split = true # auto-split after polish / completed sentences
# asr_llm_url / asr_llm_model required when a polish checkbox is on (OpenAI-compatible)
# asr_llm_token = "" # do not commit secrets
# asr_llm_prompt = "..."
# Polish sends prior output in the same session as context (homophones / names).
# Voice HUD: line 1 stays “listening…”; line 2 is “识别中” / “润色中” plus transcript.
# After polish+inject, line 2 is cleared.
# Esc during recognize/polish stops the session with no inject.
[gif_record]
gif_fps = 8 # default output FPS in preview (1–24); capture is 24 fps
gif_max_size = true
gif_max_w = 1280
gif_max_h = 720
gif_colors = 128 # palette colors in preview (32/64/128/256)
gif_scale = 100 # default scale % in previewLeave a hotkey string empty to disable that hotkey.
Do not commit real config.toml if it encodes machine-specific paths or preferences you want private.
- Capture → Screen record (or the toolbar button): click a window or drag a region.
- HUD (drawn outside the capture area):
- Red frame; drag the 5px strip outside the red line to move, or 8 grips to resize. Before Start, aspect ratio is free; after Start, resizing locks aspect ratio unless disabled in record options (
record_lock_aspect = false). Encoded resolution is fixed when you press Start. - Floating control bar: drag via the left grip; collapse to mini bar; Options before Start (record/GIF settings); start/pause share one slot.
- Bar auto-positions above/below the region and stays within the current monitor (multi-monitor safe).
- Red frame; drag the 5px strip outside the red line to move, or 8 grips to resize. Before Start, aspect ratio is free; after Start, resizing locks aspect ratio unless disabled in record options (
- Stop → confirm save → MP4 is written; Explorer opens and selects the file.
- Capture → Record options: codec (x264 / x265 / AV1), FPS, CRF (x264/x265) and AV1 CRF (AV1 only, separate scale 0–63, default 56), audio source, max output size. AV1 needs an encoder in
ffmpeg64(libsvtav1 / libaom-av1); a missing encoder fails with a message and does not fall back to x264.
- Capture → GIF record: same window/region pick.
- Same HUD; capture at 24 fps; after Stop, the preview window lets you set output FPS (1–24), scale, and palette colors, then save a silent GIF.
- Capture → GIF record options: default output FPS, max width/height, default colors.
Notes
- MP4 / GIF recording requires FFmpeg shared under
ffmpeg64/(install in-app or place manually). OpenCV is not used for video encode. - System-loopback audio pads silence on wall-clock gaps so late sound is not shifted to the start of the file.
- Temporary files live under the app
tmp/folder and are cleaned up after a successful save. - GIF size grows quickly with resolution and duration — use preview scale/FPS and the max-size limit.
| Hotkey | Action |
|---|---|
Ctrl+Alt+O |
Toggle main window show / hide |
Ctrl+Alt+Q |
Screenshot annotate |
Ctrl+Alt+W |
Screenshot and OCR |
Ctrl+Alt+V |
Voice input (press again to stop) |
Ctrl+Alt+B |
Live caption |
Tray icon: left-click toggles the window; context menu includes voice input, clipboard OCR, on-capture copy mode (image / file / path), and exit. Switching copy mode re-copies the last screenshot to the clipboard in the new form. Closing the main window typically hides to tray rather than exiting. Capture → Voice input in the main menu is the same toggle.
- Tools → Language → 中文 / English (applies immediately)
- Or set UI language in Settings → General
- Persisted in
config.tomlasui_lang = "zh"or"en"
WpfOCR --image <path> [options]
WpfOCR --snap [--out <dir>]
WpfOCR --list-models
WpfOCR --list-sapi # local SAPI + (x64) x86host voices
WpfOCR --probe-cuda
WpfOCR --help
Useful options: -d gpu|cpu, -p rapid-ch, -v <variant>, -m <models-dir>, --det-limit, --no-cls.
Some classic SAPI voices register only for 32-bit processes. Ship x86host.exe next to WpfOCR.exe (built from x86host/; a Release build of WpfOCR also builds and copies it).
| Item | Detail |
|---|---|
| Role | HTTP helper: list SAPI voices + synth WAV; no GUI, no OCR/ASR |
| Start | On demand by the x64 app, or run x86host.exe manually |
| Bind | 127.0.0.1 only, default port 17886 |
| Idle | Exit after 60s without requests (--idle-ms to override) |
| API | GET /api/sapi/status · GET /api/sapi/voices · POST /api/sapi/synth · POST /api/sapi/shutdown |
dotnet build x86host/x86host.csproj -c Release
x86host.exe --port 17886 --idle-ms 60000
x86host.exe --list-sapi
In the UI, choose engine SAPI: local voices plus x86-only entries (display name ends with · x86); speak/export for those voices goes through x86host.
When enabled, a local server listens on http_host:http_port (default loopback only).
GET /api·/api/status— capabilitiesPOST /api/ocr— image (JSON base64 or multipart)GET /api/ocr/get_options— OCR options snapshotGET /api/asr/models·POST /api/asr— speech recognitionGET /api/tts/models·POST /api/tts— TTS (wav base64)POST /api/itn— inverse text normalization
Bind to 127.0.0.1 unless you intentionally expose the service on a trusted network.
Full field reference: HTTP-API.md · HTTP接口文档.md (中文).
Set capture_log = true in config.toml to write log/capture.log (multi-monitor / DPI troubleshooting). Keep it off for normal use.
CLI: WpfOCR --snap dumps full-monitor bitmaps under log/snap/ (or --out).
WpfOCR application source code (this repository’s WpfOCR/ sources, scripts, and docs authored for the project) is released under the MIT License. See LICENSE.
Copyright (c) 2026 WpfOCR Contributors
You may use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, subject to including the copyright and permission notice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
Bundled or optional dependencies are not all MIT. Models, FFmpeg builds, CUDA/cuDNN, and some native libraries keep their own terms. See THIRD_PARTY_NOTICES.md.
Do not commit large ONNX weights, CUDA redistributables, or FFmpeg shared binaries into git without a redistribution plan that matches their licenses.
- LICENSE — MIT (application source)
- THIRD_PARTY_NOTICES.md — dependency license notes
- CHANGELOG.md
- HTTP-API.md · HTTP接口文档.md — HTTP API
- README.zh.md — Chinese documentation
