BabelDOC 0.3.23__tar.gz → 0.3.25__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.23 → babeldoc-0.3.25}/PKG-INFO +1 -1
  2. babeldoc-0.3.25/babeldoc/__init__.py +1 -0
  3. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/const.py +1 -1
  4. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/backend/pdf_creater.py +11 -3
  5. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/paragraph_finder.py +104 -0
  6. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/typesetting.py +6 -4
  7. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/main.py +1 -1
  8. {babeldoc-0.3.23 → babeldoc-0.3.25}/pyproject.toml +2 -2
  9. {babeldoc-0.3.23 → babeldoc-0.3.25}/uv.lock +1 -1
  10. babeldoc-0.3.23/babeldoc/__init__.py +0 -1
  11. {babeldoc-0.3.23 → babeldoc-0.3.25}/.cursorignore +0 -0
  12. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  13. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  14. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/PULL_REQUEST_TEMPLATE/pr_form.yml +0 -0
  15. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/dependabot.yml +0 -0
  16. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/labels.yml +0 -0
  17. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/release-drafter.yml +0 -0
  18. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/workflows/codeql.yml +0 -0
  19. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/workflows/docs.yml +0 -0
  20. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/workflows/labeler.yml +0 -0
  21. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/workflows/lint.yml +0 -0
  22. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/workflows/pr-lint.yml +0 -0
  23. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/workflows/publish-to-pypi.yml +0 -0
  24. {babeldoc-0.3.23 → babeldoc-0.3.25}/.github/workflows/test.yml +0 -0
  25. {babeldoc-0.3.23 → babeldoc-0.3.25}/.gitignore +0 -0
  26. {babeldoc-0.3.23 → babeldoc-0.3.25}/.pre-commit-config.yaml +0 -0
  27. {babeldoc-0.3.23 → babeldoc-0.3.25}/LICENSE +0 -0
  28. {babeldoc-0.3.23 → babeldoc-0.3.25}/README.md +0 -0
  29. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/assets/assets.py +0 -0
  30. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/assets/embedding_assets_metadata.py +0 -0
  31. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/asynchronize/__init__.py +0 -0
  32. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/converter.py +0 -0
  33. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/__init__.py +0 -0
  34. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/babeldoc_exception/BabelDOCException.py +0 -0
  35. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/backend/__init__.py +0 -0
  36. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/frontend/__init__.py +0 -0
  37. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/frontend/il_creater.py +0 -0
  38. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/il_version_1.py +0 -0
  39. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/il_version_1.rnc +0 -0
  40. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/il_version_1.rng +0 -0
  41. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/il_version_1.xsd +0 -0
  42. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/__init__.py +0 -0
  43. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/add_debug_information.py +0 -0
  44. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/detect_scanned_file.py +0 -0
  45. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/il_translator.py +0 -0
  46. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/il_translator_llm_only.py +0 -0
  47. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/layout_parser.py +0 -0
  48. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/remove_descent.py +0 -0
  49. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/styles_and_formulas.py +0 -0
  50. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/midend/table_parser.py +0 -0
  51. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/translator/__init__.py +0 -0
  52. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/translator/cache.py +0 -0
  53. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/translator/translator.py +0 -0
  54. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/utils/atomic_integer.py +0 -0
  55. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/utils/fontmap.py +0 -0
  56. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/utils/layout_helper.py +0 -0
  57. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/utils/priority_thread_pool_executor.py +0 -0
  58. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/utils/style_helper.py +0 -0
  59. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/document_il/xml_converter.py +0 -0
  60. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/docvision/README.md +0 -0
  61. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/docvision/__init__.py +0 -0
  62. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/docvision/doclayout.py +0 -0
  63. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/docvision/rpc_doclayout.py +0 -0
  64. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/docvision/table_detection/rapidocr.py +0 -0
  65. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/format/office/__init__.py +0 -0
  66. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/high_level.py +0 -0
  67. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/pdfinterp.py +0 -0
  68. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/progress_monitor.py +0 -0
  69. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/result_merger.py +0 -0
  70. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/split_manager.py +0 -0
  71. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/tools/generate_font_metadata.py +0 -0
  72. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/tools/italic_assistance.py +0 -0
  73. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/tools/italic_recognize_tool.py +0 -0
  74. {babeldoc-0.3.23 → babeldoc-0.3.25}/babeldoc/translation_config.py +0 -0
  75. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/CODE_OF_CONDUCT.md +0 -0
  76. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/CONTRIBUTING.md +0 -0
  77. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/CONTRIBUTOR_REWARD.md +0 -0
  78. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/ImplementationDetails/AsyncTranslate/AsyncTranslate.md +0 -0
  79. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/ImplementationDetails/ILTranslator/ILTranslator.md +0 -0
  80. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/ImplementationDetails/PDFCreation/PDFCreation.md +0 -0
  81. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/ImplementationDetails/PDFParsing/PDFParsing.md +0 -0
  82. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/ImplementationDetails/ParagraphFinding/ParagraphFinding.md +0 -0
  83. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/ImplementationDetails/README.md +0 -0
  84. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/ImplementationDetails/StylesAndFormulas/StylesAndFormulas.md +0 -0
  85. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/ImplementationDetails/Typesetting/Typesetting.md +0 -0
  86. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/README.md +0 -0
  87. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/deploy.sh +0 -0
  88. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-banner.png +0 -0
  89. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-big-logo-darkmode-with-transparent-background.png +0 -0
  90. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-big-logo-darkmode-with-transparent-background.svg +0 -0
  91. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-big-logo-with-transparent-background.png +0 -0
  92. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-big-logo-with-transparent-background.svg +0 -0
  93. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-big-logo.png +0 -0
  94. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-contributor_reward_example.png +0 -0
  95. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-preview.gif +0 -0
  96. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-small-logo-with-transparent-background.png +0 -0
  97. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-small-logo-with-transparent-background.svg +0 -0
  98. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/images/babeldoc-small-logo.png +0 -0
  99. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/index.md +0 -0
  100. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/intro-to-pdf-object.md +0 -0
  101. {babeldoc-0.3.23 → babeldoc-0.3.25}/docs/requirements.txt +0 -0
  102. {babeldoc-0.3.23 → babeldoc-0.3.25}/mkdocs.yml +0 -0
  103. {babeldoc-0.3.23 → babeldoc-0.3.25}/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.23
3
+ Version: 0.3.25
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
@@ -0,0 +1 @@
1
+ __version__ = "0.3.25"
@@ -3,7 +3,7 @@ import shutil
3
3
  import subprocess
4
4
  from pathlib import Path
5
5
 
6
- __version__ = "0.3.23"
6
+ __version__ = "0.3.25"
7
7
 
8
8
  CACHE_FOLDER = Path.home() / ".cache" / "babeldoc"
9
9
 
@@ -777,7 +777,10 @@ class PDFCreater:
777
777
 
778
778
  def restore_media_box(self, doc: pymupdf.Document, mediabox_data: dict) -> None:
779
779
  for pageno, mediabox in mediabox_data.items():
780
- doc.xref_set_key(doc[pageno].xref, "MediaBox", mediabox[1])
780
+ try:
781
+ doc.xref_set_key(doc[pageno].xref, "MediaBox", mediabox[1])
782
+ except Exception:
783
+ logger.exception(f"restore media box failed on page: {pageno}")
781
784
 
782
785
  def write(
783
786
  self, translation_config: TranslationConfig, check_font_exists: bool = False
@@ -945,7 +948,10 @@ class PDFCreater:
945
948
  )
946
949
 
947
950
  pbar.advance()
948
- self.restore_media_box(pdf, self.mediabox_data)
951
+ try:
952
+ self.restore_media_box(pdf, self.mediabox_data)
953
+ except Exception:
954
+ logger.exception("restore media box failed")
949
955
  with self.translation_config.progress_monitor.stage_start(
950
956
  SAVE_PDF_STAGE_NAME,
951
957
  2,
@@ -1037,4 +1043,6 @@ class PDFCreater:
1037
1043
  "Failed to create PDF: %s",
1038
1044
  translation_config.input_file,
1039
1045
  )
