Created
February 4, 2026 22:47
-
-
Save unreal79/cdb75c86b88a12f9fa0f210cdaa7c2f7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # !/usr/bin/env python3 | |
| # Convert SVG files to centered PNGs of fixed size. | |
| # Licensed under CC0-1.0 | |
| # | |
| # Using resvg_py lib: https://github.com/baseplate-admin/resvg-py | |
| # pip install resvg_py | |
| import resvg_py | |
| from pathlib import Path | |
| import xml.etree.ElementTree as ET | |
| WIDTH = 256 | |
| HEIGHT = 256 | |
| DIR = Path(__file__).parent | |
| # DIR = Path(__file__).parent / "BLACK" / "SVG" | |
| def _parse_length(value: str | None) -> float | None: | |
| if not value: | |
| return None | |
| for suffix in ("px", "pt", "cm", "mm", "in"): | |
| if value.endswith(suffix): | |
| value = value[: -len(suffix)] | |
| break | |
| try: | |
| return float(value) | |
| except ValueError: | |
| return None | |
| def prepare_svg(svg_text: str) -> str: | |
| """Normalize SVG to have viewBox and target size for centered fit.""" | |
| root = ET.fromstring(svg_text) | |
| view_box = root.attrib.get("viewBox") or root.attrib.get("viewbox") | |
| width_attr = root.attrib.get("width") | |
| height_attr = root.attrib.get("height") | |
| if view_box: | |
| parts = view_box.replace(",", " ").split() | |
| if len(parts) != 4: | |
| raise ValueError("Invalid viewBox format; expected four numbers.") | |
| try: | |
| # Validate numeric values even though we only need the attribute to exist. | |
| _ = list(map(float, parts)) | |
| except ValueError as exc: | |
| raise ValueError("viewBox values must be numeric.") from exc | |
| else: | |
| vb_width = _parse_length(width_attr) | |
| vb_height = _parse_length(height_attr) | |
| if vb_width and vb_height: | |
| root.set("viewBox", f"0 0 {vb_width} {vb_height}") | |
| # If we still don't have geometry, bail out early. | |
| if not root.attrib.get("viewBox"): | |
| raise ValueError("SVG missing viewBox/width/height; cannot center content.") | |
| root.set("width", str(WIDTH)) | |
| root.set("height", str(HEIGHT)) | |
| if "preserveAspectRatio" not in root.attrib: | |
| root.set("preserveAspectRatio", "xMidYMid meet") | |
| return ET.tostring(root, encoding="unicode") | |
| def convert_SVG2PNG_centered(svg_dir: Path) -> None: | |
| """Convert all SVG files in svg_dir to PNGs with the same basename.""" | |
| if not svg_dir.is_dir(): | |
| raise FileNotFoundError(f"Directory not found: {svg_dir}") | |
| for svg_path in sorted(svg_dir.glob("*.svg")): | |
| png_path = svg_path.with_suffix(".png") | |
| svg_text = svg_path.read_text(encoding="utf-8") | |
| prepared_svg = prepare_svg(svg_text) | |
| png_bytes: bytes = resvg_py.svg_to_bytes( | |
| svg_string=prepared_svg, | |
| width=WIDTH, | |
| height=HEIGHT, | |
| background=None, | |
| ) | |
| png_path.write_bytes(png_bytes) | |
| print(f"Converted {svg_path.name} -> {png_path.name}") | |
| if __name__ == "__main__": | |
| convert_SVG2PNG_centered(DIR) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment