text-block-renderer 2.2.0__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.
- text_block_renderer-2.2.0.dist-info/METADATA +489 -0
- text_block_renderer-2.2.0.dist-info/RECORD +14 -0
- text_block_renderer-2.2.0.dist-info/WHEEL +5 -0
- text_block_renderer-2.2.0.dist-info/licenses/LICENSE +19 -0
- text_block_renderer-2.2.0.dist-info/top_level.txt +1 -0
- textblockrenderer/__init__.py +128 -0
- textblockrenderer/htmlparser.py +214 -0
- textblockrenderer/lang_constants.py +576 -0
- textblockrenderer/models.py +190 -0
- textblockrenderer/pipeline.py +954 -0
- textblockrenderer/renderer.py +410 -0
- textblockrenderer/rtl_processor.py +279 -0
- textblockrenderer/splitter.py +557 -0
- textblockrenderer/timing.py +237 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: text-block-renderer
|
|
3
|
+
Version: 2.2.0
|
|
4
|
+
Summary: A library for parsing HTML text, splitting text into blocks, and rendering blocks to PNG images
|
|
5
|
+
Author: Text Driven Subtitle Team
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: text,subtitle,html,rendering,png
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: pillow>=9.0.0
|
|
19
|
+
Requires-Dist: pydantic>=2.0.0
|
|
20
|
+
Requires-Dist: arabic-reshaper>=3.0.0
|
|
21
|
+
Requires-Dist: python-bidi>=0.6.7
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest==9.0.2; extra == "dev"
|
|
24
|
+
Requires-Dist: pyarmor==9.2.3; extra == "dev"
|
|
25
|
+
Requires-Dist: mypy==1.19.1; extra == "dev"
|
|
26
|
+
Requires-Dist: build==1.4.0; extra == "dev"
|
|
27
|
+
Requires-Dist: twine==6.2.0; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# Text Block Renderer
|
|
31
|
+
|
|
32
|
+
A Python library for generating timeline subtitles from HTML text. Parse styled HTML, split text into dimension-constrained blocks, render to PNG images, and calculate reading times for video subtitle production.
|
|
33
|
+
|
|
34
|
+
一个用于从 HTML 文本生成时间轴字幕的 Python 库。解析带样式的 HTML、按尺寸约束拆分文本块、渲染为 PNG 图片,并计算阅读时间以用于视频字幕制作。
|
|
35
|
+
|
|
36
|
+
------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
## Installation \| 安装
|
|
39
|
+
|
|
40
|
+
Install from PyPI:
|
|
41
|
+
|
|
42
|
+
``` bash
|
|
43
|
+
pip install textblockrenderer
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or install from source:
|
|
47
|
+
|
|
48
|
+
``` bash
|
|
49
|
+
cd textblockrenderer
|
|
50
|
+
pip install -e .
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
从源码安装:
|
|
54
|
+
|
|
55
|
+
``` bash
|
|
56
|
+
cd textblockrenderer
|
|
57
|
+
pip install -e .
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
## Features \| 功能特性
|
|
63
|
+
|
|
64
|
+
- **HTML Parsing**: Parse HTML text with color and font-size styles\
|
|
65
|
+
**HTML 解析**:支持解析带颜色与字号样式的 HTML 文本
|
|
66
|
+
|
|
67
|
+
- **Text Splitting**: Split text into blocks within specified
|
|
68
|
+
dimensions\
|
|
69
|
+
**文本拆分**:根据尺寸约束拆分文本块
|
|
70
|
+
|
|
71
|
+
- **PNG Rendering**: Render text blocks to PNG images with
|
|
72
|
+
customizable styles\
|
|
73
|
+
**PNG 渲染**:将文本块渲染为可自定义样式的 PNG 图片
|
|
74
|
+
|
|
75
|
+
- **Newline Support**: Preserve `\n` as explicit line breaks\
|
|
76
|
+
**换行支持**:保留 `\n` 作为显式换行
|
|
77
|
+
|
|
78
|
+
- **Unlimited Height**: Use `max_height=0` to disable height limits\
|
|
79
|
+
**无限高度模式**:设置 `max_height=0` 可取消高度限制
|
|
80
|
+
|
|
81
|
+
- **O(n) Performance**: Incremental measurement algorithm for
|
|
82
|
+
efficient splitting\
|
|
83
|
+
**O(n) 性能**:使用增量测量算法提升拆分效率
|
|
84
|
+
|
|
85
|
+
- **RTL Language Support**: Full support for Arabic and Hebrew (Right-to-Left)\
|
|
86
|
+
**RTL 语言支持**:完整支持阿拉伯语和希伯来语(从右到左书写)
|
|
87
|
+
|
|
88
|
+
- **Timeline Subtitles**: Generate timeline subtitles with read time calculation\
|
|
89
|
+
**时间轴字幕**:生成带阅读时间计算的时间轴字幕
|
|
90
|
+
|
|
91
|
+
- **Overlapping Frames**: Support multiple subtitle blocks in a single frame\
|
|
92
|
+
**重叠帧**:支持单帧内显示多个字幕块
|
|
93
|
+
|
|
94
|
+
- **Long Image Export**: Generate scrolling long PNG images\
|
|
95
|
+
**长图导出**:生成滚屏长图
|
|
96
|
+
|
|
97
|
+
- **Adaptive Text Rendering**: Three adjust modes (WIDTH / HEIGHT_EXTEND / ADAPT) with vertical alignment\
|
|
98
|
+
**自适应文本渲染**:三种调整模式(固定宽度 / 高度扩展 / 自适应缩放)及垂直对齐
|
|
99
|
+
|
|
100
|
+
------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
## Multi-language Support \| 多语言支持
|
|
103
|
+
|
|
104
|
+
Supports 19 languages with language-specific WPM (words per minute) and semantic splitting:
|
|
105
|
+
|
|
106
|
+
| Language | Code | WPM | Language | Code | WPM |
|
|
107
|
+
|----------|------|-----|----------|------|-----|
|
|
108
|
+
| English | EN | 150 | German | DE | 150 |
|
|
109
|
+
| French | FR | 150 | Spanish | ES | 150 |
|
|
110
|
+
| Portuguese | PT | 150 | Italian | IT | 150 |
|
|
111
|
+
| Dutch | NL | 150 | Polish | PL | 150 |
|
|
112
|
+
| Romanian | RO | 150 | Swedish | SV | 150 |
|
|
113
|
+
| Turkish | TR | 150 | Vietnamese | VI | 150 |
|
|
114
|
+
| Indonesian | ID | 150 | Greek | EL | 150 |
|
|
115
|
+
| Filipino | TL | 150 | Russian | RU | 130 |
|
|
116
|
+
| Hindi | HI | 100 | **Arabic** | AR | 120 |
|
|
117
|
+
| **Hebrew** | HE | 120 | | | |
|
|
118
|
+
|
|
119
|
+
**RTL Languages** (Arabic, Hebrew): Full support with Arabic reshaping and bidirectional text rendering.
|
|
120
|
+
|
|
121
|
+
------------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
## Usage \| 使用示例
|
|
124
|
+
|
|
125
|
+
``` python
|
|
126
|
+
from textblockrenderer import (
|
|
127
|
+
FontSpec, RenderConstraint, SplitConfig,
|
|
128
|
+
TextMeasurer, split_html_paragraphs,
|
|
129
|
+
split_html_to_colored_blocks, render_colored_block
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# 1. Parse HTML paragraphs
|
|
133
|
+
html_text = '<p>Hello <span style="color: red;">World</span></p>'
|
|
134
|
+
paragraphs = split_html_paragraphs(html_text)
|
|
135
|
+
|
|
136
|
+
# Or combine paragraphs with newlines
|
|
137
|
+
combined = split_html_paragraphs(html_text, combine=True)
|
|
138
|
+
|
|
139
|
+
# 2. Configure font and constraints
|
|
140
|
+
font_spec = FontSpec(font_path="arialbd.ttf", font_size=36)
|
|
141
|
+
measurer = TextMeasurer(font_spec)
|
|
142
|
+
constraint = RenderConstraint(max_width=680, max_height=300)
|
|
143
|
+
# Configure language for better semantic splitting (default "EN")
|
|
144
|
+
config = SplitConfig(min_words_per_block=8, language="DE")
|
|
145
|
+
|
|
146
|
+
# 3. Split text into blocks
|
|
147
|
+
blocks = split_html_to_colored_blocks(paragraphs[0], measurer, constraint, config)
|
|
148
|
+
|
|
149
|
+
# 4. Render to PNG
|
|
150
|
+
for i, block in enumerate(blocks):
|
|
151
|
+
img = render_colored_block(
|
|
152
|
+
block,
|
|
153
|
+
measurer,
|
|
154
|
+
background_color=(0, 0, 0, 0),
|
|
155
|
+
default_color="white",
|
|
156
|
+
align="center"
|
|
157
|
+
)
|
|
158
|
+
img.save(f"block_{i}.png")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Explanation \| 说明
|
|
162
|
+
|
|
163
|
+
- Parse HTML into paragraphs\
|
|
164
|
+
将 HTML 文本解析为段落
|
|
165
|
+
|
|
166
|
+
- Configure font and layout constraints\
|
|
167
|
+
配置字体与尺寸限制
|
|
168
|
+
|
|
169
|
+
- Split paragraphs into renderable blocks\
|
|
170
|
+
将段落拆分为可渲染文本块
|
|
171
|
+
|
|
172
|
+
- Render blocks into PNG images\
|
|
173
|
+
将文本块渲染为 PNG 图片
|
|
174
|
+
|
|
175
|
+
------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
## Newline Support \| 换行支持
|
|
178
|
+
|
|
179
|
+
``` python
|
|
180
|
+
text = "First line\nSecond line\n\nAfter empty line"
|
|
181
|
+
blocks = split_html_to_colored_blocks(text, measurer, constraint, config)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Result:
|
|
185
|
+
|
|
186
|
+
- Line 1: First line\
|
|
187
|
+
- Line 2: Second line\
|
|
188
|
+
- Line 3: empty line\
|
|
189
|
+
- Line 4: After empty line
|
|
190
|
+
|
|
191
|
+
结果:
|
|
192
|
+
|
|
193
|
+
- 第1行:First line
|
|
194
|
+
- 第2行:Second line
|
|
195
|
+
- 第3行:空行
|
|
196
|
+
- 第4行:After empty line
|
|
197
|
+
|
|
198
|
+
------------------------------------------------------------------------
|
|
199
|
+
|
|
200
|
+
## Unlimited Height \| 无限高度模式
|
|
201
|
+
|
|
202
|
+
``` python
|
|
203
|
+
constraint = RenderConstraint(max_width=680, max_height=0)
|
|
204
|
+
blocks = split_html_to_colored_blocks(text, measurer, constraint, config)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
All text will remain in a single block.
|
|
208
|
+
|
|
209
|
+
所有文本将保留在一个块中。
|
|
210
|
+
|
|
211
|
+
------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
## API Reference \| API 参考
|
|
214
|
+
|
|
215
|
+
### HTML Parsing \| HTML 解析
|
|
216
|
+
|
|
217
|
+
- `parse_html_text(html_text, base_font_size, target_font_size)`\
|
|
218
|
+
- `split_html_paragraphs(html_text, combine=False)`
|
|
219
|
+
|
|
220
|
+
------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
### Text Splitting \| 文本拆分
|
|
223
|
+
|
|
224
|
+
- `TextMeasurer(font_spec)`
|
|
225
|
+
- `split_paragraph_to_blocks(paragraph, measurer, constraint, config)`
|
|
226
|
+
- `split_html_to_colored_blocks(html_paragraph, measurer, constraint, config)`
|
|
227
|
+
|
|
228
|
+
------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
### PNG Rendering \| PNG 渲染
|
|
231
|
+
|
|
232
|
+
- `render_colored_block(block, measurer, ...)`
|
|
233
|
+
|
|
234
|
+
------------------------------------------------------------------------
|
|
235
|
+
|
|
236
|
+
### Pipeline API \| 流水线 API
|
|
237
|
+
|
|
238
|
+
End-to-end functions for timeline subtitle generation:
|
|
239
|
+
|
|
240
|
+
| Function | Description |
|
|
241
|
+
|----------|-------------|
|
|
242
|
+
| `text_to_timeline_subtitles()` | Generate timeline subtitle frames from HTML / 从 HTML 生成时间轴字幕帧 |
|
|
243
|
+
| `text_to_overlapping_subtitles()` | Generate overlapping timeline subtitles / 生成可重叠时间轴字幕 |
|
|
244
|
+
| `text_to_long_image()` | Generate a single long PNG image / 生成单张长图 |
|
|
245
|
+
| `render_text_image()` | Render text image with adaptive adjust modes / 自适应模式渲染文本图片 |
|
|
246
|
+
| `blocks_to_timeline_subtitles()` | Create subtitles from existing blocks / 从已有块创建字幕 |
|
|
247
|
+
| `calculate_total_duration()` | Calculate total duration of frames / 计算字幕帧总时长 |
|
|
248
|
+
| `get_timestamps()` | Get start/end timestamps for each frame / 获取每帧时间戳 |
|
|
249
|
+
| `export_to_srt()` | Export frames to SRT file / 导出为 SRT 文件 |
|
|
250
|
+
| `get_overlapping_total_duration()` | Calculate overlapping frames duration / 计算重叠帧总时长 |
|
|
251
|
+
| `export_overlapping_to_srt()` | Export overlapping frames to SRT / 导出重叠帧为 SRT |
|
|
252
|
+
|
|
253
|
+
#### text_to_timeline_subtitles
|
|
254
|
+
|
|
255
|
+
Generate timeline subtitle frames, one block per frame.
|
|
256
|
+
生成时间轴字幕帧,每帧一个字幕块。
|
|
257
|
+
|
|
258
|
+
``` python
|
|
259
|
+
from textblockrenderer import (
|
|
260
|
+
text_to_timeline_subtitles, export_to_srt,
|
|
261
|
+
FontSpec, RenderConstraint, SplitConfig, RenderStyle
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
html_text = "<p>First paragraph.</p><p>Second paragraph with more text.</p>"
|
|
265
|
+
font_spec = FontSpec(font_path="arialbd.ttf", font_size=36, line_spacing=-8)
|
|
266
|
+
constraint = RenderConstraint(max_width=555, max_height=400)
|
|
267
|
+
split_config = SplitConfig(min_words_per_block=8, language="EN")
|
|
268
|
+
style = RenderStyle(
|
|
269
|
+
text_color="#FFFFFF",
|
|
270
|
+
mask_mode=2, # 0=none, 1=rounded rect, 2=per-line polygon
|
|
271
|
+
mask_color=(255, 0, 0, 180),
|
|
272
|
+
padding=(4, 4),
|
|
273
|
+
mask_offset=(8, 8),
|
|
274
|
+
stroke_size=2,
|
|
275
|
+
stroke_color=(0, 0, 0, 255),
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
frames = text_to_timeline_subtitles(
|
|
279
|
+
html_text, font_spec, constraint, "output/",
|
|
280
|
+
split_config=split_config, style=style, wpm=160
|
|
281
|
+
)
|
|
282
|
+
export_to_srt(frames, "output/subtitles.srt")
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### text_to_overlapping_subtitles
|
|
286
|
+
|
|
287
|
+
Generate overlapping subtitle frames, multiple blocks can share one frame.
|
|
288
|
+
生成重叠字幕帧,多个字幕块可以合并到同一帧。
|
|
289
|
+
|
|
290
|
+
``` python
|
|
291
|
+
from textblockrenderer import (
|
|
292
|
+
text_to_overlapping_subtitles, export_overlapping_to_srt,
|
|
293
|
+
FontSpec, RenderConstraint, SplitConfig, RenderStyle
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
frames = text_to_overlapping_subtitles(
|
|
297
|
+
html_text, font_spec, constraint, "output/",
|
|
298
|
+
split_config=split_config,
|
|
299
|
+
style=style,
|
|
300
|
+
wpm=160,
|
|
301
|
+
spacing=10, # spacing between blocks in pixels
|
|
302
|
+
max_blocks_per_frame=3, # max blocks per frame, 0=unlimited
|
|
303
|
+
)
|
|
304
|
+
export_overlapping_to_srt(frames, "output/subtitles.srt")
|
|
305
|
+
|
|
306
|
+
# Each frame contains multiple BlockTiming objects
|
|
307
|
+
for frame in frames:
|
|
308
|
+
print(f"Frame ends at {frame.frame_end_time}s, {len(frame.block_timings)} blocks")
|
|
309
|
+
for timing in frame.block_timings:
|
|
310
|
+
print(f" {timing.start_time}s - {timing.end_time}s: {timing.block.plain_text[:30]}...")
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
#### text_to_long_image
|
|
314
|
+
|
|
315
|
+
Generate a single long scrolling image from HTML text.
|
|
316
|
+
从 HTML 文本生成单张滚屏长图。
|
|
317
|
+
|
|
318
|
+
``` python
|
|
319
|
+
from textblockrenderer import (
|
|
320
|
+
text_to_long_image,
|
|
321
|
+
FontSpec, RenderConstraint, RenderStyle
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
block = text_to_long_image(
|
|
325
|
+
html_text, font_spec, constraint, "output/long_image.png",
|
|
326
|
+
style=style
|
|
327
|
+
)
|
|
328
|
+
print(f"Generated image: {block.image_width}x{block.image_height}")
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### render_text_image
|
|
332
|
+
|
|
333
|
+
Render text image with adaptive adjust modes and vertical alignment.
|
|
334
|
+
自适应模式渲染文本图片,支持三种调整模式和垂直对齐。
|
|
335
|
+
|
|
336
|
+
**Adjust Modes / 调整模式:**
|
|
337
|
+
|
|
338
|
+
| Mode | Description |
|
|
339
|
+
|------|-------------|
|
|
340
|
+
| `WIDTH` | Fixed width, height grows until all text is rendered / 固定宽度,高度自适应 |
|
|
341
|
+
| `HEIGHT_EXTEND` | Fixed height, width grows from `min_width` to `max_width`; extends height if still needed / 固定高度,宽度扩展;仍放不下则延伸高度 |
|
|
342
|
+
| `ADAPT` | Fixed area, auto-shrinks font size (binary search, min 16px) → reduces line spacing → truncates / 固定区域,二分缩小字号→缩小行距→截断 |
|
|
343
|
+
|
|
344
|
+
**Vertical Alignment / 垂直对齐:** `top` / `middle` / `bottom` (effective when content < image height)
|
|
345
|
+
|
|
346
|
+
``` python
|
|
347
|
+
from textblockrenderer import (
|
|
348
|
+
render_text_image,
|
|
349
|
+
FontSpec, RenderConstraint, SplitConfig, RenderStyle,
|
|
350
|
+
AdjustMode, VerticalAlignment,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
html_text = "<p>Hello <span style='color: red;'>World</span></p>"
|
|
354
|
+
font_spec = FontSpec(font_path="arialbd.ttf", font_size=36, line_spacing=-10)
|
|
355
|
+
style = RenderStyle(
|
|
356
|
+
text_color="#FFFFFF", alignment="center",
|
|
357
|
+
padding=(10, 10), mask_mode=1, mask_color=(0, 0, 0, 180),
|
|
358
|
+
stroke_size=2, stroke_color=(0, 0, 0, 255),
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
# WIDTH mode: fixed width, auto height
|
|
362
|
+
block = render_text_image(
|
|
363
|
+
html_text, font_spec,
|
|
364
|
+
RenderConstraint(max_width=555),
|
|
365
|
+
"output/width.png",
|
|
366
|
+
adjust="WIDTH", vertical_align="top", style=style,
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
# HEIGHT_EXTEND mode: try fit in height, expand width, then extend height
|
|
370
|
+
block = render_text_image(
|
|
371
|
+
html_text, font_spec,
|
|
372
|
+
RenderConstraint(max_width=555, max_height=400, min_width=300),
|
|
373
|
+
"output/height_extend.png",
|
|
374
|
+
adjust="HEIGHT_EXTEND", vertical_align="middle", style=style,
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
# ADAPT mode: fit in fixed area, auto-shrink font/spacing, truncate last
|
|
378
|
+
block = render_text_image(
|
|
379
|
+
html_text, font_spec,
|
|
380
|
+
RenderConstraint(max_width=555, max_height=400),
|
|
381
|
+
"output/adapt.png",
|
|
382
|
+
adjust=AdjustMode.ADAPT,
|
|
383
|
+
vertical_align=VerticalAlignment.MIDDLE,
|
|
384
|
+
style=style,
|
|
385
|
+
)
|
|
386
|
+
print(f"Final font size: {font_spec.font_size}, line spacing: {font_spec.line_spacing}")
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Timing API \| 时间计算 API
|
|
390
|
+
|
|
391
|
+
| Function | Description |
|
|
392
|
+
|----------|-------------|
|
|
393
|
+
| `calculate_read_time()` | Calculate read time for a block / 计算单个块的阅读时间 |
|
|
394
|
+
| `calculate_read_times()` | Calculate read times for multiple blocks / 批量计算阅读时间 |
|
|
395
|
+
| `create_frame_subtitles()` | Create subtitle frames with timing / 创建带时间的字幕帧 |
|
|
396
|
+
| `can_fit_next_block()` | Check if next block fits in frame / 检查下一块是否适合帧 |
|
|
397
|
+
| `create_overlapping_frame_subtitles()` | Create overlapping subtitle frames / 创建重叠字幕帧 |
|
|
398
|
+
| `get_wpm_for_language()` | Get WPM for a specific language / 获取特定语言的 WPM |
|
|
399
|
+
|
|
400
|
+
------------------------------------------------------------------------
|
|
401
|
+
|
|
402
|
+
### Data Models \| 数据模型
|
|
403
|
+
|
|
404
|
+
- `FontSpec` --- Font configuration / 字体配置
|
|
405
|
+
- `RenderConstraint` --- Size constraints / 尺寸限制
|
|
406
|
+
- `SplitConfig` --- Split configuration / 拆分配置
|
|
407
|
+
- `RenderStyle` --- Render style configuration / 渲染样式配置
|
|
408
|
+
- `ColoredWord` --- Styled word object / 带样式的单词对象
|
|
409
|
+
- `ColoredSubtitleBlock` --- Styled text block / 带样式文本块
|
|
410
|
+
- `FrameSubtitle` --- Timeline subtitle frame / 时间轴字幕帧
|
|
411
|
+
- `BlockTiming` --- Block timing info / 块时间信息
|
|
412
|
+
- `OverlappingFrameSubtitle` --- Overlapping subtitle frame / 重叠字幕帧
|
|
413
|
+
- `AdjustMode` --- Adjust mode enum (WIDTH / HEIGHT_EXTEND / ADAPT) / 调整模式枚举
|
|
414
|
+
- `VerticalAlignment` --- Vertical alignment enum (top / middle / bottom) / 垂直对齐枚举
|
|
415
|
+
|
|
416
|
+
------------------------------------------------------------------------
|
|
417
|
+
|
|
418
|
+
## Version History \| 版本历史
|
|
419
|
+
|
|
420
|
+
### 2.1.0
|
|
421
|
+
|
|
422
|
+
- Add `render_text_image()` function with three adjust modes / 新增 `render_text_image()` 函数,支持三种调整模式
|
|
423
|
+
- Add `AdjustMode` enum: `WIDTH`, `HEIGHT_EXTEND`, `ADAPT` / 新增 `AdjustMode` 枚举
|
|
424
|
+
- Add `VerticalAlignment` enum: `top`, `middle`, `bottom` / 新增 `VerticalAlignment` 枚举
|
|
425
|
+
- Add `min_width` field to `RenderConstraint` / `RenderConstraint` 新增 `min_width` 字段
|
|
426
|
+
- Add `vertical_align` and `target_height` params to `render_colored_block()` / `render_colored_block()` 新增垂直对齐和目标高度参数
|
|
427
|
+
- ADAPT mode: binary search font size (min 16px) → reduce line spacing → truncate / ADAPT 模式:二分缩小字号→缩小行距→截断
|
|
428
|
+
|
|
429
|
+
### 2.0.0
|
|
430
|
+
|
|
431
|
+
- Add `max_blocks_per_frame` parameter to `text_to_overlapping_subtitles()` / 为 `text_to_overlapping_subtitles()` 添加每帧最大块数限制参数
|
|
432
|
+
- Update README with Pipeline API usage examples / 更新 README 添加 Pipeline API 使用示例
|
|
433
|
+
|
|
434
|
+
### 1.4.4
|
|
435
|
+
|
|
436
|
+
- Increase the size of the produced images / 增加生产的图片尺寸
|
|
437
|
+
- Fix the issue of imprecise rendering / 修复渲染尺寸不精准的问题
|
|
438
|
+
|
|
439
|
+
### 1.4.1
|
|
440
|
+
|
|
441
|
+
- Add stroke style / 增加描边样式
|
|
442
|
+
|
|
443
|
+
### 1.4.0
|
|
444
|
+
|
|
445
|
+
- Overlapping Frame Subtitles / 可重叠帧时间轴字幕
|
|
446
|
+
- Single Long Image Export / 单张长图字幕导出
|
|
447
|
+
- `text_to_overlapping_subtitles()` API
|
|
448
|
+
- `text_to_long_image()` API
|
|
449
|
+
- `BlockTiming` and `OverlappingFrameSubtitle` models
|
|
450
|
+
|
|
451
|
+
### 1.3.0
|
|
452
|
+
|
|
453
|
+
- Release code encryption / 发布代码加密
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
### 1.2.0
|
|
457
|
+
|
|
458
|
+
- RTL Language Support / 从右到左语言支持 (Arabic, Hebrew)
|
|
459
|
+
- Arabic reshaping for connected letters / 阿拉伯语字母连接
|
|
460
|
+
- Bidirectional text rendering / 双向文本渲染
|
|
461
|
+
- RTL-aware semantic break detection / RTL 感知的语义断点检测
|
|
462
|
+
- Performance optimization with batch RTL processing / 批量 RTL 处理性能优化
|
|
463
|
+
|
|
464
|
+
### 1.1.0
|
|
465
|
+
|
|
466
|
+
- Multi-language Support / 多语言支持 (19 languages)
|
|
467
|
+
- Language-specific semantic splitting / 特定语言的语义拆分
|
|
468
|
+
- Greek question mark support / 希腊语问号支持
|
|
469
|
+
|
|
470
|
+
### 1.0.0
|
|
471
|
+
|
|
472
|
+
- Stable release / 稳定版本发布
|
|
473
|
+
- O(n) incremental measurement / O(n) 增量测量算法
|
|
474
|
+
- Newline support / 支持换行
|
|
475
|
+
- Unlimited height mode / 无限高度模式
|
|
476
|
+
- Paragraph combination support / 支持段落合并
|
|
477
|
+
|
|
478
|
+
------------------------------------------------------------------------
|
|
479
|
+
|
|
480
|
+
## License \| 许可证
|
|
481
|
+
|
|
482
|
+
MIT License
|
|
483
|
+
|
|
484
|
+
------------------------------------------------------------------------
|
|
485
|
+
|
|
486
|
+
## Todo / Roadmap
|
|
487
|
+
|
|
488
|
+
- [ ] Chinese, Japanese and Korean language support / 中日韩语言支持
|
|
489
|
+
- [ ] Block forced end marker / 区块强制结束标记
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
text_block_renderer-2.2.0.dist-info/licenses/LICENSE,sha256=77sXjnKK4vh5td9h5iydP_kiSk1QGLfe7qn7ivN9YZ0,1073
|
|
2
|
+
textblockrenderer/__init__.py,sha256=eF0LpyvCMXfvGwKbfw1G1mP1Hefkt0KpoVdl9xWVrpk,3078
|
|
3
|
+
textblockrenderer/htmlparser.py,sha256=xOAGkdM2ocil0okyQhXq38Py_pedpp39_8UPDJfwoI0,8350
|
|
4
|
+
textblockrenderer/lang_constants.py,sha256=6aVIsZ57vsQTmUza6SWSgXdWPoJz6GBvRq_xGsnWZIg,11665
|
|
5
|
+
textblockrenderer/models.py,sha256=vsYZBNtA8UsxKDUgQXFGtOHvXr3LBlbx3foORQTymj8,5631
|
|
6
|
+
textblockrenderer/pipeline.py,sha256=QnJAF55BU2yauFaQPoCvk3wBuVX4BOV7P6juivguzuQ,32172
|
|
7
|
+
textblockrenderer/renderer.py,sha256=CjaXtqvKKW3B_yfguQGyqFGsuOJNxEcT8TuYRoijx9E,15896
|
|
8
|
+
textblockrenderer/rtl_processor.py,sha256=ZWLCgssnBp2qR0q6h9Z3iPHJqLSPUPOope7ER9ELkYU,8379
|
|
9
|
+
textblockrenderer/splitter.py,sha256=qTVC6iW2oSFzdkzKDdY-6mXeQS5HA48owim9dytVJQI,19785
|
|
10
|
+
textblockrenderer/timing.py,sha256=sXXzPf5VflNX1P1TYO5r79gFrpBg5tt04koc3nR5f6U,7543
|
|
11
|
+
text_block_renderer-2.2.0.dist-info/METADATA,sha256=438vR7w6h4kUE3KF4vBnEb4rlE_YFClI9feVaRjFj1w,18205
|
|
12
|
+
text_block_renderer-2.2.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
|
13
|
+
text_block_renderer-2.2.0.dist-info/top_level.txt,sha256=VdZGT_KmJ2BD_PFGx0gz8kdVfWyoXRNIqXnvD1oh7Q8,18
|
|
14
|
+
text_block_renderer-2.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026 DramaJoker
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
textblockrenderer
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Text Block Renderer - A library for parsing HTML text, splitting text into blocks, and rendering blocks to PNG images."""
|
|
2
|
+
|
|
3
|
+
from .models import (
|
|
4
|
+
ColoredSpan,
|
|
5
|
+
ColoredWord,
|
|
6
|
+
FontSpec,
|
|
7
|
+
RenderConstraint,
|
|
8
|
+
SubtitleBlock,
|
|
9
|
+
ColoredSubtitleBlock,
|
|
10
|
+
SplitConfig,
|
|
11
|
+
RenderStyle,
|
|
12
|
+
FrameSubtitle,
|
|
13
|
+
BlockTiming,
|
|
14
|
+
OverlappingFrameSubtitle,
|
|
15
|
+
AdjustMode,
|
|
16
|
+
VerticalAlignment,
|
|
17
|
+
)
|
|
18
|
+
from .htmlparser import (
|
|
19
|
+
ColorHTMLParser,
|
|
20
|
+
parse_html_text,
|
|
21
|
+
split_html_paragraphs,
|
|
22
|
+
)
|
|
23
|
+
from .splitter import (
|
|
24
|
+
TextMeasurer,
|
|
25
|
+
find_semantic_break,
|
|
26
|
+
split_paragraph_to_blocks,
|
|
27
|
+
find_colored_semantic_break,
|
|
28
|
+
split_html_to_colored_blocks,
|
|
29
|
+
)
|
|
30
|
+
from .renderer import (
|
|
31
|
+
optimize_polygon_x_alignment,
|
|
32
|
+
round_polygon_corners,
|
|
33
|
+
render_colored_block,
|
|
34
|
+
)
|
|
35
|
+
from .rtl_processor import (
|
|
36
|
+
is_rtl_language,
|
|
37
|
+
is_rtl_text,
|
|
38
|
+
process_rtl_text,
|
|
39
|
+
RTL_AVAILABLE,
|
|
40
|
+
)
|
|
41
|
+
from .timing import (
|
|
42
|
+
DEFAULT_WPM,
|
|
43
|
+
WPM_MAP,
|
|
44
|
+
get_wpm_for_language,
|
|
45
|
+
MIN_DISPLAY_TIME,
|
|
46
|
+
MAX_DISPLAY_TIME,
|
|
47
|
+
SECONDS_PER_WORD,
|
|
48
|
+
count_words,
|
|
49
|
+
calculate_read_time,
|
|
50
|
+
calculate_read_times,
|
|
51
|
+
create_frame_subtitles,
|
|
52
|
+
can_fit_next_block,
|
|
53
|
+
create_overlapping_frame_subtitles,
|
|
54
|
+
)
|
|
55
|
+
from .pipeline import (
|
|
56
|
+
text_to_timeline_subtitles,
|
|
57
|
+
blocks_to_timeline_subtitles,
|
|
58
|
+
calculate_total_duration,
|
|
59
|
+
get_timestamps,
|
|
60
|
+
export_to_srt,
|
|
61
|
+
text_to_overlapping_subtitles,
|
|
62
|
+
get_overlapping_total_duration,
|
|
63
|
+
export_overlapping_to_srt,
|
|
64
|
+
text_to_long_image,
|
|
65
|
+
render_text_image,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
__version__ = "2.2.0"
|
|
69
|
+
|
|
70
|
+
__all__ = [
|
|
71
|
+
# Models
|
|
72
|
+
"ColoredSpan",
|
|
73
|
+
"ColoredWord",
|
|
74
|
+
"FontSpec",
|
|
75
|
+
"RenderConstraint",
|
|
76
|
+
"SubtitleBlock",
|
|
77
|
+
"ColoredSubtitleBlock",
|
|
78
|
+
"SplitConfig",
|
|
79
|
+
"RenderStyle",
|
|
80
|
+
"FrameSubtitle",
|
|
81
|
+
"BlockTiming",
|
|
82
|
+
"OverlappingFrameSubtitle",
|
|
83
|
+
"AdjustMode",
|
|
84
|
+
"VerticalAlignment",
|
|
85
|
+
# HTML Parser
|
|
86
|
+
"ColorHTMLParser",
|
|
87
|
+
"parse_html_text",
|
|
88
|
+
"split_html_paragraphs",
|
|
89
|
+
# Splitter
|
|
90
|
+
"TextMeasurer",
|
|
91
|
+
"find_semantic_break",
|
|
92
|
+
"split_paragraph_to_blocks",
|
|
93
|
+
"find_colored_semantic_break",
|
|
94
|
+
"split_html_to_colored_blocks",
|
|
95
|
+
# Renderer
|
|
96
|
+
"optimize_polygon_x_alignment",
|
|
97
|
+
"round_polygon_corners",
|
|
98
|
+
"render_colored_block",
|
|
99
|
+
# RTL Utilities
|
|
100
|
+
"is_rtl_language",
|
|
101
|
+
"is_rtl_text",
|
|
102
|
+
"process_rtl_text",
|
|
103
|
+
"RTL_AVAILABLE",
|
|
104
|
+
# Timing
|
|
105
|
+
"DEFAULT_WPM",
|
|
106
|
+
"WPM_MAP",
|
|
107
|
+
"get_wpm_for_language",
|
|
108
|
+
"MIN_DISPLAY_TIME",
|
|
109
|
+
"MAX_DISPLAY_TIME",
|
|
110
|
+
"SECONDS_PER_WORD",
|
|
111
|
+
"count_words",
|
|
112
|
+
"calculate_read_time",
|
|
113
|
+
"calculate_read_times",
|
|
114
|
+
"create_frame_subtitles",
|
|
115
|
+
"can_fit_next_block",
|
|
116
|
+
"create_overlapping_frame_subtitles",
|
|
117
|
+
# Pipeline
|
|
118
|
+
"text_to_timeline_subtitles",
|
|
119
|
+
"blocks_to_timeline_subtitles",
|
|
120
|
+
"calculate_total_duration",
|
|
121
|
+
"get_timestamps",
|
|
122
|
+
"export_to_srt",
|
|
123
|
+
"text_to_overlapping_subtitles",
|
|
124
|
+
"get_overlapping_total_duration",
|
|
125
|
+
"export_overlapping_to_srt",
|
|
126
|
+
"text_to_long_image",
|
|
127
|
+
"render_text_image",
|
|
128
|
+
]
|