BabelDOC 0.3.20__tar.gz → 0.3.22__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 (103) hide show
  1. {babeldoc-0.3.20 → babeldoc-0.3.22}/PKG-INFO +3 -1
  2. babeldoc-0.3.22/babeldoc/__init__.py +1 -0
  3. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/assets/embedding_assets_metadata.py +24 -23
  4. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/asynchronize/__init__.py +1 -1
  5. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/const.py +1 -1
  6. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/backend/pdf_creater.py +137 -0
  7. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/frontend/il_creater.py +8 -3
  8. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/paragraph_finder.py +2 -16
  9. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/styles_and_formulas.py +94 -8
  10. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/translator/translator.py +13 -6
  11. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/utils/fontmap.py +17 -1
  12. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/utils/layout_helper.py +18 -0
  13. babeldoc-0.3.22/babeldoc/format/office/__init__.py +0 -0
  14. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/high_level.py +37 -1
  15. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/main.py +1 -1
  16. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/tools/italic_assistance.py +1 -0
  17. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/tools/italic_recognize_tool.py +8 -2
  18. {babeldoc-0.3.20 → babeldoc-0.3.22}/pyproject.toml +3 -3
  19. {babeldoc-0.3.20 → babeldoc-0.3.22}/uv.lock +6 -4
  20. babeldoc-0.3.20/babeldoc/__init__.py +0 -1
  21. {babeldoc-0.3.20 → babeldoc-0.3.22}/.cursorignore +0 -0
  22. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  23. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  24. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/PULL_REQUEST_TEMPLATE/pr_form.yml +0 -0
  25. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/dependabot.yml +0 -0
  26. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/labels.yml +0 -0
  27. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/release-drafter.yml +0 -0
  28. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/workflows/codeql.yml +0 -0
  29. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/workflows/docs.yml +0 -0
  30. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/workflows/labeler.yml +0 -0
  31. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/workflows/lint.yml +0 -0
  32. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/workflows/pr-lint.yml +0 -0
  33. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/workflows/publish-to-pypi.yml +0 -0
  34. {babeldoc-0.3.20 → babeldoc-0.3.22}/.github/workflows/test.yml +0 -0
  35. {babeldoc-0.3.20 → babeldoc-0.3.22}/.gitignore +0 -0
  36. {babeldoc-0.3.20 → babeldoc-0.3.22}/.pre-commit-config.yaml +0 -0
  37. {babeldoc-0.3.20 → babeldoc-0.3.22}/LICENSE +0 -0
  38. {babeldoc-0.3.20 → babeldoc-0.3.22}/README.md +0 -0
  39. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/assets/assets.py +0 -0
  40. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/converter.py +0 -0
  41. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/__init__.py +0 -0
  42. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/babeldoc_exception/BabelDOCException.py +0 -0
  43. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/backend/__init__.py +0 -0
  44. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/frontend/__init__.py +0 -0
  45. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/il_version_1.py +0 -0
  46. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/il_version_1.rnc +0 -0
  47. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/il_version_1.rng +0 -0
  48. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/il_version_1.xsd +0 -0
  49. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/__init__.py +0 -0
  50. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/add_debug_information.py +0 -0
  51. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/detect_scanned_file.py +0 -0
  52. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/il_translator.py +0 -0
  53. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/il_translator_llm_only.py +0 -0
  54. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/layout_parser.py +0 -0
  55. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/remove_descent.py +0 -0
  56. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/table_parser.py +0 -0
  57. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/midend/typesetting.py +0 -0
  58. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/translator/__init__.py +0 -0
  59. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/translator/cache.py +0 -0
  60. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/utils/atomic_integer.py +0 -0
  61. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/utils/priority_thread_pool_executor.py +0 -0
  62. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/utils/style_helper.py +0 -0
  63. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/document_il/xml_converter.py +0 -0
  64. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/docvision/README.md +0 -0
  65. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/docvision/__init__.py +0 -0
  66. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/docvision/doclayout.py +0 -0
  67. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/docvision/rpc_doclayout.py +0 -0
  68. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/docvision/table_detection/rapidocr.py +0 -0
  69. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/pdfinterp.py +0 -0
  70. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/progress_monitor.py +0 -0
  71. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/result_merger.py +0 -0
  72. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/split_manager.py +0 -0
  73. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/tools/generate_font_metadata.py +0 -0
  74. {babeldoc-0.3.20 → babeldoc-0.3.22}/babeldoc/translation_config.py +0 -0
  75. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/CODE_OF_CONDUCT.md +0 -0
  76. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/CONTRIBUTING.md +0 -0
  77. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/CONTRIBUTOR_REWARD.md +0 -0
  78. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/ImplementationDetails/AsyncTranslate/AsyncTranslate.md +0 -0
  79. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/ImplementationDetails/ILTranslator/ILTranslator.md +0 -0
  80. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/ImplementationDetails/PDFCreation/PDFCreation.md +0 -0
  81. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/ImplementationDetails/PDFParsing/PDFParsing.md +0 -0
  82. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/ImplementationDetails/ParagraphFinding/ParagraphFinding.md +0 -0
  83. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/ImplementationDetails/README.md +0 -0
  84. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/ImplementationDetails/StylesAndFormulas/StylesAndFormulas.md +0 -0
  85. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/ImplementationDetails/Typesetting/Typesetting.md +0 -0
  86. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/README.md +0 -0
  87. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/deploy.sh +0 -0
  88. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-banner.png +0 -0
  89. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-big-logo-darkmode-with-transparent-background.png +0 -0
  90. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-big-logo-darkmode-with-transparent-background.svg +0 -0
  91. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-big-logo-with-transparent-background.png +0 -0
  92. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-big-logo-with-transparent-background.svg +0 -0
  93. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-big-logo.png +0 -0
  94. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-contributor_reward_example.png +0 -0
  95. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-preview.gif +0 -0
  96. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-small-logo-with-transparent-background.png +0 -0
  97. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-small-logo-with-transparent-background.svg +0 -0
  98. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/images/babeldoc-small-logo.png +0 -0
  99. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/index.md +0 -0
  100. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/intro-to-pdf-object.md +0 -0
  101. {babeldoc-0.3.20 → babeldoc-0.3.22}/docs/requirements.txt +0 -0
  102. {babeldoc-0.3.20 → babeldoc-0.3.22}/mkdocs.yml +0 -0
  103. {babeldoc-0.3.20 → babeldoc-0.3.22}/tests/test_translation_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: BabelDOC
3
- Version: 0.3.20
3
+ Version: 0.3.22
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
@@ -42,6 +42,8 @@ Provides-Extra: cuda
42
42
  Requires-Dist: onnxruntime-gpu>=1.16.1; extra == 'cuda'
43
43
  Provides-Extra: directml
44
44
  Requires-Dist: onnxruntime-directml>=1.16.1; extra == 'directml'
45
+ Provides-Extra: memray
46
+ Requires-Dist: memray>=1.17.1; extra == 'memray'
45
47
  Description-Content-Type: text/markdown
46
48
 
47
49
  <!-- # Yet Another Document Translator -->
@@ -0,0 +1 @@
1
+ __version__ = "0.3.22"
@@ -1,3 +1,5 @@
1
+ import itertools
2
+
1
3
  DOCLAYOUT_YOLO_DOCSTRUCTBENCH_IMGSZ1024ONNX_SHA3_256 = (
2
4
  "60be061226930524958b5465c8c04af3d7c03bcb0beb66454f5da9f792e3cf2a"
3
5
  )
@@ -495,6 +497,7 @@ EMBEDDING_FONT_METADATA = {
495
497
  },
496
498
  }
497
499
 
500
+ FONT_NAMES = {v["font_name"] for v in EMBEDDING_FONT_METADATA.values()}
498
501
 
499
502
  CN_FONT_FAMILY = {
500
503
  # 手写体
@@ -517,16 +520,12 @@ CN_FONT_FAMILY = {
517
520
  }
518
521
 
519
522
  HK_FONT_FAMILY = {
520
- "script": ["LXGWWenKaiTC-Regular.ttf", "LXGWWenKaiGB-Regular.ttf"],
523
+ "script": ["LXGWWenKaiTC-Regular.ttf"],
521
524
  "normal": [
522
525
  "SourceHanSerifHK-Bold.ttf",
523
526
  "SourceHanSerifHK-Regular.ttf",
524
527
  "SourceHanSansHK-Bold.ttf",
525
528
  "SourceHanSansHK-Regular.ttf",
526
- "SourceHanSerifCN-Bold.ttf",
527
- "SourceHanSerifCN-Regular.ttf",
528
- "SourceHanSansCN-Bold.ttf",
529
- "SourceHanSansCN-Regular.ttf",
530
529
  ],
531
530
  "fallback": [
532
531
  "GoNotoKurrent-Regular.ttf",
@@ -536,16 +535,12 @@ HK_FONT_FAMILY = {
536
535
  }
537
536
 
538
537
  TW_FONT_FAMILY = {
539
- "script": ["LXGWWenKaiTC-Regular.ttf", "LXGWWenKaiGB-Regular.ttf"],
538
+ "script": ["LXGWWenKaiTC-Regular.ttf"],
540
539
  "normal": [
541
540
  "SourceHanSerifTW-Bold.ttf",
542
541
  "SourceHanSerifTW-Regular.ttf",
543
542
  "SourceHanSansTW-Bold.ttf",
544
543
  "SourceHanSansTW-Regular.ttf",
545
- "SourceHanSerifCN-Bold.ttf",
546
- "SourceHanSerifCN-Regular.ttf",
547
- "SourceHanSansCN-Bold.ttf",
548
- "SourceHanSansCN-Regular.ttf",
549
544
  ],
550
545
  "fallback": [
551
546
  "GoNotoKurrent-Regular.ttf",
@@ -561,10 +556,6 @@ KR_FONT_FAMILY = {
561
556
  "SourceHanSerifKR-Regular.ttf",
562
557
  "SourceHanSansKR-Bold.ttf",
563
558
  "SourceHanSansKR-Regular.ttf",
564
- "SourceHanSerifCN-Bold.ttf",
565
- "SourceHanSerifCN-Regular.ttf",
566
- "SourceHanSansCN-Bold.ttf",
567
- "SourceHanSansCN-Regular.ttf",
568
559
  ],
569
560
  "fallback": [
570
561
  "GoNotoKurrent-Regular.ttf",
@@ -580,10 +571,6 @@ JP_FONT_FAMILY = {
580
571
  "SourceHanSerifJP-Regular.ttf",
581
572
  "SourceHanSansJP-Bold.ttf",
582
573
  "SourceHanSansJP-Regular.ttf",
583
- "SourceHanSerifCN-Bold.ttf",
584
- "SourceHanSerifCN-Regular.ttf",
585
- "SourceHanSansCN-Bold.ttf",
586
- "SourceHanSansCN-Regular.ttf",
587
574
  ],
588
575
  "fallback": [
589
576
  "GoNotoKurrent-Regular.ttf",
@@ -604,10 +591,6 @@ EN_FONT_FAMILY = {
604
591
  "NotoSerif-Bold.ttf",
605
592
  "NotoSans-Regular.ttf",
606
593
  "NotoSans-Bold.ttf",
607
- "SourceHanSerifCN-Bold.ttf",
608
- "SourceHanSerifCN-Regular.ttf",
609
- "SourceHanSansCN-Bold.ttf",
610
- "SourceHanSansCN-Regular.ttf",
611
594
  ],
612
595
  "fallback": [
613
596
  "GoNotoKurrent-Regular.ttf",
@@ -620,14 +603,32 @@ EN_FONT_FAMILY = {
620
603
 
621
604
  ALL_FONT_FAMILY = {
622
605
  "CN": CN_FONT_FAMILY,
623
- "HK": HK_FONT_FAMILY,
624
606
  "TW": TW_FONT_FAMILY,
607
+ "HK": HK_FONT_FAMILY,
625
608
  "KR": KR_FONT_FAMILY,
626
609
  "JP": JP_FONT_FAMILY,
627
610
  "EN": EN_FONT_FAMILY,
628
611
  }
629
612
 
630
613
 
614
+ def __add_fallback_to_font_family():
615
+ for lang1, family1 in ALL_FONT_FAMILY.items():
616
+ added_font = set()
617
+ for font in itertools.chain.from_iterable(family1.values()):
618
+ added_font.add(font)
619
+
620
+ for lang2, family2 in ALL_FONT_FAMILY.items():
621
+ if lang1 != lang2:
622
+ for type_ in family1:
623
+ for font in family2[type_]:
624
+ if font not in added_font:
625
+ family1[type_].append(font)
626
+ added_font.add(font)
627
+
628
+
629
+ __add_fallback_to_font_family()
630
+
631
+
631
632
  def get_font_family(lang_code: str):
632
633
  lang_code = lang_code.upper()
633
634
  if "KR" in lang_code:
@@ -23,7 +23,7 @@ class AsyncCallback:
23
23
  self.loop.call_soon_threadsafe(self.queue.put_nowait, args)
24
24
 
25
25
  # Add a small delay to release the GIL, ensuring the event loop has time to process messages
26
- time.sleep(0.01)
26
+ time.sleep(0.1)
27
27
 
28
28
  def finished_callback(self, *args, **kwargs):
29
29
  # Whenever a finished is called, add to the queue as with step, but also set finished to True, so __anext__
@@ -3,7 +3,7 @@ import shutil
3
3
  import subprocess
4
4
  from pathlib import Path
5
5
 
6
- __version__ = "0.3.20"
6
+ __version__ = "0.3.22"
7
7
 
8
8
  CACHE_FOLDER = Path.home() / ".cache" / "babeldoc"
9
9
 
@@ -1,13 +1,18 @@
1
+ import io
2
+ import itertools
1
3
  import logging
2
4
  import os
3
5
  import re
4
6
  import time
7
+ import unicodedata
5
8
  from multiprocessing import Process
6
9
  from pathlib import Path
7
10
 
11
+ import freetype
8
12
  import pymupdf
9
13
  from bitstring import BitStream
10
14
 
15
+ from babeldoc.assets.embedding_assets_metadata import FONT_NAMES
11
16
  from babeldoc.document_il import il_version_1
12
17
  from babeldoc.document_il.utils.fontmap import FontMapper
13
18
  from babeldoc.translation_config import TranslateResult
@@ -20,6 +25,138 @@ SUBSET_FONT_STAGE_NAME = "Subset font"
20
25
  SAVE_PDF_STAGE_NAME = "Save PDF"
21
26
 
22
27
 
28
+ def to_int(src):
29
+ return int(re.search(r"\d+", src).group(0))
30
+
31
+
32
+ def parse_mapping(text):
33
+ mapping = []
34
+ for x in re.finditer(rb"<(?P<num>[a-fA-F0-9]+)>", text):
35
+ mapping.append(int(x.group("num"), 16))
36
+ return mapping
37
+
38
+
39
+ def apply_normalization(cmap, gid, code):
40
+ need = False
41
+ if 0x2F00 <= code <= 0x2FD5: # Kangxi Radicals
42
+ need = True
43
+ if 0xF900 <= code <= 0xFAFF: # CJK Compatibility Ideographs
44
+ need = True
45
+ if need:
46
+ norm = unicodedata.normalize("NFD", chr(code))
47
+ cmap[gid] = ord(norm)
48
+ else:
49
+ cmap[gid] = code
50
+
51
+
52
+ def batched(iterable, n, *, strict=False):
53
+ # batched('ABCDEFG', 3) → ABC DEF G
54
+ if n < 1:
55
+ raise ValueError("n must be at least one")
56
+ iterator = iter(iterable)
57
+ while batch := tuple(itertools.islice(iterator, n)):
58
+ if strict and len(batch) != n:
59
+ raise ValueError("batched(): incomplete batch")
60
+ yield batch
61
+
62
+
63
+ def update_tounicode_cmap_pair(cmap, data):
64
+ for start, stop, value in batched(data, 3):
65
+ for gid in range(start, stop + 1):
66
+ code = value + gid - start
67
+ apply_normalization(cmap, gid, code)
68
+
69
+
70
+ def update_tounicode_cmap_code(cmap, data):
71
+ for gid, code in batched(data, 2):
72
+ apply_normalization(cmap, gid, code)
73
+
74
+
75
+ def parse_tounicode_cmap(data):
76
+ cmap = {}
77
+ for x in re.finditer(
78
+ rb"\s+beginbfrange\s*(?P<r>(<[0-9a-fA-F]+>\s*)+)endbfrange\s+", data
79
+ ):
80
+ update_tounicode_cmap_pair(cmap, parse_mapping(x.group("r")))
81
+ for x in re.finditer(
82
+ rb"\s+beginbfchar\s*(?P<c>(<[0-9a-fA-F]+>\s*)+)endbfchar", data
83
+ ):
84
+ update_tounicode_cmap_code(cmap, parse_mapping(x.group("c")))
85
+ return cmap
86
+
87
+
88
+ def parse_truetype_data(data):
89
+ glyph_in_use = []
90
+ face = freetype.Face(io.BytesIO(data))
91
+ for i in range(face.num_glyphs):
92
+ face.load_glyph(i)
93
+ if face.glyph.outline.contours:
94
+ glyph_in_use.append(i)
95
+ return glyph_in_use
96
+
97
+
98
+ TOUNICODE_HEAD = """\
99
+ /CIDInit /ProcSet findresource begin
100
+ 12 dict begin
101
+ /CIDSystemInfo <</Registry(Adobe)/Ordering(UCS)/Supplement 0>> def
102
+ /CMapName /Adobe-Identity-UCS def
103
+ /CMapType 2 def
104
+ 1 begincodespacerange
105
+ <0000> <FFFF>
106
+ endcodespacerange"""
107
+ TOUNICODE_TAIL = """\
108
+ endcmap
109
+ CMapName currentdict /CMap defineresource pop
110
+ end
111
+ end"""
112
+
113
+
114
+ def make_tounicode(cmap, used):
115
+ short = []
116
+ for x in used:
117
+ if x in cmap:
118
+ short.append((x, cmap[x]))
119
+ line = [TOUNICODE_HEAD]
120
+ for block in batched(short, 100):
121
+ line.append(f"{len(block)} beginbfchar")
122
+ for glyph, code in block:
123
+ if code < 0x10000:
124
+ line.append(f"<{glyph:04x}><{code:04x}>")
125
+ else:
126
+ line.append(f"<{glyph:04x}><{code:08x}>")
127
+ line.append("endbfchar")
128
+ line.append(TOUNICODE_TAIL)
129
+ return "\n".join(line)
130
+
131
+
132
+ def reproduce_one_font(doc, index):
133
+ m = doc.xref_get_key(index, "ToUnicode")
134
+ f = doc.xref_get_key(index, "DescendantFonts")
135
+ if m[0] == "xref" and f[0] == "array":
136
+ mi = to_int(m[1])
137
+ fi = to_int(f[1])
138
+ ff = doc.xref_get_key(fi, "FontDescriptor/FontFile2")
139
+ ms = doc.xref_stream(mi)
140
+ fs = doc.xref_stream(to_int(ff[1]))
141
+ cmap = parse_tounicode_cmap(ms)
142
+ used = parse_truetype_data(fs)
143
+ text = make_tounicode(cmap, used)
144
+ doc.update_stream(mi, bytes(text, "U8"))
145
+
146
+
147
+ def reproduce_cmap(doc):
148
+ assert doc
149
+ font_set = set()
150
+ for page in doc:
151
+ font_list = page.get_fonts()
152
+ for font in font_list:
153
+ if font[1] == "ttf" and font[3] in FONT_NAMES and ".ttf" in font[4]:
154
+ font_set.add(font)
155
+ for font in font_set:
156
+ reproduce_one_font(doc, font[0])
157
+ return doc
158
+
159
+
23
160
  def _subset_fonts_process(pdf_path, output_path):
24
161
  """Function to run in subprocess for font subsetting.
25
162
 
@@ -49,8 +49,11 @@ def create_hook(func, hook):
49
49
 
50
50
  def hook_pdfminer_pdf_page_init(*args):
51
51
  attrs = args[3]
52
- while isinstance(attrs["MediaBox"], PDFMinerPDFObjRef):
53
- attrs["MediaBox"] = pdftypes_resolve1(attrs["MediaBox"])
52
+ try:
53
+ while isinstance(attrs["MediaBox"], PDFMinerPDFObjRef):
54
+ attrs["MediaBox"] = pdftypes_resolve1(attrs["MediaBox"])
55
+ except Exception:
56
+ logger.exception(f"try to fix mediabox failed: {attrs}")
54
57
 
55
58
 
56
59
  PDFMinerPDFPage.__init__ = create_hook(
@@ -343,6 +346,7 @@ def parse_font_file(doc, idx, encoding, differences):
343
346
  bbox_list = []
344
347
  data = doc.xref_stream(idx)
345
348
  face = freetype.Face(BytesIO(data))
349
+ scale = 1000 / face.units_per_EM
346
350
  for charmap in face.charmaps:
347
351
  if charmap.encoding_name == "FT_ENCODING_ADOBE_CUSTOM":
348
352
  face.select_charmap(freetype.FT_ENCODING_ADOBE_CUSTOM)
@@ -351,7 +355,8 @@ def parse_font_file(doc, idx, encoding, differences):
351
355
  if differences:
352
356
  for code, name in differences:
353
357
  bbox_list[code] = get_name_cbox(face, name.encode("U8"))
354
- return bbox_list
358
+ norm_bbox_list = [[v * scale for v in box] for box in bbox_list]
359
+ return norm_bbox_list
355
360
 
356
361
 
357
362
  def parse_encoding(obj_str):
@@ -12,6 +12,7 @@ from babeldoc.document_il import PdfRectangle
12
12
  from babeldoc.document_il.utils.layout_helper import Layout
13
13
  from babeldoc.document_il.utils.layout_helper import add_space_dummy_chars
14
14
  from babeldoc.document_il.utils.layout_helper import get_char_unicode_string
15
+ from babeldoc.document_il.utils.layout_helper import is_bullet_point
15
16
  from babeldoc.document_il.utils.style_helper import WHITE
16
17
  from babeldoc.translation_config import TranslationConfig
17
18
 
@@ -30,9 +31,6 @@ class ParagraphFinder:
30
31
  stage_name = "Parse Paragraphs"
31
32
 
32
33
  # 定义项目符号的正则表达式模式
33
- BULLET_POINT_PATTERN = re.compile(
34
- r"[■•⚫⬤◆◇○●◦‣⁃▪▫∗†‡¹²³⁴⁵⁶⁷⁸⁹⁰₁₂₃₄₅₆₇₈₉₀ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖᵍʳˢᵗᵘᵛʷˣʸᶻ†‡§¶※⁑⁂⁕⁎⁜⁑❧☙⁋‖‽]"
35
- )
36
34
 
37
35
  def __init__(self, translation_config: TranslationConfig):
38
36
  self.translation_config = translation_config
@@ -246,7 +244,7 @@ class ParagraphFinder:
246
244
  and current_line_chars[-1].xobj_id != char.xobj_id
247
245
  )
248
246
  or (
249
- self.is_bullet_point(char) # 如果是项目符号,开启新段落
247
+ is_bullet_point(char) # 如果是项目符号,开启新段落
250
248
  and not current_line_chars
251
249
  )
252
250
  ):
@@ -512,15 +510,3 @@ class ParagraphFinder:
512
510
  break
513
511
  j += 1
514
512
  i += 1
515
-
516
- def is_bullet_point(self, char: PdfCharacter) -> bool:
517
- """Check if the character is a bullet point.
518
-
519
- Args:
520
- char: The character to check
521
-
522
- Returns:
523
- bool: True if the character is a bullet point
524
- """
525
- is_bullet = bool(self.BULLET_POINT_PATTERN.match(char.char_unicode))
526
- return is_bullet
@@ -17,6 +17,7 @@ from babeldoc.document_il.utils.fontmap import FontMapper
17
17
  from babeldoc.document_il.utils.layout_helper import LEFT_BRACKET
18
18
  from babeldoc.document_il.utils.layout_helper import RIGHT_BRACKET
19
19
  from babeldoc.document_il.utils.layout_helper import formular_height_ignore_char
20
+ from babeldoc.document_il.utils.layout_helper import is_bullet_point
20
21
  from babeldoc.document_il.utils.layout_helper import is_same_style
21
22
  from babeldoc.translation_config import TranslationConfig
22
23
 
@@ -70,6 +71,7 @@ class StylesAndFormulas:
70
71
  continue
71
72
 
72
73
  new_compositions = []
74
+ first_is_bullet = False
73
75
 
74
76
  for composition in paragraph.pdf_paragraph_composition:
75
77
  current_chars = []
@@ -81,6 +83,8 @@ class StylesAndFormulas:
81
83
  new_compositions.append(composition)
82
84
  continue
83
85
  for char in line.pdf_character:
86
+ if not current_chars and is_bullet_point(char):
87
+ first_is_bullet = True
84
88
  is_formula = (
85
89
  ( # 区分公式开头的字符&公式中间的字符。主要是逗号不能在公式开头,但是可以在中间。
86
90
  (
@@ -112,6 +116,7 @@ class StylesAndFormulas:
112
116
  is_corner_mark = (
113
117
  len(current_chars) > 0
114
118
  and not isspace
119
+ and not first_is_bullet
115
120
  # 角标字体,有 0.76 的角标和 0.799 的大写,这里用 0.79 取中,同时考虑首字母放大的情况
116
121
  and char.pdf_style.font_size
117
122
  < current_chars[-1].pdf_style.font_size * 0.79
@@ -119,6 +124,7 @@ class StylesAndFormulas:
119
124
  ) or (
120
125
  len(current_chars) > 0
121
126
  and not isspace
127
+ and not first_is_bullet
122
128
  # 角标字体,有 0.76 的角标和 0.799 的大写,这里用 0.79 取中,同时考虑首字母放大的情况
123
129
  and char.pdf_style.font_size
124
130
  < current_chars[-1].pdf_style.font_size * 1.1
@@ -520,7 +526,7 @@ class StylesAndFormulas:
520
526
  return bool(re.match(r"^[0-9, ]+$", text))
521
527
 
522
528
  def is_formulas_font(self, font_name: str) -> bool:
523
- pattern2 = (
529
+ pattern_text = (
524
530
  r"^("
525
531
  r"|Cambria.*"
526
532
  r"|EUAlbertina.+"
@@ -570,12 +576,90 @@ class StylesAndFormulas:
570
576
  r"|.*CronosPro.*"
571
577
  r"|.*ACaslon.*"
572
578
  r"|.*Frutiger.*"
579
+ r"|.*BrandonGrotesque.*"
580
+ r"|.*FairfieldLH.*"
581
+ r"|.*CaeciliaLTStd.*"
582
+ r"|.*Whitney.*"
583
+ r"|.*Mercury.*"
584
+ r"|.*SabonLTStd.*"
585
+ r"|.*AnonymousPro.*"
586
+ r"|.*SabonLTPro.*"
587
+ r"|.*ArnoPro.*"
588
+ r"|.*CharisSIL.*"
589
+ r")$"
590
+ )
591
+ precise_formula_font_pattern = (
592
+ r"^("
593
+ r"|.*CambriaMath.*"
594
+ r"|.*Cambria Math.*"
595
+ r"|.*Asana.*"
596
+ r"|.*MiriamMonoCLM-BookOblique.*"
597
+ r"|.*Miriam Mono CLM.*"
598
+ r"|.*Logix.*"
599
+ r"|.*AeBonum.*"
600
+ r"|.*AeMRoman.*"
601
+ r"|.*AePagella.*"
602
+ r"|.*AeSchola.*"
603
+ r"|.*Concrete.*"
604
+ r"|.*LatinModernMathCompanion.*"
605
+ r"|.*Latin Modern Math Companion.*"
606
+ r"|.*RalphSmithsFormalScriptCompanion.*"
607
+ r"|.*Ralph Smiths Formal Script Companion.*"
608
+ r"|.*TeXGyreBonumMathCompanion.*"
609
+ r"|.*TeX Gyre Bonum Companion.*"
610
+ r"|.*TeXGyrePagellaMathCompanion.*"
611
+ r"|.*TeX Gyre Pagella Math Companion.*"
612
+ r"|.*TeXGyreTermesMathCompanion.*"
613
+ r"|.*TeX Gyre Termes Math Companion.*"
614
+ r"|.*XITSMathCompanion.*"
615
+ r"|.*XITS Math Companion.*"
616
+ r"|.*Erewhon.*"
617
+ r"|.*Euler-Math.*"
618
+ r"|.*Euler Math.*"
619
+ r"|.*FiraMath-Regular.*"
620
+ r"|.*Fira Math.*"
621
+ r"|.*Garamond-Math.*"
622
+ r"|.*GFSNeohellenicMath.*"
623
+ r"|.*KpMath.*"
624
+ r"|.*Lete Sans Math.*"
625
+ r"|.*LeteSansMath.*"
626
+ r"|.*LinLibertineO.*"
627
+ r"|.*Linux Libertine O.*"
628
+ r"|.*LibertinusMath-Regular.*"
629
+ r"|.*Libertinus Math.*"
630
+ r"|.*LatinModernMath-Regular.*"
631
+ r"|.*Latin Modern Math.*"
632
+ r"|.*Luciole.*"
633
+ r"|.*NewCM.*"
634
+ r"|.*NewComputerModern.*"
635
+ r"|.*OldStandard-Math.*"
636
+ r"|.*STIXMath-Regular.*"
637
+ r"|.*STIX Math.*"
638
+ r"|.*STIXTwoMath-Regular.*"
639
+ r"|.*STIX Two Math.*"
640
+ r"|.*TeXGyreBonumMath.*"
641
+ r"|.*TeX Gyre Bonum Math.*"
642
+ r"|.*TeXGyreDejaVuMath.*"
643
+ r"|.*TeX Gyre DejaVu Math.*"
644
+ r"|.*TeXGyrePagellaMath.*"
645
+ r"|.*TeX Gyre Pagella Math.*"
646
+ r"|.*TeXGyreScholaMath.*"
647
+ r"|.*TeX Gyre Schola Math.*"
648
+ r"|.*TeXGyreTermesMath.*"
649
+ r"|.*TeX Gyre Termes Math.*"
650
+ r"|.*XCharter-Math.*"
651
+ r"|.*XCharter Math.*"
652
+ r"|.*XITSMath-Bold.*"
653
+ r"|.*XITS Math.*"
654
+ r"|.*XITSMath.*"
655
+ r"|.*IBMPlexMath.*"
656
+ r"|.*IBM Plex Math.*"
573
657
  r")$"
574
658
  )
575
659
  if self.translation_config.formular_font_pattern:
576
- pattern = self.translation_config.formular_font_pattern
660
+ broad_formula_font_pattern = self.translation_config.formular_font_pattern
577
661
  else:
578
- pattern = (
662
+ broad_formula_font_pattern = (
579
663
  r"(CM[^RB]"
580
664
  r"|(MS|XY|MT|BL|RM|EU|LA|RS)[A-Z]"
581
665
  r"|LINE"
@@ -599,14 +683,16 @@ class StylesAndFormulas:
599
683
  if font_name.startswith("BASE64:"):
600
684
  font_name_bytes = base64.b64decode(font_name[7:])
601
685
  font = font_name_bytes.split(b"+")[-1]
602
- pattern2 = pattern2.encode()
603
- pattern = pattern.encode()
686
+ pattern_text = pattern_text.encode()
687
+ broad_formula_font_pattern = broad_formula_font_pattern.encode()
604
688
  else:
605
689
  font = font_name.split("+")[-1]
606
690
 
607
- if re.match(pattern2, font):
691
+ if re.match(precise_formula_font_pattern, font):
692
+ return True
693
+ elif re.match(pattern_text, font):
608
694
  return False
609
- if re.match(pattern, font):
695
+ elif re.match(broad_formula_font_pattern, font):
610
696
  return True
611
697
 
612
698
  return False
@@ -626,7 +712,7 @@ class StylesAndFormulas:
626
712
  and (
627
713
  unicodedata.category(char[0])
628
714
  in [
629
- "Lm",
715
+ # "Lm",
630
716
  "Mn",
631
717
  "Sk",
632
718
  "Sm",
@@ -215,9 +215,7 @@ class OpenAITranslator(BaseTranslator):
215
215
  **self.options,
216
216
  messages=self.prompt(text),
217
217
  )
218
- self.token_count.inc(response.usage.total_tokens)
219
- self.prompt_token_count.inc(response.usage.prompt_tokens)
220
- self.completion_token_count.inc(response.usage.completion_tokens)
218
+ self.update_token_count(response)
221
219
  return response.choices[0].message.content.strip()
222
220
 
223
221
  def prompt(self, text):
@@ -255,11 +253,20 @@ class OpenAITranslator(BaseTranslator):
255
253
  },
256
254
  ],
257
255
  )
258
- self.token_count.inc(response.usage.total_tokens)
259
- self.prompt_token_count.inc(response.usage.prompt_tokens)
260
- self.completion_token_count.inc(response.usage.completion_tokens)
256
+ self.update_token_count(response)
261
257
  return response.choices[0].message.content.strip()
262
258
 
259
+ def update_token_count(self, response):
260
+ try:
261
+ if response.usage and response.usage.total_tokens:
262
+ self.token_count.inc(response.usage.total_tokens)
263
+ if response.usage and response.usage.prompt_tokens:
264
+ self.prompt_token_count.inc(response.usage.prompt_tokens)
265
+ if response.usage and response.usage.completion_tokens:
266
+ self.completion_token_count.inc(response.usage.completion_tokens)
267
+ except Exception as e:
268
+ logger.exception("Error updating token count")
269
+
263
270
  def get_formular_placeholder(self, placeholder_id: int):
264
271
  return "{{v" + str(placeholder_id) + "}}"
265
272
  return "{{" + str(placeholder_id) + "}}"
@@ -174,8 +174,24 @@ class FontMapper:
174
174
  )
175
175
  return None
176
176
 
177
+ def get_used_font_ids(self, il: il_version_1.Document) -> set[str]:
178
+ result = set()
179
+ for page in il.page:
180
+ for char in page.pdf_character:
181
+ if char.pdf_style and char.pdf_style.font_id:
182
+ result.add(char.pdf_style.font_id)
183
+ for para in page.pdf_paragraph:
184
+ for comp in para.pdf_paragraph_composition:
185
+ if char := comp.pdf_character:
186
+ if char.pdf_style and char.pdf_style.font_id:
187
+ result.add(char.pdf_style.font_id)
188
+ return result
189
+
177
190
  def add_font(self, doc_zh: pymupdf.Document, il: il_version_1.Document):
178
- font_list = [(k, v) for k, v in self.fontid2fontpath.items()]
191
+ used_font_ids = self.get_used_font_ids(il)
192
+ font_list = [
193
+ (k, v) for k, v in self.fontid2fontpath.items() if k in used_font_ids
194
+ ]
179
195
 
180
196
  font_id = {}
181
197
  xreflen = doc_zh.xref_length()
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  import math
3
+ import re
3
4
 
4
5
  from babeldoc.document_il import GraphicState
5
6
  from babeldoc.document_il import il_version_1
@@ -37,6 +38,23 @@ HEIGHT_NOT_USFUL_CHAR_IN_CHAR = (
37
38
  LEFT_BRACKET = ("(cid:8)", "(", "(cid:16)", "{", "[", "(cid:104)", "(cid:2)")
38
39
  RIGHT_BRACKET = ("(cid:9)", ")", "(cid:17)", "}", "]", "(cid:105)", "(cid:3)")
39
40
 
41
+ BULLET_POINT_PATTERN = re.compile(
42
+ r"[■•⚫⬤◆◇○●◦‣⁃▪▫∗†‡¹²³⁴⁵⁶⁷⁸⁹⁰₁₂₃₄₅₆₇₈₉₀ᵃᵇᶜᵈᵉᶠᵍʰⁱʲᵏˡᵐⁿᵒᵖᵍʳˢᵗᵘᵛʷˣʸᶻ†‡§¶※⁑⁂⁕⁎⁜⁑❧☙⁋‖‽]"
43
+ )
44
+
45
+
46
+ def is_bullet_point(char: PdfCharacter) -> bool:
47
+ """Check if the character is a bullet point.
48
+
49
+ Args:
50
+ char: The character to check
51
+
52
+ Returns:
53
+ bool: True if the character is a bullet point
54
+ """
55
+ is_bullet = bool(BULLET_POINT_PATTERN.match(char.char_unicode))
56
+ return is_bullet
57
+
40
58
 
41
59
  def formular_height_ignore_char(char: PdfCharacter):
42
60
  return (
File without changes
@@ -4,6 +4,7 @@ import hashlib
4
4
  import io
5
5
  import logging
6
6
  import pathlib
7
+ import shutil
7
8
  import threading
8
9
  import time
9
10
  from asyncio import CancelledError
@@ -11,6 +12,7 @@ from pathlib import Path
11
12
  from typing import Any
12
13
  from typing import BinaryIO
13
14
 
15
+ import pymupdf
14
16
  from pdfminer.pdfdocument import PDFDocument
15
17
  from pdfminer.pdfinterp import PDFResourceManager
16
18
  from pdfminer.pdfpage import PDFPage
@@ -26,6 +28,7 @@ from babeldoc.document_il import il_version_1
26
28
  from babeldoc.document_il.backend.pdf_creater import SAVE_PDF_STAGE_NAME
27
29
  from babeldoc.document_il.backend.pdf_creater import SUBSET_FONT_STAGE_NAME
28
30
  from babeldoc.document_il.backend.pdf_creater import PDFCreater
31
+ from babeldoc.document_il.backend.pdf_creater import reproduce_cmap
29
32
  from babeldoc.document_il.frontend.il_creater import ILCreater
30
33
  from babeldoc.document_il.midend.add_debug_information import AddDebugInformation
31
34
  from babeldoc.document_il.midend.detect_scanned_file import DetectScannedFile
@@ -75,6 +78,26 @@ resfont_map = {
75
78
  }
76
79
 
77
80
 
81
+ def fix_cmap(translate_result: TranslateResult, translate_config: TranslationConfig):
82
+ processed = []
83
+ for attr in (
84
+ "mono_pdf_path",
85
+ "dual_pdf_path",
86
+ "no_watermark_mono_pdf_path",
87
+ "no_watermark_dual_pdf_path",
88
+ ):
89
+ path = getattr(translate_result, attr)
90
+ if path in processed:
91
+ continue
92
+ processed.append(path)
93
+
94
+ temp_path = translate_config.get_working_file_path(f"{path.stem}.cmap.pdf")
95
+ pdf = pymupdf.open(path)
96
+ reproduce_cmap(pdf)
97
+ pdf.save(temp_path)
98
+ shutil.move(temp_path, path)
99
+
100
+
78
101
  def verify_file_hash(file_path: str, expected_hash: str) -> bool:
79
102
  """Verify the SHA256 hash of a file."""
80
103
  sha256_hash = hashlib.sha256()
@@ -514,11 +537,18 @@ def do_translate(
514
537
  )
515
538
  result.original_pdf_path = translation_config.input_file
516
539
  result.peak_memory_usage = peak_memory_usage
540
+
541
+ # should fix macOS preview compatibility
542
+ # Although the issue of Windows Edge
543
+ # not being able to copy translated text can be fixed,
544
+ # the macOS preview is broken
545
+ # fix_cmap(result, translation_config)
517
546
  pm.translate_done(result)
518
547
  return result
519
548
 
520
549
  except Exception as e:
521
550
  logger.exception(f"translate error: {e}")
551
+ pm.disable = False
522
552
  pm.translate_error(e)
523
553
  raise
524
554
  finally:
@@ -530,10 +560,16 @@ def do_translate(
530
560
  def fix_media_box(doc: Document) -> None:
531
561
  mediabox_data = {}
532
562
  for page in doc:
563
+ mediabox = doc.xref_get_key(page.xref, "MediaBox")
564
+
565
+ # Some PDF pages do not have a mediabox
566
+ if mediabox[0] == "null":
567
+ mediabox = ("array", "[0 0 612 792]")
568
+ doc.xref_set_key(page.xref, "MediaBox", mediabox[1])
533
569
  if page.mediabox.x0 != 0 or page.mediabox.y0 != 0:
534
570
  x1 = page.mediabox.x1
535
571
  y1 = page.mediabox.y1
536
- mediabox_data[page.number] = doc.xref_get_key(page.xref, "MediaBox")
572
+ mediabox_data[page.number] = mediabox
537
573
  doc.xref_set_key(page.xref, "MediaBox", f"[0 0 {x1} {y1}]")
538
574
  return mediabox_data
539
575
 
@@ -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.3.20"
26
+ __version__ = "0.3.22"
27
27
 
28
28
 
29
29
  def create_parser():
@@ -104,6 +104,7 @@ def extract_fonts_from_paragraph(
104
104
  same_style_unicode = comp["pdf_same_style_unicode_characters"]
105
105
  if (
106
106
  "pdf_style" in same_style_unicode
107
+ and same_style_unicode["pdf_style"] is not None
107
108
  and "font_id" in same_style_unicode["pdf_style"]
108
109
  ):
109
110
  font_id = same_style_unicode["pdf_style"]["font_id"]
@@ -72,8 +72,14 @@ for each_font in fonts:
72
72
  font_name,
73
73
  "[bold red]Formula Font[/bold red]",
74
74
  )
75
- # else:
76
- # table.add_row(str(page_index), font_name, "[bold blue]Non-Formula Font[/bold blue]")
75
+ else:
76
+ table.add_row(
77
+ str(page_index),
78
+ str(paragraph_index),
79
+ str(font_debug_id),
80
+ font_name,
81
+ "[bold blue]Non-Formula Font[/bold blue]",
82
+ )
77
83
 
78
84
  # Print table
79
85
  console.print(table)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "BabelDOC"
3
- version = "0.3.20"
3
+ version = "0.3.22"
4
4
  description = "Yet Another Document Translator"
5
5
  license = "AGPL-3.0"
6
6
  readme = "README.md"
@@ -48,6 +48,7 @@ dependencies = [
48
48
  [project.optional-dependencies]
49
49
  directml = ["onnxruntime-directml>=1.16.1"]
50
50
  cuda = ["onnxruntime-gpu>=1.16.1"]
51
+ memray = ["memray>=1.17.1"]
51
52
 
52
53
  [project.urls]
53
54
  Homepage = "https://github.com/funstory-ai/BabelDOC"
@@ -141,7 +142,6 @@ dev = [
141
142
  "pygments>=2.19.1",
142
143
  "ruff>=0.9.2",
143
144
  "pytest>=8.3.4",
144
- "memray>=1.17.1",
145
145
  ]
146
146
 
147
147
  [tool.pytest.ini_options]
@@ -149,7 +149,7 @@ pythonpath = [".", "src"]
149
149
  testpaths = ["tests"]
150
150
 
151
151
  [bumpver]
152
- current_version = "0.3.20"
152
+ current_version = "0.3.22"
153
153
  version_pattern = "MAJOR.MINOR.PATCH[.PYTAGNUM]"
154
154
 
155
155
  [bumpver.file_patterns]
@@ -48,7 +48,7 @@ wheels = [
48
48
 
49
49
  [[package]]
50
50
  name = "babeldoc"
51
- version = "0.3.20"
51
+ version = "0.3.22"
52
52
  source = { editable = "." }
53
53
  dependencies = [
54
54
  { name = "bitstring" },
@@ -86,13 +86,15 @@ cuda = [
86
86
  directml = [
87
87
  { name = "onnxruntime-directml" },
88
88
  ]
89
+ memray = [
90
+ { name = "memray" },
91
+ ]
89
92
 
90
93
  [package.dev-dependencies]
91
94
  dev = [
92
95
  { name = "bumpver" },
93
96
  { name = "markdown-callouts" },
94
97
  { name = "markdown-include" },
95
- { name = "memray" },
96
98
  { name = "mkdocs-git-authors-plugin" },
97
99
  { name = "mkdocs-git-committers-plugin-2" },
98
100
  { name = "mkdocs-git-revision-date-localized-plugin" },
@@ -110,6 +112,7 @@ requires-dist = [
110
112
  { name = "freetype-py", specifier = ">=2.5.1" },
111
113
  { name = "httpx", extras = ["socks"], specifier = ">=0.27.0" },
112
114
  { name = "huggingface-hub", specifier = ">=0.27.0" },
115
+ { name = "memray", marker = "extra == 'memray'", specifier = ">=1.17.1" },
113
116
  { name = "msgpack", specifier = ">=1.1.0" },
114
117
  { name = "numpy", specifier = ">=2.0.2" },
115
118
  { name = "onnx", specifier = ">=1.17.0" },
@@ -134,14 +137,13 @@ requires-dist = [
134
137
  { name = "tqdm", specifier = ">=4.67.1" },
135
138
  { name = "xsdata", extras = ["cli", "lxml", "soap"], specifier = ">=24.12" },
136
139
  ]
137
- provides-extras = ["directml", "cuda"]
140
+ provides-extras = ["directml", "cuda", "memray"]
138
141
 
139
142
  [package.metadata.requires-dev]
140
143
  dev = [
141
144
  { name = "bumpver", specifier = ">=2024.1130" },
142
145
  { name = "markdown-callouts", specifier = ">=0.4.0" },
143
146
  { name = "markdown-include", specifier = ">=0.8.1" },
144
- { name = "memray", specifier = ">=1.17.1" },
145
147
  { name = "mkdocs-git-authors-plugin", specifier = ">=0.9.2" },
146
148
  { name = "mkdocs-git-committers-plugin-2", specifier = ">=2.5.0" },
147
149
  { name = "mkdocs-git-revision-date-localized-plugin", specifier = ">=1.3.0" },
@@ -1 +0,0 @@
1
- __version__ = "0.3.20"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes