dynimg 0.1.10__tar.gz → 0.1.11__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 (46) hide show
  1. {dynimg-0.1.10 → dynimg-0.1.11}/Cargo.lock +1 -1
  2. {dynimg-0.1.10 → dynimg-0.1.11}/Cargo.toml +1 -1
  3. {dynimg-0.1.10 → dynimg-0.1.11}/PKG-INFO +1 -1
  4. {dynimg-0.1.10 → dynimg-0.1.11}/examples/google-fonts.html +1 -1
  5. {dynimg-0.1.10 → dynimg-0.1.11}/pyproject.toml +1 -1
  6. {dynimg-0.1.10 → dynimg-0.1.11}/scripts/render-examples.sh +2 -0
  7. {dynimg-0.1.10 → dynimg-0.1.11}/src/lib.rs +26 -15
  8. {dynimg-0.1.10 → dynimg-0.1.11}/.claude/settings.local.json +0 -0
  9. {dynimg-0.1.10 → dynimg-0.1.11}/.github/workflows/build-wheels.yml +0 -0
  10. {dynimg-0.1.10 → dynimg-0.1.11}/.github/workflows/ci.yml +0 -0
  11. {dynimg-0.1.10 → dynimg-0.1.11}/.github/workflows/release.yml +0 -0
  12. {dynimg-0.1.10 → dynimg-0.1.11}/.gitignore +0 -0
  13. {dynimg-0.1.10 → dynimg-0.1.11}/.pearls/CLAUDE.md +0 -0
  14. {dynimg-0.1.10 → dynimg-0.1.11}/.pearls/issues.jsonl +0 -0
  15. {dynimg-0.1.10 → dynimg-0.1.11}/CLAUDE.md +0 -0
  16. {dynimg-0.1.10 → dynimg-0.1.11}/LICENSE +0 -0
  17. {dynimg-0.1.10 → dynimg-0.1.11}/Makefile +0 -0
  18. {dynimg-0.1.10 → dynimg-0.1.11}/README.md +0 -0
  19. {dynimg-0.1.10 → dynimg-0.1.11}/codebook.toml +0 -0
  20. {dynimg-0.1.10 → dynimg-0.1.11}/examples/assets/PlaywriteINGuides-Regular.ttf +0 -0
  21. {dynimg-0.1.10 → dynimg-0.1.11}/examples/assets/RobotoMono-Bold.ttf +0 -0
  22. {dynimg-0.1.10 → dynimg-0.1.11}/examples/assets/RobotoMono-Bold.woff2 +0 -0
  23. {dynimg-0.1.10 → dynimg-0.1.11}/examples/assets/logo.svg +0 -0
  24. {dynimg-0.1.10 → dynimg-0.1.11}/examples/assets/servo.css +0 -0
  25. {dynimg-0.1.10 → dynimg-0.1.11}/examples/assets/style.css +0 -0
  26. {dynimg-0.1.10 → dynimg-0.1.11}/examples/inline-only.html +0 -0
  27. {dynimg-0.1.10 → dynimg-0.1.11}/examples/local-assets.html +0 -0
  28. {dynimg-0.1.10 → dynimg-0.1.11}/examples/local-font-woff2.html +0 -0
  29. {dynimg-0.1.10 → dynimg-0.1.11}/examples/local-font.html +0 -0
  30. {dynimg-0.1.10 → dynimg-0.1.11}/examples/mixed-assets.html +0 -0
  31. {dynimg-0.1.10 → dynimg-0.1.11}/examples/og-image.html +0 -0
  32. {dynimg-0.1.10 → dynimg-0.1.11}/examples/quote.html +0 -0
  33. {dynimg-0.1.10 → dynimg-0.1.11}/examples/remote-image.html +0 -0
  34. {dynimg-0.1.10 → dynimg-0.1.11}/examples/servo.html +0 -0
  35. {dynimg-0.1.10 → dynimg-0.1.11}/examples/social-card.html +0 -0
  36. {dynimg-0.1.10 → dynimg-0.1.11}/python/dynimg/__init__.py +0 -0
  37. {dynimg-0.1.10 → dynimg-0.1.11}/python/dynimg/__init__.pyi +0 -0
  38. {dynimg-0.1.10 → dynimg-0.1.11}/python/dynimg/py.typed +0 -0
  39. {dynimg-0.1.10 → dynimg-0.1.11}/src/main.rs +0 -0
  40. {dynimg-0.1.10 → dynimg-0.1.11}/src/python.rs +0 -0
  41. {dynimg-0.1.10 → dynimg-0.1.11}/test_wheels/.gitignore +0 -0
  42. {dynimg-0.1.10 → dynimg-0.1.11}/test_wheels/README.md +0 -0
  43. {dynimg-0.1.10 → dynimg-0.1.11}/test_wheels/debug_parser.py +0 -0
  44. {dynimg-0.1.10 → dynimg-0.1.11}/test_wheels/debug_verbose.py +0 -0
  45. {dynimg-0.1.10 → dynimg-0.1.11}/test_wheels/test_dynimg.py +0 -0
  46. {dynimg-0.1.10 → dynimg-0.1.11}/test_wheels/test_from_ci.sh +0 -0
@@ -630,7 +630,7 @@ dependencies = [
630
630
 
631
631
  [[package]]
632
632
  name = "dynimg"
633
- version = "0.1.10"
633
+ version = "0.1.11"
634
634
  dependencies = [
635
635
  "anyhow",
636
636
  "anyrender",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "dynimg"
3
- version = "0.1.10"
3
+ version = "0.1.11"
4
4
  edition = "2024"
5
5
  description = "A fast library and CLI for rendering HTML/CSS to images"
6
6
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dynimg
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -62,7 +62,7 @@
62
62
  <h1>Google Fonts Example</h1>
63
63
  <p>
64
64
  This example attempts to use
65
- <span class="highlight">Playfair Display</span> and
65
+ <span class="highlight">Playwrite IN Guides</span> and
66
66
  <span class="highlight">Inter</span> from Google Fonts.
67
67
  </p>
68
68
  <div class="note">
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "dynimg"
7
- version = "0.1.10"
7
+ version = "0.1.11"
8
8
  description = "A fast library for rendering HTML/CSS to images"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -71,6 +71,7 @@ echo ""
71
71
  echo "--- Mixed Assets (requires both flags) ---"
72
72
  run_test "Without flags" false "$DYNIMG" "$EXAMPLES_DIR/mixed-assets.html" -o "$OUTPUT_DIR/mixed-no-flags.png"
73
73
  run_test "With --allow-net only" false "$DYNIMG" "$EXAMPLES_DIR/mixed-assets.html" -o "$OUTPUT_DIR/mixed-net-only.png" --allow-net
74
+ run_test "With --allow-net only" false "$DYNIMG" "$EXAMPLES_DIR/mixed-assets.html" -o "$OUTPUT_DIR/mixed-net-only.webp" --allow-net
74
75
  run_test "With --assets only" false "$DYNIMG" "$EXAMPLES_DIR/mixed-assets.html" -o "$OUTPUT_DIR/mixed-assets-only.png" --assets "$ASSETS_DIR"
75
76
  run_test "With both flags" false "$DYNIMG" "$EXAMPLES_DIR/mixed-assets.html" -o "$OUTPUT_DIR/mixed-both-flags.png" --allow-net --assets "$ASSETS_DIR"
76
77
  run_test "With both flags" false "$DYNIMG" "$EXAMPLES_DIR/google-fonts.html" -o "$OUTPUT_DIR/google-fonts.png" --allow-net --assets "$ASSETS_DIR"
@@ -78,6 +79,7 @@ run_test "With both flags" false "$DYNIMG" "$EXAMPLES_DIR/google-fonts.html" -o
78
79
  echo ""
79
80
  echo "--- OG Image Templates ---"
80
81
  run_test "og-image.html" false "$DYNIMG" "$EXAMPLES_DIR/og-image.html" -o "$OUTPUT_DIR/og-image.png"
82
+ run_test "og-image.html" false "$DYNIMG" "$EXAMPLES_DIR/og-image.html" -o "$OUTPUT_DIR/og-image.webp"
81
83
  run_test "social-card.html" false "$DYNIMG" "$EXAMPLES_DIR/social-card.html" -o "$OUTPUT_DIR/social-card.png"
82
84
  run_test "quote.html" false "$DYNIMG" "$EXAMPLES_DIR/quote.html" -o "$OUTPUT_DIR/quote.png"
83
85
 
@@ -451,18 +451,22 @@ async fn render_document(
451
451
  ) -> Result<RenderedImage, Error> {
452
452
  // Resolve resource requests
453
453
  if let Some(p) = provider {
454
- loop {
454
+ // Wait for all network requests including cascading requests.
455
+ // CSS stylesheets may trigger font fetches when processed, so we need
456
+ // multiple consecutive "empty" checks to ensure all cascading requests complete.
457
+ // Using 5 cycles provides safety margin for complex pages with many resources.
458
+ let mut consecutive_empty = 0u32;
459
+ const REQUIRED_EMPTY_CYCLES: u32 = 5;
460
+
461
+ while consecutive_empty < REQUIRED_EMPTY_CYCLES {
455
462
  document.resolve(0.0);
456
- if p.is_empty() {
457
- break;
458
- }
459
463
  tokio::time::sleep(std::time::Duration::from_millis(1)).await;
460
- }
461
464
 
462
- // Extra resolve cycles for font registration
463
- for _ in 0..3 {
464
- tokio::time::sleep(std::time::Duration::from_millis(5)).await;
465
- document.resolve(0.0);
465
+ if p.is_empty() {
466
+ consecutive_empty += 1;
467
+ } else {
468
+ consecutive_empty = 0;
469
+ }
466
470
  }
467
471
  }
468
472
 
@@ -521,11 +525,13 @@ fn write_png(path: &Path, buffer: &[u8], width: u32, height: u32) -> Result<(),
521
525
  fn encode_png(buffer: &[u8], width: u32, height: u32) -> Result<Vec<u8>, Error> {
522
526
  const PPM: u32 = (144.0 * 39.3701) as u32;
523
527
 
524
- let mut output = Vec::new();
528
+ // Pre-allocate output (PNG is typically 10-50% of raw size after compression)
529
+ let mut output = Vec::with_capacity(buffer.len() / 4);
525
530
  {
526
531
  let mut encoder = png::Encoder::new(&mut output, width, height);
527
532
  encoder.set_color(png::ColorType::Rgba);
528
533
  encoder.set_depth(png::BitDepth::Eight);
534
+ encoder.set_compression(png::Compression::Fast);
529
535
  encoder.set_pixel_dims(Some(png::PixelDimensions {
530
536
  xppu: PPM,
531
537
  yppu: PPM,
@@ -552,14 +558,19 @@ fn write_jpeg(
552
558
  }
553
559
 
554
560
  fn encode_jpeg(buffer: &[u8], width: u32, height: u32, quality: u8) -> Result<Vec<u8>, Error> {
555
- let rgb_buffer: Vec<u8> = buffer
556
- .chunks(4)
557
- .flat_map(|rgba| [rgba[0], rgba[1], rgba[2]])
558
- .collect();
561
+ // Pre-allocate RGB buffer (3 bytes per pixel instead of 4)
562
+ let pixel_count = (width * height) as usize;
563
+ let mut rgb_buffer = Vec::with_capacity(pixel_count * 3);
564
+
565
+ // Convert RGBA to RGB in-place
566
+ for chunk in buffer.chunks_exact(4) {
567
+ rgb_buffer.extend_from_slice(&chunk[..3]);
568
+ }
559
569
 
560
570
  let img = image::RgbImage::from_raw(width, height, rgb_buffer).ok_or(Error::InvalidBuffer)?;
561
571
 
562
- let mut output = Vec::new();
572
+ // Pre-allocate output (estimate ~10% of raw size for compressed JPEG)
573
+ let mut output = Vec::with_capacity(pixel_count / 10);
563
574
  let mut encoder = image::codecs::jpeg::JpegEncoder::new_with_quality(&mut output, quality);
564
575
  encoder.encode_image(&img)?;
565
576
 
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes