BabelDOC 0.2.31__tar.gz → 0.2.33__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {babeldoc-0.2.31 → babeldoc-0.2.33}/PKG-INFO +4 -1
  2. {babeldoc-0.2.31 → babeldoc-0.2.33}/README.md +3 -0
  3. babeldoc-0.2.33/babeldoc/__init__.py +1 -0
  4. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/const.py +1 -1
  5. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/styles_and_formulas.py +2 -0
  6. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/high_level.py +27 -20
  7. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/main.py +8 -1
  8. babeldoc-0.2.33/babeldoc/tools/italic_assistance.py +205 -0
  9. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/translation_config.py +2 -0
  10. {babeldoc-0.2.31 → babeldoc-0.2.33}/pyproject.toml +2 -2
  11. {babeldoc-0.2.31 → babeldoc-0.2.33}/uv.lock +1 -1
  12. babeldoc-0.2.31/babeldoc/__init__.py +0 -1
  13. {babeldoc-0.2.31 → babeldoc-0.2.33}/.cursorignore +0 -0
  14. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  15. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  16. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/dependabot.yml +0 -0
  17. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/labels.yml +0 -0
  18. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/release-drafter.yml +0 -0
  19. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/workflows/codeql.yml +0 -0
  20. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/workflows/docs.yml +0 -0
  21. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/workflows/labeler.yml +0 -0
  22. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/workflows/publish-to-pypi.yml +0 -0
  23. {babeldoc-0.2.31 → babeldoc-0.2.33}/.github/workflows/test.yml +0 -0
  24. {babeldoc-0.2.31 → babeldoc-0.2.33}/.gitignore +0 -0
  25. {babeldoc-0.2.31 → babeldoc-0.2.33}/.pre-commit-config.yaml +0 -0
  26. {babeldoc-0.2.31 → babeldoc-0.2.33}/LICENSE +0 -0
  27. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/assets/assets.py +0 -0
  28. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/assets/embedding_assets_metadata.py +0 -0
  29. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/asynchronize/__init__.py +0 -0
  30. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/converter.py +0 -0
  31. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/__init__.py +0 -0
  32. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/babeldoc_exception/BabelDOCException.py +0 -0
  33. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/backend/__init__.py +0 -0
  34. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/backend/pdf_creater.py +0 -0
  35. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/frontend/__init__.py +0 -0
  36. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/frontend/il_creater.py +0 -0
  37. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/il_version_1.py +0 -0
  38. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/il_version_1.rnc +0 -0
  39. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/il_version_1.rng +0 -0
  40. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/il_version_1.xsd +0 -0
  41. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/__init__.py +0 -0
  42. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/add_debug_information.py +0 -0
  43. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/detect_scanned_file.py +0 -0
  44. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/il_translator.py +0 -0
  45. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/il_translator_llm_only.py +0 -0
  46. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/layout_parser.py +0 -0
  47. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/paragraph_finder.py +0 -0
  48. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/remove_descent.py +0 -0
  49. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/table_parser.py +0 -0
  50. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/midend/typesetting.py +0 -0
  51. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/translator/__init__.py +0 -0
  52. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/translator/cache.py +0 -0
  53. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/translator/translator.py +0 -0
  54. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/utils/atomic_integer.py +0 -0
  55. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/utils/fontmap.py +0 -0
  56. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/utils/layout_helper.py +0 -0
  57. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/utils/priority_thread_pool_executor.py +0 -0
  58. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/utils/style_helper.py +0 -0
  59. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/document_il/xml_converter.py +0 -0
  60. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/docvision/README.md +0 -0
  61. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/docvision/__init__.py +0 -0
  62. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/docvision/doclayout.py +0 -0
  63. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/docvision/rpc_doclayout.py +0 -0
  64. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/docvision/table_detection/rapidocr.py +0 -0
  65. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/pdfinterp.py +0 -0
  66. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/progress_monitor.py +0 -0
  67. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/result_merger.py +0 -0
  68. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/split_manager.py +0 -0
  69. {babeldoc-0.2.31 → babeldoc-0.2.33}/babeldoc/tools/generate_font_metadata.py +0 -0
  70. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/CODE_OF_CONDUCT.md +0 -0
  71. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/CONTRIBUTING.md +0 -0
  72. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/CONTRIBUTOR_REWARD.md +0 -0
  73. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/ImplementationDetails/AsyncTranslate/AsyncTranslate.md +0 -0
  74. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/ImplementationDetails/ILTranslator/ILTranslator.md +0 -0
  75. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/ImplementationDetails/PDFCreation/PDFCreation.md +0 -0
  76. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/ImplementationDetails/PDFParsing/PDFParsing.md +0 -0
  77. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/ImplementationDetails/ParagraphFinding/ParagraphFinding.md +0 -0
  78. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/ImplementationDetails/README.md +0 -0
  79. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/ImplementationDetails/StylesAndFormulas/StylesAndFormulas.md +0 -0
  80. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/ImplementationDetails/Typesetting/Typesetting.md +0 -0
  81. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/README.md +0 -0
  82. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/deploy.sh +0 -0
  83. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-banner.png +0 -0
  84. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-big-logo-darkmode-with-transparent-background.png +0 -0
  85. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-big-logo-darkmode-with-transparent-background.svg +0 -0
  86. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-big-logo-with-transparent-background.png +0 -0
  87. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-big-logo-with-transparent-background.svg +0 -0
  88. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-big-logo.png +0 -0
  89. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-contributor_reward_example.png +0 -0
  90. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-preview.gif +0 -0
  91. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-small-logo-with-transparent-background.png +0 -0
  92. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-small-logo-with-transparent-background.svg +0 -0
  93. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/images/babeldoc-small-logo.png +0 -0
  94. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/index.md +0 -0
  95. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/intro-to-pdf-object.md +0 -0
  96. {babeldoc-0.2.31 → babeldoc-0.2.33}/docs/requirements.txt +0 -0
  97. {babeldoc-0.2.31 → babeldoc-0.2.33}/mkdocs.yml +0 -0
  98. {babeldoc-0.2.31 → babeldoc-0.2.33}/tests/test_translation_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: BabelDOC