1040
- return self.write(translation_config, True)
1046
+ if not check_font_exists:
1047
+ return self.write(translation_config, True)
1048
+ raise
@@ -167,6 +167,8 @@ class ParagraphFinder:
167
167
  # image characters are not needed
168
168
  page.pdf_character = []
169
169
 
170
+ self.fix_overlapping_paragraphs(page)
171
+
170
172
  def is_isolated_formula(self, char: PdfCharacter):
171
173
  return char.char_unicode in (
172
174
  "(cid:122)",
@@ -510,3 +512,105 @@ class ParagraphFinder:
510
512
  break
511
513
  j += 1
512
514
  i += 1
515
+
516
+ @staticmethod
517
+ def is_bbox_contain_in_vertical(bbox1: Box, bbox2: Box) -> bool:
518
+ """Check if one bounding box is completely contained within the other."""
519
+ # Check if bbox1 is contained in bbox2
520
+ bbox1_in_bbox2 = bbox1.y >= bbox2.y and bbox1.y2 <= bbox2.y2
521
+ # Check if bbox2 is contained in bbox1
522
+ bbox2_in_bbox1 = bbox2.y >= bbox1.y and bbox2.y2 <= bbox1.y2
523
+ return bbox1_in_bbox2 or bbox2_in_bbox1
524
+
525
+ def fix_overlapping_paragraphs(self, page: Page):
526
+ """
527
+ Adjusts the bounding boxes of paragraphs on a page to resolve vertical overlaps.
528
+
529
+ Iteratively checks pairs of paragraphs and adjusts their vertical boundaries
530
+ (y and y2) if they overlap, aiming to place the boundary at the midpoint
531
+ of the vertical overlap.
532
+ """
533
+ paragraphs = page.pdf_paragraph
534
+ if not paragraphs or len(paragraphs) < 2:
535
+ return
536
+
537
+ max_iterations = len(paragraphs) * len(paragraphs) # Safety break
538
+ iterations = 0
539
+
540
+ while iterations < max_iterations:
541
+ iterations += 1
542
+ overlap_found_in_pass = False
543
+
544
+ for i in range(len(paragraphs)):
545
+ for j in range(i + 1, len(paragraphs)):
546
+ para1 = paragraphs[i]
547
+ para2 = paragraphs[j]
548
+
549
+ if para1.box is None or para2.box is None:
550
+ continue
551
+
552
+ if para1.xobj_id != para2.xobj_id:
553
+ continue
554
+
555
+ # Check for overlap using the existing method
556
+ if self.bbox_overlap(para1.box, para2.box):
557
+ if self.is_bbox_contain_in_vertical(para1.box, para2.box):
558
+ continue
559
+ # Calculate vertical overlap details
560
+ overlap_y_start = max(para1.box.y, para2.box.y)
561
+ overlap_y_end = min(para1.box.y2, para2.box.y2)
562
+ overlap_height = overlap_y_end - overlap_y_start
563
+
564
+ # Calculate horizontal overlap details
565
+ overlap_x_start = max(para1.box.x, para2.box.x)
566
+ overlap_x_end = min(para1.box.x2, para2.box.x2)
567
+ overlap_width = overlap_x_end - overlap_x_start
568
+
569
+ # Ensure there's a real 2D overlap, focusing on vertical adjustment
570
+ if overlap_height > 1e-6 and overlap_width > 1e-6:
571
+ overlap_found_in_pass = True
572
+
573
+ # Determine which paragraph is visually higher
574
+ if para1.box.y2 > para2.box.y and para1.box.y < para2.box.y:
575
+ lower_para = para1
576
+ higher_para = para2
577
+ # Handle cases where y values are identical (or very close)
578
+ # Prefer the one with smaller y2 as the higher one, or break tie arbitrarily
579
+ elif para1.box.y2 < para2.box.y2:
580
+ lower_para = para1
581
+ higher_para = para2
582
+ else:
583
+ lower_para = para2
584
+ higher_para = para1
585
+
586
+ # Calculate the midpoint of the vertical overlap
587
+ mid_y = overlap_y_start + overlap_height / 2
588
+
589
+ # Adjust boxes, ensuring they remain valid (y2 > y)
590
+ if mid_y > higher_para.box.y and mid_y < lower_para.box.y2:
591
+ higher_para.box.y = mid_y + 1
592
+ lower_para.box.y2 = mid_y - 1
593
+ else:
594
+ # This might happen if one box is fully contained vertically
595
+ # within another, or due to floating point issues.
596
+ # Log a warning and skip adjustment for this pair in this iteration.
597
+ # A more complex strategy might be needed for full containment.
598
+ logger.warning(
599
+ "Could not resolve overlap between paragraphs"
600
+ f" {higher_para.debug_id} and {lower_para.debug_id}"
601
+ " using simple midpoint strategy."
602
+ f" Midpoint: {mid_y},"
603
+ f" Higher Box: {higher_para.box},"
604
+ f" Lower Box: {lower_para.box}"
605
+ )
606
+
607
+ # If no overlaps were found and adjusted in this pass, we're done.
608
+ if not overlap_found_in_pass:
609
+ break
610
+
611
+ if iterations == max_iterations:
612
+ logger.warning(
613
+ f"Maximum iterations ({max_iterations}) reached in"
614
+ f" fix_overlapping_paragraphs for page {page.page_number}."
615
+ " Some overlaps might remain."
616
+ )
@@ -645,7 +645,7 @@ class Typesetting:
645
645
  current_x = box.x
646
646
  current_y = box.y2 - avg_height
647
647
  box = copy.deepcopy(box)
648
- box.y -= avg_height * (line_spacing - 1)
648
+ # box.y -= avg_height * (line_spacing - 1.01)
649
649
  line_height = 0
650
650
  current_line_heights = [] # 存储当前行所有元素的高度
651
651
 
@@ -722,7 +722,8 @@ class Typesetting:
722
722
  current_line_heights = [] # 清空当前行高度列表
723
723
 
724
724
  # 检查是否超出底部边界
725
- if current_y - unit_height < box.y:
725
+ # if current_y - unit_height < box.y:
726
+ if current_y < box.y:
726
727
  all_units_fit = False
727
728
  break
728
729
 
@@ -750,8 +751,9 @@ class Typesetting:
750
751
  # 处理最后一行的行高
751
752
  if current_line_heights:
752
753
  mode_height = statistics.mode(current_line_heights)
753
- max_height = max(current_line_heights)
754
- line_height = max(mode_height, max_height)
754
+ # max_height = max(current_line_heights)
755
+ # line_height = max(mode_height, max_height)
756
+ line_height = mode_height
755
757
 
756
758
  return typeset_units, all_units_fit
757
759
 
@@ -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.23"
26
+ __version__ = "0.3.25"
27
27
 
28
28
 
29
29
  def create_parser():
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "BabelDOC"
3
- version = "0.3.23"
3
+ version = "0.3.25"
4
4
  description = "Yet Another Document Translator"
5
5
  license = "AGPL-3.0"
6
6
  readme = "README.md"
@@ -149,7 +149,7 @@ pythonpath = [".", "src"]
149
149
  testpaths = ["tests"]
150
150
 
151
151
  [bumpver]
152
- current_version = "0.3.23"
152
+ current_version = "0.3.25"
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.23"
51
+ version = "0.3.25"
52
52
  source = { editable = "." }
53
53
  dependencies = [
54
54
  { name = "bitstring" },
@@ -1 +0,0 @@
1
- __version__ = "0.3.23"
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