远程 OCR 必须配置可用的 DeepSeek OCR 兼容服务,示例中的 example.com 只是占位地址;本地 OCR 需额外安装 [local] 及匹配 CUDA 的 PyTorch 并下载模型;转换前还需自行安装 Poppler 系统依赖。
pdf-craft
oomol-labMIT活跃维护把扫描版 PDF 书籍转成 Markdown、EPUB 等格式,结合 DeepSeek OCR 处理影印书,方便数字化阅读和翻译。
PDF craft can convert PDF files into various other formats. This project will focus on processing PDF files of scanned books.
python -m pip install pdf-craft
python -m pip install "pdf-craft[local]"本地 OCR 需要 NVIDIA GPU、CUDA、足够显存和模型文件(默认从 Hugging Face 下载);用远程 OCR 则不需要本地 CUDA,只需 Python 3.11–3.13 和 Poppler。
把扫描版 PDF 书籍转成可编辑 Markdown 或 EPUB 的 Python 库,还能顺带翻译
把扫描版 PDF 书籍转成 Markdown、EPUB 等格式,结合 DeepSeek OCR 处理影印书,方便数字化阅读和翻译。
核心能力
- 识别正文、章节、目录、脚注、表格、公式和图片
- PDF 转 Markdown 并输出配套图片资源
- PDF 转 EPUB 带书籍元数据与目录
- 转换时翻译或单独翻译 EPUB,支持双语输出
- 把译文写回原 PDF 页面生成翻译版
容易踩的坑
- v2.6.7最新正式版2026-10-28 · 2026-10-28 13:22 UTC
PDF Craft v2.6.7
Restore incremental PDF extraction
on_body/on_footnotedelivery after the 2.6.6 regression. Closed page-processed paragraphs and footnotes arrive while OCR and later analysis are still running, without a duplicate replay at completion.Page refinement now runs as a bounded pipeline: JEV starts when its initial neighbor inputs are ready; the target LLM follows only that page's score. Neighbor scores and refined neighbor content never enter its prompt. Ordered assembly emits closed processed paragraphs/footnotes without waiting for whole-book OCR, other JEV jobs or final TOC. This supersedes the temporary pre-refinement preview. The initial paragraph boundary survives intervening image/table-only pages without retaining those pages in memory. Cancellation also interrupts a full refinement window, then settles its page jobs before releasing providers and workers. OCR completions now enter refinement by neighborhood readiness rather than a contiguous page prefix. An unrelated earlier slow OCR page no longer blocks a ready JEV/LLM job. Cross-window identities remain resolved at ordered assembly; finished later jobs free request slots while their results wait on disk.
Callbacks describe page-processed content; final TOC/heading levels and directory exclusion may organize the PCEX differently. Final TOC, chapter and furniture consistency checks remain in place. See streaming callbacks and 中文说明.
Ordered delivery, source identities, disk buffering, callback errors and cancellation remain supported. Barrier regressions guard timely delivery independently of unrelated pages, whole-book scoring and final packaging. The progress event schema and PCEX format are unchanged; PAGE completion now reports local page-work completion rather than waiting for publication.
EPUB accepted atomic fragments now notify before unrelated chapter groups finish. Word progress and content delivery remain independent. PDF layout no longer waits for document metadata or all furniture: shared templates and page fragments feed individual page dependencies; body/note previews keep separate ordered channels. Final metadata and PDF page ordering are joined at publication. Necessary whole paragraph and page-level typography constraints remain unchanged.
Independent PDF pages isolate preceding-body font state: heading sizes and preview geometry no longer depend on translation completion order. Pages without a body reference use the configured headline fallback.
See the streaming design rationale (Chinese) for the product latency contract, immutable inputs, backpressure and the deliberate tradeoff of omitting neighbor JEV scores.
PDF layout now fits each ready paragraph once and finalizes pages from their direct inputs, rather than waiting for a transitive chain of cross-page paragraphs. Cross-page previews accumulate actual final regions on disk and publish only when the paragraph's own regions are complete. Page typography remains independent of arrival order; paragraph fitting and page normalization retain separate boundaries.
Related changes: #564, #565, #566, #567.
Full Changelog: https://github.com/oomol-lab/pdf-craft/compare/v2.6.6...v2.6.7
- v2.6.62026-10-28 · 2026-10-28 07:27 UTC
查看更新说明
PDF Craft v2.6.6
PDF Craft 2.6.6 fixes concurrent PDF extraction, footnote OCR masks, XML fill whitespace recovery, and chapter consistency after refinement. Downstream content now comes from one finalized extraction result.
Migration from 2.6.5
- Extraction PAGE progress now uses stages 0–7 (
max_stage=7). Update numeric labels: the previous OCR-persisted/JEV/LLM/final stages 2/3/4/5 become 4/5/6/7. First OCR, second-pass image preparation and second OCR have separate entry events. Async PDF pre-rendering remains in stage 0. See the stage table. #552, #553. - Extraction
on_body/on_footnotecallbacks now deliver finalized, validated content once, after optional refinement and chapter assembly. The first content callback arrives later; useon_extraction_eventfor live progress. Callback delivery is not a task-success signal. Metadata may still arrive earlier. - Derived TOC, chapter and furniture files are rebuilt from adopted content;
existing
toc.xmlis no longer trusted as input. Valid raw OCR caches remain reusable. Re-extraction may assign different chapter IDs; existing PCEX files retain their format and identities. See streaming and cache migration.
Fixes
-
Fix PCEX translation end-of-input races: title-dependent furniture waits for its producer, and body/footnote callbacks drain the final content exactly once in channel order. Failed or cancelled input scans are not successful EOF. Queue emptiness is checked after observing successful production completion.
-
Serialize live page consumption across concurrent preparation/completion events, fixing duplicate pages and
KeyError. Isolate blocking analysis and rendering workers from the short-IO pool, coordinate cancellation and callback draining, and settle concurrent work-unit completion only once. #560. -
Finalize traditional/refined content before deriving chapter IDs, TOC and furniture. Removing or merging a heading no longer leaves stale directory anchors; furniture uses final ownership. Formal content callbacks match adopted chapters. Private disk chunks bound intermediate aggregation without restoring pre-refinement directory constraints. #561.
-
Preserve the complete union of first-pass OCR redaction masks. A lower, narrower text box no longer leaves the right side of a wider box exposed to the second footnote pass, preventing duplicate recognition from that leak. #554.
-
Share document-whitespace semantics across friendly XML, segmentation and fill recovery. Preserve inline word boundaries and special spaces; reconstruct unambiguous canonical whitespace instead of spending another LLM request. Protected contexts retain their semantics; ambiguous allocation and changed words or punctuation still require correction. See LLM acceptance. #556, #558.
-
Allocate merged canonical formulas through immutable math references, retain required empty source slots, and keep boundary spaces outside formula content that will be replaced. Accepted separators survive source-formula restoration. #557, #559.
-
Preserve mixed-content text when serializing ordinary and streamed PCEX chapters; XML indentation no longer inserts separators between adjacent formulas. #555.
PCEX v4 and the progress event object structure are unchanged. The PAGE stage numbers and extraction content-callb
- Extraction PAGE progress now uses stages 0–7 (
- v2.6.52026-10-26 · 2026-10-26 14:37 UTC
查看更新说明
PDF Craft v2.6.5
PDF Craft 2.6.5 adds translation-size previews and operation-scoped resource reports, so applications can inspect source words before execution and observed remote consumption after completion, failure or cancellation.
- New
pcex_words_countandepub_words_countread-only queries share the actual translation pre-scan and source-word rules. Matching options produce the same total as translation'sSTARTED.total_words. Both Craft facades expose methods; the async facade keeps parsing outside the event loop. - New
UsageCollector,UsageReport,UsageandRequestUsagegroup observed requests and input/output/cache-hit input tokens by original provider object. Passusage=to model-calling operations and inspectusage.report()without changing the operation's existing return type. - Accepted and discarded consumption are separated as
effectiveandwasted, including transport retries and business validation loops. Missing usage is not estimated. Provider prompt cache is distinguished from ordinary input; local cache hits do not create external consumption. - Support LLM, JEV and OCR vendors. OCR counts recognition submissions rather than
pages, authentication calls or polling. Existing
OCRTokensMeteringis retained. - Classify translation and fill consumption for withdrawn PCEX metadata collections
as wasted, including otherwise valid members of an incomplete
subjectslist. Independent accepted fields retain their effective consumption. Collections are translated separately from scalar fields so their usage can be settled accurately. - Adopt
doc-page-extractor1.2.2 and clip second-pass vendor OCR boxes against the actual redaction masks. This prevents later-stage detections from extending into previously recognized regions, including oversized footer boxes that blocked PDF translation writeback. See #545. - Read PCEX queue readiness and results from one SQLite snapshot, avoiding a race where online rendering or callbacks could read an unfinished result during scanning.
- See usage and sizing or 中文说明 for examples, the accounting boundaries, and limitations. PCEX v4 and progress events are unchanged.
Resource reporting and task sizing: #550.
Full Changelog: https://github.com/oomol-lab/pdf-craft/compare/v2.6.4...v2.6.5
- New
- v2.6.42026-10-26 · 2026-10-26 11:22 UTC
查看更新说明
PDF Craft v2.6.4
PDF Craft 2.6.4 unifies extraction and translation progress, counts source words consistently, and starts independent metadata and PCEX translation work as soon as its inputs are ready. This release includes breaking progress API changes; callback consumers should follow the migration notes below. PCEX v4 is unchanged.
Unified work-unit progress
- Extraction and translation now report
ProgressEventwith onlySTARTED,PROGRESS, andCOMPLETED. An operation starts with required per-kindunit_counts; translation also supplies pre-scanned sourcetotal_words. - Work units receive operation-local integer IDs only when execution begins.
Each reports integer
stage/max_stagevalues and a finalUnitOutcome. Stages describe an individual unit, not a serial phase of the whole document. - Standard XML translation reports after each accepted or final-fallback round, including heading, metadata, furniture and chapter work. Retries do not count work twice. Allowed ignore, fallback, skip and cache paths settle their units and words; operation completion follows successful output publication.
- EPUB pre-scans the same source tasks used for translation without buffering
the book. Empty XML tasks settle as
SKIPPED; assets are counted independently of request batches. EPUB navigation and document titles share NAVIGATION, while OPF book fields belong to METADATA. - See #546, #547, and the progress protocol and stage numbers. Fixes the progress-reporting gaps discussed in #544.
Shared source-word counting
- All translation accounting uses one streaming implementation, exported as
WordCounter,count_text_words, andMAX_WORD_LENGTH. - Each Han character counts as one word. Other consecutive Unicode letters and
numbers count as
ceil(length / 20)words; combining marks extend a word without increasing its length. Whitespace and punctuation separate words. - XML inline tags and streaming chunks do not split words; paragraph and field boundaries do. Original context prompts and reused headings are not counted as additional translation work. Counts use source text, not output or tokens.
Dependency-aware concurrency
- OCR-based book metadata starts from committed front-page evidence while later OCR continues. Additional reads wait only for requested pages, up to twelve. Native-only metadata is reported before OCR and saved consistently regardless of whether content or progress callbacks are registered.
- PCEX metadata, body, footnotes, image/table text and furniture share one bounded
windowand the existing translator executor. Internal group windows do not multiply that capacity;window=1remains serial. - Furniture waiting for a heading occupies no execution slot. A final heading result releases its dependants immediately, including fallback. Assets wait only for necessary original-text context, never for translated body text.
- Pending work and out-of-order results live on temporary disk. Body and footnote callbacks each preserve source order independently of the other channel and ordered output writing. Closing a content stream early cancels remaining work without reporting false operation completion.
- Close progress SQLite connections explicitly and avoid waiting for replacement events on failed caches belonging to pages not selected for this operation.
- See #548 and PCEX scheduling and delivery.
Breaking API migration
- Replace root
OCREvent/OCREventKindandTranslationEvent/TranslationEventKind/TranslationItemKindimports with the unifiedProgressEvent,ProgressEventKind,OperationKind, `UnitKin
- Extraction and translation now report
- v2.6.32026-10-25 · 2026-10-25 04:07 UTC
查看更新说明
PDF Craft v2.6.3
PDF Craft 2.6.3 preserves the original cause of concurrent service failures, coordinates temporary rate limits across request pools, and replaces automatic PDF input gating with optional input assertions. It also fixes XML fill text handling and PDF-to-PCEX directory/chapter consistency during refinement and recovery. Operation-scoped request headers now propagate across model-service calls.
Operation-scoped request headers
- Model-calling operations accept keyword-only
request_headers, including synchronous/asynchronous Craft facades and advanced components. Headers reach LLM, DeepSeek OCR/OCR2, Unlimited OCR token/submission/polling, and JEV calls, including retries and nested translation/fill recovery. - Each operation snapshots its headers without mutating shared clients or model
configurations. Concurrent operations remain isolated; nested operations inherit
headers by default, an explicit mapping replaces them, and
{}clears them. - Headers are not attached to resource downloads or caller-owned image resolvers. Authentication, routing and body-framing headers remain client-managed.
- Pass headers to the operation, not the
LLMor OCR configuration constructor. Applications migrating from experimental instance-levelheaderssupport must move their mapping torequest_headerson each operation. - See #542 and the request-header API.
Concurrent failures
- The first recorded fatal error remains the cause of the operation failing, even when sibling cancellation is collected first or cleanup also fails.
- OCR HTTP 402 and HTTP 429 quota failures retain their original HTTP status and exception chain. Ordinary user cancellation still propagates as cancellation.
- The same protection applies across OCR, JEV, translation/fill and their surrounding pipelines. See #535.
Shared rate-limit recovery
- New optional
RateLimitScope()instances coordinate executors using the same provider quota. Executors without an explicit scope receive their own scope. - Temporary limits trigger shared cooldown, one probe request, and gradual, spaced recovery. Waiting releases request capacity and supports cancellation.
- Defaults are
cooldown_seconds=1.0andmax_wait_seconds=600.0. The latter is a separate cumulative waiting budget for each logical request. Exhaustion raisesRateLimitTimeoutError; existing total request timeouts still apply. - LLM, JEV and OCR vendor temporary limits no longer consume ordinary retry counts, including when those counts are zero. Existing retry parameters remain available for non-rate failures and provider-specific recovery.
- Numeric and HTTP-date
Retry-Aftervalues are supported, along with structured LLM rate-limit errors received after a streaming HTTP 200 response starts. Payment/quota failures remain fatal, rather than triggering cooldown. - See #537 and the shared rate-limit API.
Optional input checks and migration
- Conversion no longer runs mandatory whole-file PDF preflight. Failures surface at the actual operation, retaining supported page-level recovery.
- Applications can explicitly call
assert_pdf_readable,assert_pdf_renderable,assert_pdf_editableorassert_epub_readable. These blocking checks returnNoneor raise the original backend/parser error; they do not repair inputs or guarantee a complete conversion. - Breaking change:
PDFPreflightErroris removed frompdf_craftandpdf_craft.error, together with the automatic gate. Remove its imports and catch clauses; optional assertions propagate original backend/parser errors. - Existing conversion entry points and LLM/OCR configuration parameters remain available. See [#536](
- Model-calling operations accept keyword-only
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
PDF Craft is a Python library for scanned books, research papers, and technical documents. It converts scanned PDFs into editable Markdown or reader-friendly EPUB. It can also translate PDF and EPUB content into another language, create translated or bilingual EPUBs, and write translations back onto the original PDF pages. It recognizes body text, chapters, tables of contents, footnotes, tables, formulas, and images so the content can be searched, edited, and read beyond the scanned page.
Convert online — no installation needed
Have a scanned PDF you want to edit or read as an ebook? Use PDF Craft Online · pdfcraft.ai: upload your file in a browser, submit a conversion task, and download the result when it is ready. There is no Python to install, no CUDA to configure, and no OCR provider or API key to set up.
PDF Craft Online is the official online service for this open-source project. Use it to convert your files directly, or use the Python library below to build conversion into your own application or run OCR on your own machine.
Upload your PDF and convert it online →
Conversion examples
Markdown: edit, search, and process the content.

EPUB: read the book in an ebook reader.

Results depend on scan quality, page layout, and the OCR model. Check a representative document before processing a larger collection.
Want to see how your own file turns out? Upload a PDF and convert it to Markdown or EPUB →
What you can do
| Your goal | PDF Craft provides |
|---|---|
| Edit scanned books | PDF → Markdown, with text and image assets |
| Read in an ebook reader | PDF → EPUB, with book metadata and table of contents |
| Read books in another language | Translate during conversion or translate an existing EPUB; translation-only and bilingual output modes |
| Create a translated PDF | Translate extracted text and write it back onto the source pages |
| Integrate conversion into an app | Python APIs and reusable extraction files for later rendering or translation |
Choose how to use it
| Path | Best for | Requirements |
|---|---|---|
| Online conversion | Upload a file and download Markdown or EPUB | A browser; no Python installation or OCR service setup |
| Python + remote OCR | Developers who do not want to run OCR models locally | Python, Poppler, a compatible OCR service URL and credentials |
| Python + local OCR | Developers with their own NVIDIA GPU | Python, Poppler, CUDA, sufficient VRAM, and model files |
Remote OCR sends pages to the configured service and does not require local CUDA. Local OCR runs on your machine; using a remote LLM for translation or table-of-contents analysis still sends the corresponding content to that service.
Python quick start
This example uses remote OCR to convert a PDF to Markdown. Prepare Python 3.11–3.13, Poppler, and a working DeepSeek OCR-compatible service configuration. See the installation guide for Poppler setup.
Just need to convert a file without setting up a development environment or OCR service? Use PDF Craft Online and upload your PDF in a browser.
1. Install
python -m pip install pdf-craft
2. Convert a PDF
Place input.pdf in the directory where you run your script. Replace the URL, API key, and model name with your service configuration:
from pdf_craft import DeepSeekOCRVendorConfig, PDFCraft, PDFOptions
craft = PDFCraft(
pdf=PDFOptions(
ocr=DeepSeekOCRVendorConfig(
base_url="https://example.com/v1",
api_key="your-api-key",
model="deepseek-ocr",
),
),
)
craft.convert_pdf_to_markdown("input.pdf", "output.md")
Async applications use the same options through AsyncPDFCraft; callbacks may
also be async def functions and run on the caller's event loop:
import asyncio
from pdf_craft import AsyncPDFCraft, DeepSeekOCRVendorConfig, PDFOptions
async def main():
craft = AsyncPDFCraft(pdf=PDFOptions(ocr=DeepSeekOCRVendorConfig(
base_url="https://example.com/v1",
api_key="your-api-key",
model="deepseek-ocr",
)))
await craft.convert_pdf_to_markdown("input.pdf", "output.md")
asyncio.run(main())
Do not call the synchronous PDFCraft facade from a running event loop; use
AsyncPDFCraft and await its corresponding method instead.
https://example.com/v1 is a placeholder, not a working endpoint. Use a compatible service that actually provides the OCR model. See OCR configuration for other models. If you do not have an OCR service yet, you can convert your files with PDF Craft Online.
Open output.md after conversion. Documents containing images also produce asset files; keep those files with the Markdown when moving or sharing it.
3. Create an EPUB
Reuse the configured craft instance above and replace the last line with:
craft.convert_pdf_to_epub("input.pdf", "output.epub")
Open output.epub in an EPUB reader. For title, author, and rendering options, see PDF conversion and translation. For installation or runtime problems, see troubleshooting.
For EPUB bibliographic metadata, opt in to front-page OCR metadata extraction and provide a separate metadata LLM. PDF Craft accepts only values it can verify against OCR evidence. PDF file properties fill missing fields; they never override information printed in the book.
Optional input assertions
Conversion does not automatically validate the whole input. If needed, call
assert_pdf_readable, assert_pdf_renderable, assert_pdf_editable, or
assert_epub_readable from pdf_craft before conversion. Choose the operation
you need: success returns None, failure raises the original exception, and the
input is never repaired or modified. Passing does not guarantee later OCR or
translation succeeds. See usage and capability limits.
Translation and reusable extraction
Translate books. Supply an XMLTranslator when converting PDF to Markdown or EPUB, or translate an existing EPUB directly. Translation uses a separate text LLM; OCR and translation have independent configurations. EPUB translation can replace the original text or append the translation for bilingual reading.
Create a translated PDF. Extract the content, translate it, and write the translation back onto the original pages. This workflow needs suitable local fonts; the default fill preserves source graphics and removes masked source characters. Check the resulting layout against the source and translated text.
Extract once, reuse later. Save a .pcex extraction file for subsequent rendering, translation, or processing on another machine. Reuse the configured craft instance:
craft.convert_pdf_to_markdown(
"input.pdf",
"output.md",
extraction_path="book.pcex",
)
Preview content as it is processed. PDF extraction, EPUB translation, and PCEX translation/rendering support optional callbacks. Receive source-mapped paragraphs, translated EPUB fragments, final PDF layout data, and finalized book metadata before the complete output file is ready. See incremental callbacks.
See PDF conversion and translation, EPUB translation, and the .pcex format reference.
OCR and runtime requirements
PDF Craft supports DeepSeek OCR, DeepSeek OCR 2, and Unlimited OCR, each with local and remote configurations.
The standard installation supports remote OCR. For local OCR, install the extra:
python -m pip install "pdf-craft[local]"
Local execution also requires a matching CUDA-enabled PyTorch build, sufficient VRAM, and model files. Models download from Hugging Face by default; you can also download them in advance and load them locally. Presets and requirements vary by model; see OCR configuration.
Language support depends on the processing stage. README languages describe documentation availability. Text recognition depends on the OCR model, and translation depends on the translator and text LLM. The EPUB label_language parameter selects fixed navigation/default-title labels (zh / en, with English as the default and fallback); it does not restrict content or translation languages; see the API reference.
Documentation
| Task | Guide |
|---|---|
| Preview task size and inspect remote resource consumption | Usage and sizing |
| Install system dependencies and configure a local GPU | Installation |
| Select OCR models, remote services, or model caches | OCR backends |
| Convert PDFs, create EPUBs, or write translations into PDFs | PDF conversion and translation |
| Translate existing EPUBs and configure bilingual output | EPUB translation |
| Display incremental content and source locations | Callback guide |
| Understand extraction streaming and latency tradeoffs | Design rationale (Chinese) |
| Look up parameters, types, and methods | API reference |
| Store or exchange extraction results | .pcex format |
| Resolve installation and conversion issues | Troubleshooting |
| Upgrade to 2.6.0: retry and recovery policies | Migration guide |
| Upgrade to 2.6.4: progress API migration and concurrency | Release notes · Migration guide |
Feedback and contributions
Report problems or suggest improvements through Issues. For conversion problems, include the package version, OCR configuration type, error logs, and a minimal file you can share publicly. Remove credentials and private content first.
Pull requests improving code, documentation, and translations are welcome. Use the Chinese README as the content baseline for all languages. Write naturally for local readers, preserving the focus on online conversion and translation capabilities, and keep API examples accurate.
If PDF Craft helps you, a Star helps others discover it.
Related projects
Wiki Graph can turn converted EPUB or Markdown books into structured summaries, chapter topology, and knowledge graphs.
License and acknowledgments
PDF Craft uses the MIT license. Third-party dependencies and selected OCR models retain their own licenses.
Thanks to DeepSeek OCR, DeepSeek OCR 2, Unlimited OCR, doc-page-extractor, pyahocorasick and the open-source projects that make PDF Craft possible.
Contributors
Thanks to everyone who has contributed to PDF Craft. Contributions to code, documentation, and translations are welcome.
Star History
Translation progress reports source words (one Han character per word, long-word cap 20), with complete pre-scanned totals and per-round updates. See translation progress.
Extraction and translation share unit progress events, with upfront counts, integer stages, and source words.