3
- Version: 0.2.31
3
+ Version: 0.2.33
4
4
  Summary: Yet Another Document Translator
5
5
  Project-URL: Homepage, https://github.com/funstory-ai/BabelDOC
6
6
  Project-URL: Issues, https://github.com/funstory-ai/BabelDOC/issues
@@ -187,6 +187,7 @@ uv run babeldoc --files example.pdf --files example2.pdf --openai --openai-model
187
187
  - `--max-pages-per-part`: Maximum number of pages per part for split translation. If not set, no splitting will be performed.
188
188
  - `--no-watermark`: [DEPRECATED] Use --watermark-output-mode=no_watermark instead.
189
189
  - `--translate-table-text`: Translate table text (experimental, default: False)
190
+ - `--skip-scanned-detection`: Skip scanned document detection (default: False). When using split translation, only the first part performs detection if not skipped.
190
191
 
191
192
  > [!TIP]
192
193
  > - Both `--skip-clean` and `--dual-translate-first` may help improve compatibility with some PDF readers
@@ -194,6 +195,7 @@ uv run babeldoc --files example.pdf --files example2.pdf --openai --openai-model
194
195
  > - However, using `--skip-clean` will result in larger file sizes
195
196
  > - If you encounter any compatibility issues, try using `--enhance-compatibility` first
196
197
  > - Use `--max-pages-per-part` for large documents to split them into smaller parts for translation and automatically merge them back.
198
+ > - Use `--skip-scanned-detection` to speed up processing when you know your document is not a scanned PDF.
197
199
 
198
200
  ### Translation Service Options
199
201
 
@@ -268,6 +270,7 @@ use-alternating-pages-dual = false
268
270
  watermark-output-mode = "watermarked" # Choices: "watermarked", "no_watermark", "both"
269
271
  max-pages-per-part = 50 # Automatically split the document for translation and merge it back.
270
272
  # no-watermark = false # DEPRECATED: Use watermark-output-mode instead
273
+ skip-scanned-detection = false # Skip scanned document detection for faster processing
271
274
 
272
275
  # Translation service
273
276
  openai = true
@@ -141,6 +141,7 @@ uv run babeldoc --files example.pdf --files example2.pdf --openai --openai-model
141
141
  - `--max-pages-per-part`: Maximum number of pages per part for split translation. If not set, no splitting will be performed.
142
142
  - `--no-watermark`: [DEPRECATED] Use --watermark-output-mode=no_watermark instead.
143
143
  - `--translate-table-text`: Translate table text (experimental, default: False)
144
+ - `--skip-scanned-detection`: Skip scanned document detection (default: False). When using split translation, only the first part performs detection if not skipped.
144
145
 
145
146
  > [!TIP]
146
147
  > - Both `--skip-clean` and `--dual-translate-first` may help improve compatibility with some PDF readers
@@ -148,6 +149,7 @@ uv run babeldoc --files example.pdf --files example2.pdf --openai --openai-model
148
149
  > - However, using `--skip-clean` will result in larger file sizes
149
150
  > - If you encounter any compatibility issues, try using `--enhance-compatibility` first
150
151
  > - Use `--max-pages-per-part` for large documents to split them into smaller parts for translation and automatically merge them back.
152
+ > - Use `--skip-scanned-detection` to speed up processing when you know your document is not a scanned PDF.
151
153
 
152
154
  ### Translation Service Options
153
155
 
@@ -222,6 +224,7 @@ use-alternating-pages-dual = false
222
224
  watermark-output-mode = "watermarked" # Choices: "watermarked", "no_watermark", "both"
223
225
  max-pages-per-part = 50 # Automatically split the document for translation and merge it back.
224
226
  # no-watermark = false # DEPRECATED: Use watermark-output-mode instead
227
+ skip-scanned-detection = false # Skip scanned document detection for faster processing
225
228
 
226
229
  # Translation service
227
230
  openai = true
@@ -0,0 +1 @@
1
+ __version__ = "0.2.33"
@@ -3,7 +3,7 @@ import shutil
3
3
  import subprocess
4
4
  from pathlib import Path
5
5
 
6
- __version__ = "0.2.31"
6
+ __version__ = "0.2.33"
7
7
 
8
8
  CACHE_FOLDER = Path.home() / ".cache" / "babeldoc"
9
9
 
@@ -541,6 +541,8 @@ class StylesAndFormulas:
541
541
  r"|Times-Italic.*"
542
542
  r"|MeridienLTStd.*"
543
543
  r"|Calibri.*"
544
+ r"|STIXMathJax_Main-Regular.*"
545
+ r"|STIXMathJax_Main-Italic.*"
544
546
  r")$"
545
547
  )
546
548
  if self.translation_config.formular_font_pattern:
@@ -49,19 +49,19 @@ from babeldoc.translation_config import WatermarkOutputMode
49
49
  logger = logging.getLogger(__name__)
50
50
 
51
51
  TRANSLATE_STAGES = [
52
- (ILCreater.stage_name, 5.35), # Parse PDF and Create IR
53
- (DetectScannedFile.stage_name, 0.5), # No historical data, estimated
54
- (LayoutParser.stage_name, 6.42), # Parse Page Layout
55
- (TableParser.stage_name, 0.5), # Parse Table
56
- (ParagraphFinder.stage_name, 2.14), # Parse Paragraphs
57
- (StylesAndFormulas.stage_name, 1.12), # Parse Formulas and Styles
52
+ (ILCreater.stage_name, 14.12), # Parse PDF and Create IR
53
+ (DetectScannedFile.stage_name, 2.45), # DetectScannedFile
54
+ (LayoutParser.stage_name, 14.03), # Parse Page Layout
55
+ (TableParser.stage_name, 1.0), # Parse Table
56
+ (ParagraphFinder.stage_name, 6.26), # Parse Paragraphs
57
+ (StylesAndFormulas.stage_name, 1.66), # Parse Formulas and Styles
58
58
  # (RemoveDescent.stage_name, 0.15), # Remove Char Descent
59
- (ILTranslator.stage_name, 75.16), # Translate Paragraphs
60
- (Typesetting.stage_name, 3.84), # Typesetting
61
- (FontMapper.stage_name, 0.65), # Add Fonts
62
- (PDFCreater.stage_name, 1.41), # Generate drawing instructions
63
- (SUBSET_FONT_STAGE_NAME, 1.29), # Subset font
64
- (SAVE_PDF_STAGE_NAME, 2.45), # Save PDF
59
+ (ILTranslator.stage_name, 46.96), # Translate Paragraphs
60
+ (Typesetting.stage_name, 4.71), # Typesetting
61
+ (FontMapper.stage_name, 0.61), # Add Fonts
62
+ (PDFCreater.stage_name, 1.96), # Generate drawing instructions
63
+ (SUBSET_FONT_STAGE_NAME, 0.92), # Subset font
64
+ (SAVE_PDF_STAGE_NAME, 6.34), # Save PDF
65
65
  ]
66
66
 
67
67
  resfont_map = {
@@ -431,6 +431,10 @@ def do_translate(
431
431
  (x, x) for x in should_translate_pages
432
432
  ]
433
433
 
434
+ # Only first part should do scanned detection if enabled
435
+ if i > 0:
436
+ part_config.skip_scanned_detection = True
437
+
434
438
  part_config.working_dir = (
435
439
  translation_config.get_part_working_dir(i)
436
440
  )
@@ -576,14 +580,17 @@ def _do_translate_single(
576
580
  # [Previous implementation of do_translate continues here]
577
581
 
578
582
  # 检测是否为扫描文件
579
- logger.debug("start detect scanned file")
580
- DetectScannedFile(translation_config).process(docs)
581
- logger.debug("finish detect scanned file")
582
- if translation_config.debug:
583
- xml_converter.write_json(
584
- docs,
585
- translation_config.get_working_file_path("detect_scanned_file.json"),
586
- )
583
+ if translation_config.skip_scanned_detection:
584
+ logger.debug("skipping scanned file detection")
585
+ else:
586
+ logger.debug("start detect scanned file")
587
+ DetectScannedFile(translation_config).process(docs)
588
+ logger.debug("finish detect scanned file")
589
+ if translation_config.debug:
590
+ xml_converter.write_json(
591
+ docs,
592
+ translation_config.get_working_file_path("detect_scanned_file.json"),
593
+ )
587
594
 
588
595
  # Generate layouts for all pages
589
596
  logger.debug("start generating layouts")
@@ -23,7 +23,7 @@ from babeldoc.translation_config import TranslationConfig
23
23
  from babeldoc.translation_config import WatermarkOutputMode
24
24
 
25
25
  logger = logging.getLogger(__name__)
26
- __version__ = "0.2.31"
26
+ __version__ = "0.2.33"
27
27
 
28
28
 
29
29
  def create_parser():
@@ -204,6 +204,12 @@ def create_parser():
204
204
  default=False,
205
205
  help="Show character box (debug only)",
206
206
  )
207
+ translation_group.add_argument(
208
+ "--skip-scanned-detection",
209
+ action="store_true",
210
+ default=False,
211
+ help="Skip scanned document detection (speeds up processing for non-scanned documents)",
212
+ )
207
213
  # service option argument group
208
214
  service_group = translation_group.add_mutually_exclusive_group()
209
215
  service_group.add_argument(
@@ -370,6 +376,7 @@ async def main():
370
376
  split_strategy=split_strategy,
371
377
  table_model=table_model,
372
378
  show_char_box=args.show_char_box,
379
+ skip_scanned_detection=args.skip_scanned_detection,
373
380
  )
374
381
 
375
382
  # Create progress handler
@@ -0,0 +1,205 @@
1
+ import argparse
2
+ import json
3
+ import re
4
+ from pathlib import Path
5
+
6
+ import orjson
7
+ from babeldoc.const import CACHE_FOLDER
8
+
9
+ WORKING_FOLDER = Path(CACHE_FOLDER) / "working"
10
+
11
+
12
+ def find_latest_il_json() -> Path | None:
13
+ """
14
+ Find the latest il_translated.json file in ~/.cache/babeldoc/ subdirectories.
15
+
16
+ Returns:
17
+ Path to the most recently modified il_translated.json file, or None if not found.
18
+ """
19
+ base_dir = Path(WORKING_FOLDER)
20
+ json_files = list(base_dir.glob("*/il_translated.json"))
21
+
22
+ if not json_files:
23
+ return None
24
+
25
+ # Sort by modification time (newest first)
26
+ json_files.sort(key=lambda p: p.stat().st_mtime, reverse=True)
27
+ return json_files[0]
28
+
29
+
30
+ def extract_fonts_from_paragraph(
31
+ paragraph: dict, page_font_map: dict[str, tuple[str, str]]
32
+ ) -> set[tuple[str, str]]:
33
+ """
34
+ Extract all font_ids and names used in a paragraph.
35
+
36
+ Args:
37
+ paragraph: The paragraph dictionary
38
+ page_font_map: Dictionary mapping font_id to (font_id, name) tuples
39
+
40
+ Returns:
41
+ Set of (font_id, name) tuples
42
+ """
43
+ fonts = set()
44
+
45
+ # Check if paragraph has a pdfStyle with font_id
46
+ if (
47
+ "pdf_style" in paragraph
48
+ and paragraph["pdf_style"]
49
+ and "font_id" in paragraph["pdf_style"]
50
+ ):
51
+ font_id = paragraph["pdf_style"]["font_id"]
52
+ if font_id in page_font_map:
53
+ fonts.add(page_font_map[font_id])
54
+
55
+ # Process paragraph compositions if present
56
+ if "pdf_paragraph_composition" in paragraph:
57
+ for comp in paragraph["pdf_paragraph_composition"]:
58
+ # Check different composition types that might contain font information
59
+
60
+ # Direct pdfCharacter in composition
61
+ if "pdf_character" in comp and comp["pdf_character"]:
62
+ char = comp["pdf_character"]
63
+ if "pdf_style" in char and "font_id" in char["pdf_style"]:
64
+ font_id = char["pdf_style"]["font_id"]
65
+ if font_id in page_font_map:
66
+ fonts.add(page_font_map[font_id])
67
+
68
+ # PdfLine in composition
69
+ elif "pdf_line" in comp and comp["pdf_line"]:
70
+ line = comp["pdf_line"]
71
+ if "pdf_character" in line:
72
+ for char in line["pdf_character"]:
73
+ if "pdf_style" in char and "font_id" in char["pdf_style"]:
74
+ font_id = char["pdf_style"]["font_id"]
75
+ if font_id in page_font_map:
76
+ fonts.add(page_font_map[font_id])
77
+
78
+ # PdfFormula in composition
79
+ elif "pdf_formula" in comp and comp["pdf_formula"]:
80
+ formula = comp["pdf_formula"]
81
+ if "pdf_character" in formula:
82
+ for char in formula["pdf_character"]:
83
+ if "pdf_style" in char and "font_id" in char["pdf_style"]:
84
+ font_id = char["pdf_style"]["font_id"]
85
+ if font_id in page_font_map:
86
+ fonts.add(page_font_map[font_id])
87
+
88
+ # PdfSameStyleCharacters in composition
89
+ elif (
90
+ "pdf_same_style_characters" in comp
91
+ and comp["pdf_same_style_characters"]
92
+ ):
93
+ same_style = comp["pdf_same_style_characters"]
94
+ if "pdf_style" in same_style and "font_id" in same_style["pdf_style"]:
95
+ font_id = same_style["pdf_style"]["font_id"]
96
+ if font_id in page_font_map:
97
+ fonts.add(page_font_map[font_id])
98
+
99
+ # PdfSameStyleUnicodeCharacters in composition
100
+ elif (
101
+ "pdf_same_style_unicode_characters" in comp
102
+ and comp["pdf_same_style_unicode_characters"]
103
+ ):
104
+ same_style_unicode = comp["pdf_same_style_unicode_characters"]
105
+ if (
106
+ "pdf_style" in same_style_unicode
107
+ and "font_id" in same_style_unicode["pdf_style"]
108
+ ):
109
+ font_id = same_style_unicode["pdf_style"]["font_id"]
110
+ if font_id in page_font_map:
111
+ fonts.add(page_font_map[font_id])
112
+
113
+ return fonts
114
+
115
+
116
+ def find_fonts_by_debug_id(json_path: Path, debug_id_regex: str) -> dict[str, str]:
117
+ """
118
+ Find all fonts used in paragraphs with matching debug_id.
119
+
120
+ Args:
121
+ json_path: Path to the il_translated.json file
122
+ debug_id_regex: Regular expression to match debug_id values
123
+
124
+ Returns:
125
+ Dictionary mapping font_ids to font names
126
+ """
127
+ # Load and parse JSON
128
+ with json_path.open("rb") as f:
129
+ doc_data = orjson.loads(f.read())
130
+
131
+ # Compile regex pattern (case insensitive)
132
+ pattern = re.compile(debug_id_regex.strip(" \"'"), re.IGNORECASE)
133
+
134
+ # Set to collect all found font information
135
+ found_fonts = set()
136
+
137
+ # Process each page
138
+ for page in doc_data.get("page", []):
139
+ # Create a mapping of font_id to (font_id, name) tuples for this page
140
+ page_font_map = {}
141
+ for font in page.get("pdf_font", []):
142
+ if "font_id" in font and "name" in font:
143
+ page_font_map[font["font_id"]] = (font["font_id"], font["name"])
144
+
145
+ # Check each paragraph
146
+ for paragraph in page.get("pdf_paragraph", []):
147
+ # Check if paragraph has debug_id and if it matches the pattern
148
+ debug_id = paragraph.get("debug_id")
149
+ if debug_id and pattern.search(debug_id):
150
+ # Get all fonts used in this paragraph
151
+ paragraph_fonts = extract_fonts_from_paragraph(paragraph, page_font_map)
152
+ found_fonts.update(paragraph_fonts)
153
+
154
+ # Convert set of tuples to dictionary
155
+ return dict(found_fonts)
156
+
157
+
158
+ def main():
159
+ parser = argparse.ArgumentParser(
160
+ description="Extract fonts from paragraphs with matching debug_id"
161
+ )
162
+ parser.add_argument(
163
+ "debug_id_regex", nargs="+", help="Regular expression to match debug_id values"
164
+ )
165
+ parser.add_argument(
166
+ "--json-path",
167
+ help="Path to il_translated.json (if not provided, will use the latest file)",
168
+ )
169
+
170
+ args = parser.parse_args()
171
+
172
+ # Determine JSON file path
173
+ json_path = None
174
+ if args.json_path:
175
+ json_path = Path(args.json_path)
176
+ if not json_path.exists():
177
+ print(f"Error: File not found: {json_path}")
178
+ return 1
179
+ else:
180
+ json_path = find_latest_il_json()
181
+ if not json_path:
182
+ print("Error: Could not find any il_translated.json file")
183
+ return 1
184
+
185
+ print(f"Using JSON file: {json_path}")
186
+
187
+ # Find fonts matching the debug_id pattern
188
+ fonts = find_fonts_by_debug_id(json_path, "|".join(args.debug_id_regex))
189
+
190
+ # Output the results
191
+ if fonts:
192
+ print(
193
+ f"Found {len(fonts)} fonts in paragraphs matching debug_id pattern: {args.debug_id_regex}"
194
+ )
195
+ print(json.dumps(fonts, indent=2, ensure_ascii=False))
196
+ else:
197
+ print(
198
+ f"No fonts found for paragraphs matching debug_id pattern: {args.debug_id_regex}"
199
+ )
200
+
201
+ return 0
202
+
203
+
204
+ if __name__ == "__main__":
205
+ exit(main())
@@ -67,6 +67,7 @@ class TranslationConfig:
67
67
  split_strategy: BaseSplitStrategy | None = None,
68
68
  table_model=None,
69
69
  show_char_box: bool = False,
70
+ skip_scanned_detection: bool = False,
70
71
  ):
71
72
  self.translator = translator
72
73
 
@@ -97,6 +98,7 @@ class TranslationConfig:
97
98
  self.doc_layout_model = doc_layout_model
98
99
 
99
100
  self.skip_clean = skip_clean or enhance_compatibility
101
+ self.skip_scanned_detection = skip_scanned_detection
100
102
 
101
103
  self.dual_translate_first = dual_translate_first or enhance_compatibility
102
104
  self.disable_rich_text_translate = (
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "BabelDOC"
3
- version = "0.2.31"
3
+ version = "0.2.33"
4
4
  description = "Yet Another Document Translator"
5
5
  license = "AGPL-3.0"
6
6
  readme = "README.md"
@@ -148,7 +148,7 @@ pythonpath = [".", "src"]
148
148
  testpaths = ["tests"]
149
149
 
150
150
  [bumpver]
151
- current_version = "0.2.31"
151
+ current_version = "0.2.33"
152
152
  version_pattern = "MAJOR.MINOR.PATCH[.PYTAGNUM]"
153
153
 
154
154
  [bumpver.file_patterns]
@@ -48,7 +48,7 @@ wheels = [
48
48
 
49
49
  [[package]]
50
50
  name = "babeldoc"
51
- version = "0.2.31"
51
+ version = "0.2.33"
52
52
  source = { editable = "." }
53
53
  dependencies = [
54
54
  { name = "bitstring" },
@@ -1 +0,0 @@
1
- __version__ = "0.2.31"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes