dynimg 0.1.9__cp311-abi3-macosx_10_12_x86_64.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.
- dynimg/__init__.py +35 -0
- dynimg/__init__.pyi +111 -0
- dynimg/_dynimg.abi3.so +0 -0
- dynimg/py.typed +0 -0
- dynimg-0.1.9.dist-info/METADATA +423 -0
- dynimg-0.1.9.dist-info/RECORD +8 -0
- dynimg-0.1.9.dist-info/WHEEL +4 -0
- dynimg-0.1.9.dist-info/licenses/LICENSE +21 -0
dynimg/__init__.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
dynimg - Fast HTML/CSS to image rendering
|
|
3
|
+
|
|
4
|
+
Example:
|
|
5
|
+
>>> import dynimg
|
|
6
|
+
>>> html = '''
|
|
7
|
+
... <html>
|
|
8
|
+
... <body style="background: linear-gradient(135deg, #667eea, #764ba2);
|
|
9
|
+
... display: flex; justify-content: center; align-items: center;
|
|
10
|
+
... height: 630px; margin: 0;">
|
|
11
|
+
... <h1 style="color: white; font-family: system-ui; font-size: 64px;">
|
|
12
|
+
... Hello World
|
|
13
|
+
... </h1>
|
|
14
|
+
... </body>
|
|
15
|
+
... </html>
|
|
16
|
+
... '''
|
|
17
|
+
>>> image = dynimg.render(html)
|
|
18
|
+
>>> image.save_png("output.png")
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from dynimg._dynimg import (
|
|
22
|
+
RenderOptions,
|
|
23
|
+
Image,
|
|
24
|
+
render,
|
|
25
|
+
render_to_file,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"RenderOptions",
|
|
30
|
+
"Image",
|
|
31
|
+
"render",
|
|
32
|
+
"render_to_file",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
__version__ = "0.1.0"
|
dynimg/__init__.pyi
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Type stubs for dynimg"""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
class RenderOptions:
|
|
6
|
+
"""Options for rendering HTML to an image"""
|
|
7
|
+
|
|
8
|
+
width: int
|
|
9
|
+
height: Optional[int]
|
|
10
|
+
scale: float
|
|
11
|
+
allow_net: bool
|
|
12
|
+
assets_dir: Optional[str]
|
|
13
|
+
base_url: Optional[str]
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
width: int = 1200,
|
|
18
|
+
height: Optional[int] = None,
|
|
19
|
+
scale: float = 2.0,
|
|
20
|
+
allow_net: bool = False,
|
|
21
|
+
assets_dir: Optional[str] = None,
|
|
22
|
+
base_url: Optional[str] = None,
|
|
23
|
+
) -> None: ...
|
|
24
|
+
|
|
25
|
+
class Image:
|
|
26
|
+
"""A rendered image with RGBA pixel data"""
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def width(self) -> int:
|
|
30
|
+
"""Image width in pixels"""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def height(self) -> int:
|
|
35
|
+
"""Image height in pixels"""
|
|
36
|
+
...
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def data(self) -> bytes:
|
|
40
|
+
"""Raw RGBA pixel data"""
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
def save_png(self, path: str) -> None:
|
|
44
|
+
"""Save the image as PNG"""
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
def save_jpeg(self, path: str, quality: int = 90) -> None:
|
|
48
|
+
"""Save the image as JPEG with the specified quality (1-100)"""
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
def save_webp(self, path: str) -> None:
|
|
52
|
+
"""Save the image as lossless WebP"""
|
|
53
|
+
...
|
|
54
|
+
|
|
55
|
+
def to_png(self) -> bytes:
|
|
56
|
+
"""Encode the image as PNG bytes"""
|
|
57
|
+
...
|
|
58
|
+
|
|
59
|
+
def to_jpeg(self, quality: int = 90) -> bytes:
|
|
60
|
+
"""Encode the image as JPEG bytes with the specified quality (1-100)"""
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
def to_webp(self) -> bytes:
|
|
64
|
+
"""Encode the image as lossless WebP bytes"""
|
|
65
|
+
...
|
|
66
|
+
|
|
67
|
+
def render(html: str, options: Optional[RenderOptions] = None) -> Image:
|
|
68
|
+
"""
|
|
69
|
+
Render HTML to an image.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
html: The HTML content to render
|
|
73
|
+
options: Rendering options (optional, uses defaults if not provided)
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
The rendered image
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
>>> import dynimg
|
|
80
|
+
>>> html = '<html><body style="background: blue;"><h1>Hello</h1></body></html>'
|
|
81
|
+
>>> image = dynimg.render(html)
|
|
82
|
+
>>> image.save_png("output.png")
|
|
83
|
+
"""
|
|
84
|
+
...
|
|
85
|
+
|
|
86
|
+
def render_to_file(
|
|
87
|
+
html: str,
|
|
88
|
+
path: str,
|
|
89
|
+
options: Optional[RenderOptions] = None,
|
|
90
|
+
quality: int = 90,
|
|
91
|
+
) -> None:
|
|
92
|
+
"""
|
|
93
|
+
Render HTML and save directly to a file.
|
|
94
|
+
|
|
95
|
+
The output format is detected from the file extension.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
html: The HTML content to render
|
|
99
|
+
path: Output file path (.png, .jpg, .webp)
|
|
100
|
+
options: Rendering options (optional)
|
|
101
|
+
quality: JPEG quality 1-100 (default: 90, ignored for PNG/WebP)
|
|
102
|
+
|
|
103
|
+
Example:
|
|
104
|
+
>>> import dynimg
|
|
105
|
+
>>> html = '<html><body><h1>Hello</h1></body></html>'
|
|
106
|
+
>>> dynimg.render_to_file(html, "output.png")
|
|
107
|
+
"""
|
|
108
|
+
...
|
|
109
|
+
|
|
110
|
+
__version__: str
|
|
111
|
+
__all__: list[str]
|
dynimg/_dynimg.abi3.so
ADDED
|
Binary file
|
dynimg/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dynimg
|
|
3
|
+
Version: 0.1.9
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Operating System :: MacOS
|
|
8
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Rust
|
|
14
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
15
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Summary: A fast library for rendering HTML/CSS to images
|
|
18
|
+
Keywords: html,css,image,render,screenshot,og-image
|
|
19
|
+
License: MIT
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
22
|
+
Project-URL: Homepage, https://github.com/blopker/dynimg
|
|
23
|
+
Project-URL: Repository, https://github.com/blopker/dynimg
|
|
24
|
+
|
|
25
|
+
# dynimg
|
|
26
|
+
|
|
27
|
+
A fast library and CLI for rendering HTML/CSS to images. Use from Python, Rust, or the command line. Built on [Blitz](https://github.com/DioxusLabs/blitz), a modular Rust rendering engine.
|
|
28
|
+
|
|
29
|
+
Perfect for generating dynamic images like Open Graph (OG) images, social media cards, email headers, and more.
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- **Python + Rust + CLI**: Use from Python, as a Rust library, or command-line tool
|
|
34
|
+
- **Multiple output formats**: PNG, WebP (lossless), and JPEG
|
|
35
|
+
- **High-quality rendering**: Configurable scale factor for retina displays
|
|
36
|
+
- **Fast**: Native Rust performance with no browser overhead
|
|
37
|
+
- **Secure by default**: Network and filesystem access disabled unless explicitly enabled
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
### Python
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install dynimg
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Rust CLI
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cargo install dynimg
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Rust Library
|
|
54
|
+
|
|
55
|
+
```toml
|
|
56
|
+
[dependencies]
|
|
57
|
+
dynimg = "0.1"
|
|
58
|
+
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Library Usage
|
|
62
|
+
|
|
63
|
+
```rust
|
|
64
|
+
use dynimg::{render, RenderOptions};
|
|
65
|
+
|
|
66
|
+
#[tokio::main]
|
|
67
|
+
async fn main() -> Result<(), dynimg::Error> {
|
|
68
|
+
let html = r#"
|
|
69
|
+
<html>
|
|
70
|
+
<body style="background: linear-gradient(135deg, #667eea, #764ba2);
|
|
71
|
+
display: flex; justify-content: center; align-items: center;
|
|
72
|
+
height: 630px; margin: 0;">
|
|
73
|
+
<h1 style="color: white; font-family: system-ui; font-size: 64px;">
|
|
74
|
+
Hello World
|
|
75
|
+
</h1>
|
|
76
|
+
</body>
|
|
77
|
+
</html>
|
|
78
|
+
"#;
|
|
79
|
+
|
|
80
|
+
// Render with default options (1200×auto viewport, 2x scale)
|
|
81
|
+
let image = render(html, RenderOptions::default()).await?;
|
|
82
|
+
|
|
83
|
+
// Save as PNG
|
|
84
|
+
image.save_png("output.png")?;
|
|
85
|
+
|
|
86
|
+
// Or get raw bytes
|
|
87
|
+
let png_bytes = image.to_png()?;
|
|
88
|
+
let webp_bytes = image.to_webp();
|
|
89
|
+
let jpeg_bytes = image.to_jpeg(90)?;
|
|
90
|
+
|
|
91
|
+
Ok(())
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Configuration
|
|
96
|
+
|
|
97
|
+
```rust
|
|
98
|
+
use dynimg::RenderOptions;
|
|
99
|
+
|
|
100
|
+
// Using builder pattern
|
|
101
|
+
let options = RenderOptions::default()
|
|
102
|
+
.width(1200)
|
|
103
|
+
.height(630)
|
|
104
|
+
.scale(2.0)
|
|
105
|
+
.allow_net()
|
|
106
|
+
.assets_dir("./assets");
|
|
107
|
+
|
|
108
|
+
// Or struct initialization
|
|
109
|
+
let options = RenderOptions {
|
|
110
|
+
width: 1200,
|
|
111
|
+
height: Some(630),
|
|
112
|
+
scale: 2.0,
|
|
113
|
+
allow_net: true,
|
|
114
|
+
assets_dir: Some("./assets".into()),
|
|
115
|
+
base_url: None,
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Convenience function
|
|
120
|
+
|
|
121
|
+
```rust
|
|
122
|
+
use dynimg::{render_to_file, RenderOptions};
|
|
123
|
+
|
|
124
|
+
// Render directly to a file (format detected from extension)
|
|
125
|
+
render_to_file(html, "output.png", RenderOptions::default(), 90).await?;
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## CLI Usage
|
|
129
|
+
|
|
130
|
+
### Basic Usage
|
|
131
|
+
|
|
132
|
+
Render an HTML file to PNG:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
dynimg input.html -o output.png
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Output Formats
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# PNG (lossless)
|
|
142
|
+
dynimg input.html -o image.png
|
|
143
|
+
|
|
144
|
+
# WebP (lossless)
|
|
145
|
+
dynimg input.html -o image.webp
|
|
146
|
+
|
|
147
|
+
# JPEG (lossy)
|
|
148
|
+
dynimg input.html -o image.jpg --quality 90
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Image Dimensions
|
|
152
|
+
|
|
153
|
+
The `--width` and `--height` options set the **viewport size** (CSS layout dimensions). The actual output image is scaled by the `--scale` factor (default: 2x for high-DPI/retina displays).
|
|
154
|
+
|
|
155
|
+
**Output image size = viewport × scale**
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# Default: 1200px viewport → 2400px output (at 2x scale)
|
|
159
|
+
dynimg input.html -o output.png
|
|
160
|
+
|
|
161
|
+
# OG image: 1200×630 viewport → 2400×1260 output
|
|
162
|
+
dynimg input.html -o output.png --width 1200 --height 630
|
|
163
|
+
|
|
164
|
+
# 1x scale for exact pixel dimensions (1200×630 output)
|
|
165
|
+
dynimg input.html -o output.png --width 1200 --height 630 --scale 1
|
|
166
|
+
|
|
167
|
+
# 3x scale for extra-high-DPI (3600×1890 output)
|
|
168
|
+
dynimg input.html -o output.png --width 1200 --height 630 --scale 3
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Your HTML/CSS should use the viewport dimensions (e.g., `width: 1200px`) - the scale factor handles the high-resolution rendering.
|
|
172
|
+
|
|
173
|
+
### Reading from stdin
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
echo '<html><body><h1>Hello</h1></body></html>' | dynimg - -o output.png
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Loading External Resources
|
|
180
|
+
|
|
181
|
+
By default, network and filesystem access are disabled for security. Enable them to load images, fonts, and other resources:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Load images/fonts from URLs
|
|
185
|
+
dynimg input.html -o output.png --allow-net
|
|
186
|
+
|
|
187
|
+
# Load images/fonts from a local assets directory
|
|
188
|
+
dynimg input.html -o output.png --assets ./assets
|
|
189
|
+
|
|
190
|
+
# Allow both
|
|
191
|
+
dynimg input.html -o output.png --allow-net --assets ./assets
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
When using `--assets`, all local paths are resolved relative to the asset directory. Attempts to load files outside this directory will error:
|
|
195
|
+
|
|
196
|
+
```html
|
|
197
|
+
<!-- With --assets ./assets -->
|
|
198
|
+
<img src="logo.png"> <!-- loads ./assets/logo.png -->
|
|
199
|
+
<img src="img/hero.png"> <!-- loads ./assets/img/hero.png -->
|
|
200
|
+
<img src="../secret.png"> <!-- ERROR: outside assets directory -->
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
For self-contained templates, consider using inline base64 data URIs instead:
|
|
204
|
+
|
|
205
|
+
```html
|
|
206
|
+
<img src="data:image/png;base64,iVBORw0KGgo...">
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## CLI Reference
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
dynimg [OPTIONS] <INPUT> -o <OUTPUT>
|
|
213
|
+
|
|
214
|
+
Arguments:
|
|
215
|
+
<INPUT> HTML file path or '-' for stdin
|
|
216
|
+
|
|
217
|
+
Options:
|
|
218
|
+
-o, --output <FILE> Output image path (format detected from extension)
|
|
219
|
+
-w, --width <PIXELS> Viewport width in CSS pixels [default: 1200]
|
|
220
|
+
-H, --height <PIXELS> Viewport height in CSS pixels [default: document height]
|
|
221
|
+
-s, --scale <FACTOR> Scale multiplier for output (2 = 2x resolution) [default: 2]
|
|
222
|
+
-q, --quality <1-100> JPEG quality [default: 90]
|
|
223
|
+
--allow-net Allow network access for loading remote resources
|
|
224
|
+
--assets <DIR> Asset directory for local resources
|
|
225
|
+
-v, --verbose Enable verbose logging
|
|
226
|
+
--help Print help
|
|
227
|
+
--version Print version
|
|
228
|
+
|
|
229
|
+
Options can also be set via HTML meta tags (see below). CLI flags override meta tags.
|
|
230
|
+
|
|
231
|
+
Note: Output image dimensions = viewport × scale. A 1200×630 viewport at 2x scale produces a 2400×1260 image.
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Python Usage
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
import dynimg
|
|
238
|
+
|
|
239
|
+
html = """
|
|
240
|
+
<html>
|
|
241
|
+
<body style="background: linear-gradient(135deg, #667eea, #764ba2);
|
|
242
|
+
display: flex; justify-content: center; align-items: center;
|
|
243
|
+
height: 630px; margin: 0;">
|
|
244
|
+
<h1 style="color: white; font-family: system-ui; font-size: 64px;">
|
|
245
|
+
Hello World
|
|
246
|
+
</h1>
|
|
247
|
+
</body>
|
|
248
|
+
</html>
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
# Render with default options
|
|
252
|
+
image = dynimg.render(html)
|
|
253
|
+
|
|
254
|
+
# Save to file
|
|
255
|
+
image.save("output.png")
|
|
256
|
+
|
|
257
|
+
# Or get bytes
|
|
258
|
+
png_bytes = image.to_png()
|
|
259
|
+
webp_bytes = image.to_webp()
|
|
260
|
+
jpeg_bytes = image.to_jpeg(quality=90)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Configuration
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
import dynimg
|
|
267
|
+
|
|
268
|
+
options = dynimg.RenderOptions(
|
|
269
|
+
width=1200, # Viewport width (default: 1200)
|
|
270
|
+
height=630, # Viewport height (default: auto)
|
|
271
|
+
scale=2.0, # Output scale factor (default: 2.0)
|
|
272
|
+
allow_net=True, # Allow network requests (default: False)
|
|
273
|
+
assets_dir="./assets", # Local assets directory (default: None)
|
|
274
|
+
base_url="https://example.com", # Base URL for relative URLs (default: None)
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
image = dynimg.render(html, options)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Direct File Output
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
# Render directly to a file (format detected from extension)
|
|
284
|
+
dynimg.render_to_file(html, "output.png")
|
|
285
|
+
|
|
286
|
+
# With options
|
|
287
|
+
dynimg.render_to_file(html, "output.png", options=options)
|
|
288
|
+
|
|
289
|
+
# JPEG with quality setting
|
|
290
|
+
dynimg.render_to_file(html, "output.jpg", quality=90)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Image Properties
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
image = dynimg.render(html)
|
|
297
|
+
print(f"Size: {image.width}x{image.height}")
|
|
298
|
+
print(f"Bytes: {len(image.data)}")
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## HTML Meta Tags
|
|
302
|
+
|
|
303
|
+
You can configure rendering options directly in your HTML using meta tags. CLI flags take precedence over meta tags.
|
|
304
|
+
|
|
305
|
+
```html
|
|
306
|
+
<meta name="dynimg:width" content="1200"> <!-- viewport width -->
|
|
307
|
+
<meta name="dynimg:height" content="630"> <!-- viewport height -->
|
|
308
|
+
<meta name="dynimg:scale" content="2"> <!-- output multiplier -->
|
|
309
|
+
<meta name="dynimg:quality" content="90"> <!-- JPEG quality -->
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
This is useful for templates that should always render at specific dimensions. Remember: the output image size is viewport × scale.
|
|
313
|
+
|
|
314
|
+
## Example HTML Template
|
|
315
|
+
|
|
316
|
+
```html
|
|
317
|
+
<!DOCTYPE html>
|
|
318
|
+
<html>
|
|
319
|
+
<head>
|
|
320
|
+
<meta name="dynimg:width" content="1200">
|
|
321
|
+
<meta name="dynimg:height" content="630">
|
|
322
|
+
<style>
|
|
323
|
+
.container {
|
|
324
|
+
width: 1200px;
|
|
325
|
+
height: 630px;
|
|
326
|
+
display: flex;
|
|
327
|
+
flex-direction: column;
|
|
328
|
+
justify-content: center;
|
|
329
|
+
align-items: center;
|
|
330
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
331
|
+
font-family: system-ui, sans-serif;
|
|
332
|
+
}
|
|
333
|
+
h1 {
|
|
334
|
+
color: white;
|
|
335
|
+
font-size: 64px;
|
|
336
|
+
margin: 0;
|
|
337
|
+
}
|
|
338
|
+
p {
|
|
339
|
+
color: rgba(255,255,255,0.8);
|
|
340
|
+
font-size: 32px;
|
|
341
|
+
}
|
|
342
|
+
</style>
|
|
343
|
+
</head>
|
|
344
|
+
<body>
|
|
345
|
+
<div class="container">
|
|
346
|
+
<h1>Hello World</h1>
|
|
347
|
+
<p>Welcome to my site</p>
|
|
348
|
+
</div>
|
|
349
|
+
</body>
|
|
350
|
+
</html>
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Supported CSS Features
|
|
354
|
+
|
|
355
|
+
dynimg uses Blitz for rendering, which supports:
|
|
356
|
+
|
|
357
|
+
- Flexbox and Grid layouts
|
|
358
|
+
- CSS variables
|
|
359
|
+
- Media queries
|
|
360
|
+
- Complex selectors
|
|
361
|
+
- Gradients and shadows
|
|
362
|
+
- Web fonts (via `@font-face`, requires `--allow-net` or `--assets`)
|
|
363
|
+
- Images (requires `--allow-net` or `--assets`, or use data URIs)
|
|
364
|
+
|
|
365
|
+
## Performance
|
|
366
|
+
|
|
367
|
+
dynimg is designed for speed:
|
|
368
|
+
|
|
369
|
+
- No browser startup overhead
|
|
370
|
+
- Native Rust rendering pipeline
|
|
371
|
+
- Efficient image encoding
|
|
372
|
+
|
|
373
|
+
Typical rendering time: 50-200ms depending on complexity.
|
|
374
|
+
|
|
375
|
+
## Development
|
|
376
|
+
|
|
377
|
+
### Building
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
# Build CLI
|
|
381
|
+
cargo build --release
|
|
382
|
+
|
|
383
|
+
# Build Python wheel
|
|
384
|
+
pip install maturin
|
|
385
|
+
maturin build --release --features python
|
|
386
|
+
|
|
387
|
+
# Install locally for development
|
|
388
|
+
maturin develop --features python
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Running Tests
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
cargo test
|
|
395
|
+
cargo clippy -- -D warnings
|
|
396
|
+
cargo fmt -- --check
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## Releasing
|
|
400
|
+
|
|
401
|
+
Releases are automated via GitHub Actions. To create a new release:
|
|
402
|
+
|
|
403
|
+
1. Update the version in `Cargo.toml`
|
|
404
|
+
2. Create and push a git tag:
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
git tag v0.1.0
|
|
408
|
+
git push origin v0.1.0
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
This triggers the release workflow which:
|
|
412
|
+
- Builds wheels for Linux (x86_64, aarch64) and macOS (x86_64, aarch64)
|
|
413
|
+
- Creates a GitHub Release with all artifacts
|
|
414
|
+
- (Optional) Publishes to PyPI (when enabled)
|
|
415
|
+
|
|
416
|
+
## License
|
|
417
|
+
|
|
418
|
+
MIT
|
|
419
|
+
|
|
420
|
+
## AI Warning
|
|
421
|
+
|
|
422
|
+
This is AI slop, if you want to use it, fork and make it your own!
|
|
423
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
dynimg/__init__.py,sha256=0aKwVNQaUq9AbeafWxnOLwl-ge_cOUpfUU6fFivYopA,768
|
|
2
|
+
dynimg/__init__.pyi,sha256=7gWC_cE0XjlRKHUiDFrOoPLKistMje89FRj6ndgVpDQ,2714
|
|
3
|
+
dynimg/_dynimg.abi3.so,sha256=9VyB1X7Oksj_QGXXeFlV_idlClB37td61wdXfusKUpA,17221708
|
|
4
|
+
dynimg/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
dynimg-0.1.9.dist-info/METADATA,sha256=06UgILDNEona3KhsXOhTomrf0-eFcTTXOPcPWCycu2A,10801
|
|
6
|
+
dynimg-0.1.9.dist-info/WHEEL,sha256=kXxrpAlDxFfJk3NKudODw2af-hZi5kEF-I_4llGgByk,106
|
|
7
|
+
dynimg-0.1.9.dist-info/licenses/LICENSE,sha256=PQMmij6bMT3ZG29qvpImWYE-PX-a2lvznHr8obLAfxc,1080
|
|
8
|
+
dynimg-0.1.9.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) BO LLC, https://bollc.co
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|