table-renderer 0.2.0__tar.gz → 0.3.0__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.
- {table_renderer-0.2.0 → table_renderer-0.3.0}/PKG-INFO +4 -1
- {table_renderer-0.2.0 → table_renderer-0.3.0}/README.md +3 -0
- {table_renderer-0.2.0 → table_renderer-0.3.0}/pyproject.toml +1 -1
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/__init__.py +1 -1
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/models/table.py +22 -5
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/renderer.py +29 -27
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/models/__init__.py +0 -0
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/models/base.py +0 -0
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/models/cell.py +0 -0
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/models/column.py +0 -0
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/models/row.py +0 -0
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/models/style.py +0 -0
- {table_renderer-0.2.0 → table_renderer-0.3.0}/src/table_renderer/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: table-renderer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A Python library for rendering structured tables as high-quality images or HTML.
|
|
5
5
|
Keywords: table,renderer,rendering,image,html,weasyprint,pdfium,report
|
|
6
6
|
Author: pTaunium
|
|
@@ -174,6 +174,9 @@ Fine-tune your output image quality and margins.
|
|
|
174
174
|
# High-res JPG with custom 20px padding
|
|
175
175
|
table.to_image("output.jpg", dpi=300, padding=20)
|
|
176
176
|
|
|
177
|
+
# PNG with a solid white background (instead of the default transparent)
|
|
178
|
+
table.to_image("output_white.png", background_color="white")
|
|
179
|
+
|
|
177
180
|
# Lightweight WebP with tight margins
|
|
178
181
|
table.to_image("output.webp", dpi=72, padding=0)
|
|
179
182
|
```
|
|
@@ -151,6 +151,9 @@ Fine-tune your output image quality and margins.
|
|
|
151
151
|
# High-res JPG with custom 20px padding
|
|
152
152
|
table.to_image("output.jpg", dpi=300, padding=20)
|
|
153
153
|
|
|
154
|
+
# PNG with a solid white background (instead of the default transparent)
|
|
155
|
+
table.to_image("output_white.png", background_color="white")
|
|
156
|
+
|
|
154
157
|
# Lightweight WebP with tight margins
|
|
155
158
|
table.to_image("output.webp", dpi=72, padding=0)
|
|
156
159
|
```
|
|
@@ -6,6 +6,6 @@ try:
|
|
|
6
6
|
__version__ = importlib.metadata.version("table-renderer")
|
|
7
7
|
except importlib.metadata.PackageNotFoundError:
|
|
8
8
|
# Package is not installed (e.g. during local development without pip install -e .)
|
|
9
|
-
__version__ = "0.
|
|
9
|
+
__version__ = "0.3.0"
|
|
10
10
|
|
|
11
11
|
__all__ = ["Cell", "Column", "Row", "Style", "StyledObject", "Table", "__version__"]
|
|
@@ -25,7 +25,7 @@ class Table(StyledObject):
|
|
|
25
25
|
self._cells = [[Cell() for _ in range(cols)] for _ in range(rows)]
|
|
26
26
|
self._row_objects = [Row(i) for i in range(rows)]
|
|
27
27
|
self._col_objects = [Column(i) for i in range(cols)]
|
|
28
|
-
self.width: int | str = "
|
|
28
|
+
self.width: int | str = "auto"
|
|
29
29
|
self.font_files: list[str] = []
|
|
30
30
|
|
|
31
31
|
def cell(self, row_index: int, col_index: int) -> Cell:
|
|
@@ -112,7 +112,14 @@ class Table(StyledObject):
|
|
|
112
112
|
self.font_files.append(font_path)
|
|
113
113
|
return self
|
|
114
114
|
|
|
115
|
-
def to_image(
|
|
115
|
+
def to_image(
|
|
116
|
+
self,
|
|
117
|
+
output_path: str,
|
|
118
|
+
*,
|
|
119
|
+
dpi: int = 144,
|
|
120
|
+
padding: int = 10,
|
|
121
|
+
background_color: str = "transparent",
|
|
122
|
+
) -> None:
|
|
116
123
|
"""
|
|
117
124
|
Render the table to an image file.
|
|
118
125
|
|
|
@@ -120,17 +127,27 @@ class Table(StyledObject):
|
|
|
120
127
|
output_path: Path to the output file (e.g., 'table.png', 'table.webp').
|
|
121
128
|
dpi: Resolution of the output image.
|
|
122
129
|
padding: Padding around the table in pixels.
|
|
130
|
+
background_color: Background color of the image.
|
|
123
131
|
"""
|
|
124
|
-
render_to_image(
|
|
132
|
+
render_to_image(
|
|
133
|
+
self,
|
|
134
|
+
output_path,
|
|
135
|
+
dpi=dpi,
|
|
136
|
+
padding=padding,
|
|
137
|
+
background_color=background_color,
|
|
138
|
+
)
|
|
125
139
|
|
|
126
|
-
def to_html(
|
|
140
|
+
def to_html(
|
|
141
|
+
self, output_path: str, *, background_color: str = "transparent"
|
|
142
|
+
) -> None:
|
|
127
143
|
"""
|
|
128
144
|
Export the table to an HTML file.
|
|
129
145
|
|
|
130
146
|
Args:
|
|
131
147
|
output_path: Path to the output HTML file.
|
|
148
|
+
background_color: Background color of the HTML body.
|
|
132
149
|
"""
|
|
133
|
-
save_html(self, output_path)
|
|
150
|
+
save_html(self, output_path, background_color=background_color)
|
|
134
151
|
|
|
135
152
|
def _prepare_render(self) -> None:
|
|
136
153
|
"""Handle merging logic and cascading styles before rendering."""
|
|
@@ -19,7 +19,7 @@ HTML_TEMPLATE = """
|
|
|
19
19
|
body {
|
|
20
20
|
margin: 0;
|
|
21
21
|
padding: 20px;
|
|
22
|
-
background-color:
|
|
22
|
+
background-color: {{ background_color }};
|
|
23
23
|
}
|
|
24
24
|
{% for font in font_faces %}
|
|
25
25
|
@font-face {
|
|
@@ -37,7 +37,14 @@ table {
|
|
|
37
37
|
td {
|
|
38
38
|
padding: 8px;
|
|
39
39
|
box-sizing: border-box;
|
|
40
|
+
{{ table_style }}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
{% for row in rows %}
|
|
44
|
+
.row-{{ row.index }} {
|
|
45
|
+
{{ row.style }}
|
|
40
46
|
}
|
|
47
|
+
{% endfor %}
|
|
41
48
|
|
|
42
49
|
{% for col in columns %}
|
|
43
50
|
.col-{{ col.index }} {
|
|
@@ -45,12 +52,6 @@ td {
|
|
|
45
52
|
{{ col.style }}
|
|
46
53
|
}
|
|
47
54
|
{% endfor %}
|
|
48
|
-
|
|
49
|
-
{% for row in rows %}
|
|
50
|
-
.row-{{ row.index }} {
|
|
51
|
-
{{ row.style }}
|
|
52
|
-
}
|
|
53
|
-
{% endfor %}
|
|
54
55
|
</style>
|
|
55
56
|
</head>
|
|
56
57
|
<body>
|
|
@@ -60,10 +61,10 @@ td {
|
|
|
60
61
|
{% for c_idx in range(cells[r_idx]|length) %}
|
|
61
62
|
{% set cell = cells[r_idx][c_idx] %}
|
|
62
63
|
{% if not cell.is_merged %}
|
|
63
|
-
<td class="col-{{ c_idx }}"
|
|
64
|
+
<td class="row-{{ r_idx }} col-{{ c_idx }}"
|
|
64
65
|
rowspan="{{ cell.row_span }}"
|
|
65
66
|
colspan="{{ cell.col_span }}"
|
|
66
|
-
style="{{ cell.
|
|
67
|
+
style="{{ cell.style.to_css() }}">
|
|
67
68
|
{% if cell.image_url %}
|
|
68
69
|
<img src="{{ cell.image_url }}"
|
|
69
70
|
style="{% if cell.image_width %}width: {{ cell.image_width }}px;{% endif %}
|
|
@@ -82,12 +83,13 @@ td {
|
|
|
82
83
|
"""
|
|
83
84
|
|
|
84
85
|
|
|
85
|
-
def render_to_html(table: "Table") -> str:
|
|
86
|
+
def render_to_html(table: "Table", *, background_color: str = "transparent") -> str:
|
|
86
87
|
"""
|
|
87
88
|
Generate the HTML representation of the table.
|
|
88
89
|
|
|
89
90
|
Args:
|
|
90
91
|
table: The Table object to render.
|
|
92
|
+
background_color: The background color of the body.
|
|
91
93
|
|
|
92
94
|
Returns:
|
|
93
95
|
A string containing the complete HTML document.
|
|
@@ -107,12 +109,6 @@ def render_to_html(table: "Table") -> str:
|
|
|
107
109
|
row_data = []
|
|
108
110
|
for col_index in range(len(table._cells[0])):
|
|
109
111
|
cell = table._cells[row_index][col_index]
|
|
110
|
-
row = table.get_row(row_index)
|
|
111
|
-
col = table.get_column(col_index)
|
|
112
|
-
|
|
113
|
-
# Cascading: Table -> Row/Col -> Cell
|
|
114
|
-
base_style = table.style.merge(col.style).merge(row.style)
|
|
115
|
-
final_style = base_style.merge(cell.style)
|
|
116
112
|
|
|
117
113
|
# Handle Image URL resolution
|
|
118
114
|
cell.image_url = ""
|
|
@@ -123,8 +119,6 @@ def render_to_html(table: "Table") -> str:
|
|
|
123
119
|
abs_img_path = os.path.abspath(cell.image_path)
|
|
124
120
|
cell.image_url = f"file://{abs_img_path}"
|
|
125
121
|
|
|
126
|
-
# Attach final style string for template
|
|
127
|
-
cell.final_style = final_style.to_css()
|
|
128
122
|
row_data.append(cell)
|
|
129
123
|
cells_data.append(row_data)
|
|
130
124
|
|
|
@@ -151,6 +145,7 @@ def render_to_html(table: "Table") -> str:
|
|
|
151
145
|
return template.render(
|
|
152
146
|
page_width=estimated_width,
|
|
153
147
|
page_height=estimated_height,
|
|
148
|
+
background_color=background_color,
|
|
154
149
|
table_width=f"{table.width}px" if isinstance(table.width, int) else table.width,
|
|
155
150
|
table_style=table.style.to_css(),
|
|
156
151
|
font_faces=font_faces,
|
|
@@ -175,6 +170,7 @@ def render_to_image(
|
|
|
175
170
|
*,
|
|
176
171
|
dpi: int = 144,
|
|
177
172
|
padding: int = 10,
|
|
173
|
+
background_color: str = "transparent",
|
|
178
174
|
) -> None:
|
|
179
175
|
"""
|
|
180
176
|
Render the table to an image file.
|
|
@@ -184,8 +180,9 @@ def render_to_image(
|
|
|
184
180
|
output_path: Destination path for the image.
|
|
185
181
|
dpi: Target resolution.
|
|
186
182
|
padding: Margin around the table.
|
|
183
|
+
background_color: Background color of the image.
|
|
187
184
|
"""
|
|
188
|
-
html_content = render_to_html(table)
|
|
185
|
+
html_content = render_to_html(table, background_color=background_color)
|
|
189
186
|
# WeasyPrint v53+ removed write_png, so we render to PDF then convert to PNG
|
|
190
187
|
pdf_bytes = HTML(string=html_content).write_pdf()
|
|
191
188
|
|
|
@@ -220,17 +217,19 @@ def render_to_image(
|
|
|
220
217
|
y_offset += img.height
|
|
221
218
|
|
|
222
219
|
# Visual Auto-Crop: Find the bounding box of non-white pixels
|
|
223
|
-
#
|
|
224
|
-
bg = Image.new("RGB", pil_image.size, (255, 255, 255))
|
|
220
|
+
# Use 'L' (grayscale) mode to reduce memory usage (1 byte per pixel vs 3)
|
|
225
221
|
if pil_image.mode == "RGBA":
|
|
226
|
-
|
|
222
|
+
# Flatten RGBA onto a white grayscale background
|
|
223
|
+
grayscale = Image.new("L", pil_image.size, 255)
|
|
224
|
+
grayscale.paste(pil_image.convert("L"), mask=pil_image.getchannel("A"))
|
|
227
225
|
else:
|
|
228
|
-
|
|
226
|
+
# For RGB or other modes, just convert to grayscale
|
|
227
|
+
grayscale = pil_image.convert("L")
|
|
229
228
|
|
|
230
|
-
#
|
|
229
|
+
# Invert and find bbox of "ink" (non-white pixels)
|
|
231
230
|
import PIL.ImageOps
|
|
232
231
|
|
|
233
|
-
inverted = PIL.ImageOps.invert(
|
|
232
|
+
inverted = PIL.ImageOps.invert(grayscale)
|
|
234
233
|
bbox = inverted.getbbox()
|
|
235
234
|
|
|
236
235
|
if bbox:
|
|
@@ -252,14 +251,17 @@ def render_to_image(
|
|
|
252
251
|
pil_image.save(output_path)
|
|
253
252
|
|
|
254
253
|
|
|
255
|
-
def save_html(
|
|
254
|
+
def save_html(
|
|
255
|
+
table: "Table", output_path: str, *, background_color: str = "transparent"
|
|
256
|
+
) -> None:
|
|
256
257
|
"""
|
|
257
258
|
Save the table's HTML representation to a file.
|
|
258
259
|
|
|
259
260
|
Args:
|
|
260
261
|
table: The Table object to export.
|
|
261
262
|
output_path: Path to the destination HTML file.
|
|
263
|
+
background_color: Background color of the HTML body.
|
|
262
264
|
"""
|
|
263
|
-
html_content = render_to_html(table)
|
|
265
|
+
html_content = render_to_html(table, background_color=background_color)
|
|
264
266
|
with open(output_path, "w", encoding="utf-8") as f:
|
|
265
267
|
f.write(html_content)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|