BabelDOC 0.1.6__py3-none-any.whl
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.
- babeldoc/__init__.py +1 -0
- babeldoc/asynchronize/__init__.py +51 -0
- babeldoc/const.py +7 -0
- babeldoc/converter.py +510 -0
- babeldoc/document_il/__init__.py +43 -0
- babeldoc/document_il/backend/__init__.py +0 -0
- babeldoc/document_il/backend/pdf_creater.py +402 -0
- babeldoc/document_il/frontend/__init__.py +0 -0
- babeldoc/document_il/frontend/il_creater.py +348 -0
- babeldoc/document_il/il_version_1.py +799 -0
- babeldoc/document_il/il_version_1.rnc +141 -0
- babeldoc/document_il/il_version_1.rng +390 -0
- babeldoc/document_il/il_version_1.xsd +235 -0
- babeldoc/document_il/midend/__init__.py +0 -0
- babeldoc/document_il/midend/add_debug_information.py +138 -0
- babeldoc/document_il/midend/il_translator.py +553 -0
- babeldoc/document_il/midend/layout_parser.py +180 -0
- babeldoc/document_il/midend/paragraph_finder.py +452 -0
- babeldoc/document_il/midend/remove_descent.py +168 -0
- babeldoc/document_il/midend/styles_and_formulas.py +701 -0
- babeldoc/document_il/midend/typesetting.py +761 -0
- babeldoc/document_il/translator/__init__.py +0 -0
- babeldoc/document_il/translator/cache.py +145 -0
- babeldoc/document_il/translator/translator.py +267 -0
- babeldoc/document_il/utils/fontmap.py +227 -0
- babeldoc/document_il/utils/layout_helper.py +467 -0
- babeldoc/document_il/utils/style_helper.py +86 -0
- babeldoc/document_il/xml_converter.py +51 -0
- babeldoc/docvision/README.md +0 -0
- babeldoc/docvision/__init__.py +0 -0
- babeldoc/docvision/doclayout.py +278 -0
- babeldoc/docvision/rpc_doclayout.py +162 -0
- babeldoc/high_level.py +468 -0
- babeldoc/main.py +466 -0
- babeldoc/pdfinterp.py +464 -0
- babeldoc/progress_monitor.py +146 -0
- babeldoc/translation_config.py +156 -0
- babeldoc-0.1.6.dist-info/METADATA +283 -0
- babeldoc-0.1.6.dist-info/RECORD +42 -0
- babeldoc-0.1.6.dist-info/WHEEL +4 -0
- babeldoc-0.1.6.dist-info/entry_points.txt +2 -0
- babeldoc-0.1.6.dist-info/licenses/LICENSE +661 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from collections import Counter
|
|
3
|
+
from functools import cache
|
|
4
|
+
|
|
5
|
+
from babeldoc.document_il import il_version_1
|
|
6
|
+
from babeldoc.translation_config import TranslationConfig
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RemoveDescent:
|
|
12
|
+
stage_name = "移除字体下沉"
|
|
13
|
+
|
|
14
|
+
def __init__(self, translation_config: TranslationConfig):
|
|
15
|
+
self.translation_config = translation_config
|
|
16
|
+
|
|
17
|
+
def _remove_char_descent(
|
|
18
|
+
self,
|
|
19
|
+
char: il_version_1.PdfCharacter,
|
|
20
|
+
font: il_version_1.PdfFont,
|
|
21
|
+
) -> float | None:
|
|
22
|
+
"""Remove descent from a single character and return the descent value.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
char: The character to process
|
|
26
|
+
font: The font used by this character
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
The descent value if it was removed, None otherwise
|
|
30
|
+
"""
|
|
31
|
+
if (
|
|
32
|
+
char.box
|
|
33
|
+
and char.box.y is not None
|
|
34
|
+
and char.box.y2 is not None
|
|
35
|
+
and font
|
|
36
|
+
and hasattr(font, "descent")
|
|
37
|
+
):
|
|
38
|
+
descent = font.descent * char.pdf_style.font_size / 1000
|
|
39
|
+
if char.vertical:
|
|
40
|
+
# For vertical text, remove descent from x coordinates
|
|
41
|
+
char.box.x += descent
|
|
42
|
+
char.box.x2 += descent
|
|
43
|
+
else:
|
|
44
|
+
# For horizontal text, remove descent from y coordinates
|
|
45
|
+
char.box.y -= descent
|
|
46
|
+
char.box.y2 -= descent
|
|
47
|
+
return descent
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
def process(self, document: il_version_1.Document):
|
|
51
|
+
"""Process the document to remove descent adjustments from character boxes.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
document: The document to process
|
|
55
|
+
"""
|
|
56
|
+
with self.translation_config.progress_monitor.stage_start(
|
|
57
|
+
self.stage_name,
|
|
58
|
+
len(document.page),
|
|
59
|
+
) as pbar:
|
|
60
|
+
for page in document.page:
|
|
61
|
+
self.translation_config.raise_if_cancelled()
|
|
62
|
+
self.process_page(page)
|
|
63
|
+
pbar.advance()
|
|
64
|
+
|
|
65
|
+
def process_page(self, page: il_version_1.Page):
|
|
66
|
+
"""Process a single page to remove descent adjustments.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
page: The page to process
|
|
70
|
+
"""
|
|
71
|
+
# Build font map including xobjects
|
|
72
|
+
fonts: dict[
|
|
73
|
+
str | int,
|
|
74
|
+
il_version_1.PdfFont | dict[str, il_version_1.PdfFont],
|
|
75
|
+
] = {f.font_id: f for f in page.pdf_font}
|
|
76
|
+
page_fonts = {f.font_id: f for f in page.pdf_font}
|
|
77
|
+
|
|
78
|
+
# Add xobject fonts
|
|
79
|
+
for xobj in page.pdf_xobject:
|
|
80
|
+
fonts[xobj.xobj_id] = page_fonts.copy()
|
|
81
|
+
for font in xobj.pdf_font:
|
|
82
|
+
fonts[xobj.xobj_id][font.font_id] = font
|
|
83
|
+
|
|
84
|
+
@cache
|
|
85
|
+
def get_font(
|
|
86
|
+
font_id: str,
|
|
87
|
+
xobj_id: int | None = None,
|
|
88
|
+
) -> il_version_1.PdfFont | None:
|
|
89
|
+
if xobj_id is not None and xobj_id in fonts:
|
|
90
|
+
font_map = fonts[xobj_id]
|
|
91
|
+
if isinstance(font_map, dict) and font_id in font_map:
|
|
92
|
+
return font_map[font_id]
|
|
93
|
+
return (
|
|
94
|
+
fonts.get(font_id)
|
|
95
|
+
if isinstance(fonts.get(font_id), il_version_1.PdfFont)
|
|
96
|
+
else None
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Process all standalone characters in the page
|
|
100
|
+
for char in page.pdf_character:
|
|
101
|
+
if font := get_font(char.pdf_style.font_id, char.xobj_id):
|
|
102
|
+
self._remove_char_descent(char, font)
|
|
103
|
+
|
|
104
|
+
# Process all paragraphs
|
|
105
|
+
for paragraph in page.pdf_paragraph:
|
|
106
|
+
descent_values = []
|
|
107
|
+
vertical_chars = []
|
|
108
|
+
|
|
109
|
+
# Process all characters in paragraph compositions
|
|
110
|
+
for comp in paragraph.pdf_paragraph_composition:
|
|
111
|
+
# Handle direct characters
|
|
112
|
+
if comp.pdf_character:
|
|
113
|
+
font = get_font(
|
|
114
|
+
comp.pdf_character.pdf_style.font_id,
|
|
115
|
+
comp.pdf_character.xobj_id,
|
|
116
|
+
)
|
|
117
|
+
if font:
|
|
118
|
+
descent = self._remove_char_descent(comp.pdf_character, font)
|
|
119
|
+
if descent is not None:
|
|
120
|
+
descent_values.append(descent)
|
|
121
|
+
vertical_chars.append(comp.pdf_character.vertical)
|
|
122
|
+
|
|
123
|
+
# Handle characters in PdfLine
|
|
124
|
+
elif comp.pdf_line:
|
|
125
|
+
for char in comp.pdf_line.pdf_character:
|
|
126
|
+
if font := get_font(char.pdf_style.font_id, char.xobj_id):
|
|
127
|
+
descent = self._remove_char_descent(char, font)
|
|
128
|
+
if descent is not None:
|
|
129
|
+
descent_values.append(descent)
|
|
130
|
+
vertical_chars.append(char.vertical)
|
|
131
|
+
|
|
132
|
+
# Handle characters in PdfFormula
|
|
133
|
+
elif comp.pdf_formula:
|
|
134
|
+
for char in comp.pdf_formula.pdf_character:
|
|
135
|
+
if font := get_font(char.pdf_style.font_id, char.xobj_id):
|
|
136
|
+
descent = self._remove_char_descent(char, font)
|
|
137
|
+
if descent is not None:
|
|
138
|
+
descent_values.append(descent)
|
|
139
|
+
vertical_chars.append(char.vertical)
|
|
140
|
+
|
|
141
|
+
# Handle characters in PdfSameStyleCharacters
|
|
142
|
+
elif comp.pdf_same_style_characters:
|
|
143
|
+
for char in comp.pdf_same_style_characters.pdf_character:
|
|
144
|
+
if font := get_font(char.pdf_style.font_id, char.xobj_id):
|
|
145
|
+
descent = self._remove_char_descent(char, font)
|
|
146
|
+
if descent is not None:
|
|
147
|
+
descent_values.append(descent)
|
|
148
|
+
vertical_chars.append(char.vertical)
|
|
149
|
+
|
|
150
|
+
# Adjust paragraph box based on most common descent value
|
|
151
|
+
if descent_values and paragraph.box:
|
|
152
|
+
# Calculate mode of descent values
|
|
153
|
+
descent_counter = Counter(descent_values)
|
|
154
|
+
most_common_descent = descent_counter.most_common(1)[0][0]
|
|
155
|
+
|
|
156
|
+
# Check if paragraph is vertical (all characters are vertical)
|
|
157
|
+
is_vertical = all(vertical_chars) if vertical_chars else False
|
|
158
|
+
|
|
159
|
+
# Adjust paragraph box
|
|
160
|
+
if paragraph.box.y is not None and paragraph.box.y2 is not None:
|
|
161
|
+
if is_vertical:
|
|
162
|
+
# For vertical paragraphs, adjust x coordinates
|
|
163
|
+
paragraph.box.x += most_common_descent
|
|
164
|
+
paragraph.box.x2 += most_common_descent
|
|
165
|
+
else:
|
|
166
|
+
# For horizontal paragraphs, adjust y coordinates
|
|
167
|
+
paragraph.box.y -= most_common_descent
|
|
168
|
+
paragraph.box.y2 -= most_common_descent
|