#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ export_icons.py Laedt alle Material-Symbols-Outlined Icons herunter die unsere WERKZEUGE- Sidebar benutzt, und konvertiert sie zu PNG (32x32) fuer Rhino-Toolbars. Ausgabe-Ordner: ./icons_export/ dossier_icons/ svg/ — Originale SVGs (skalierbar) png/ — 32x32 PNGs fuer Rhino .rui Buttons Konvertierung SVG->PNG nutzt 'rsvg-convert' wenn installiert, sonst Mac's 'qlmanage' (immer verfuegbar) als Fallback. Verwendung: python3 tools/export_icons.py """ import os import sys import shutil import subprocess from urllib.request import urlopen, Request # Icons gruppiert wie in WerkzeugeApp.jsx — name : label (label nur fuer Logging) ICONS = { # 2D Zeichnen "horizontal_rule": "Line", "polyline": "Polyline", "rectangle": "Rect", "radio_button_unchecked": "Circle", "network_intelligence": "Arc", "gesture": "Curve", "text_fields": "Text", "grid_view": "Hatch", "straighten": "Dim", # 2D Editieren "open_with": "Move", "content_copy": "Copy", "rotate_right": "Rotate", "aspect_ratio": "Scale", "flip": "Mirror", "padding": "Offset", "content_cut": "Trim", "swipe_right_alt": "Extend", "link": "Join", "scatter_plot": "Explode", "rounded_corner": "Fillet", "apps": "Array", # 3D Modellieren "vertical_align_top": "Extrude", "square": "Box", "join_inner": "Union", "remove": "Diff", "gradient": "Intersect", "roofing": "Cap", "cut": "Section", "unfold_more": "Loft", # Auswahl "add_link": "SelChain", "filter_alt": "SelDup", "loop": "SelClosed", "compare_arrows": "Invert", "select_all": "SelAll", "deselect": "SelNone", } URL_TPL = "https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsoutlined/{name}/default/24px.svg" OUT_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "icons_export", "dossier_icons") OUT_SVG = os.path.join(OUT_ROOT, "svg") OUT_PNG = os.path.join(OUT_ROOT, "png") def ensure_dirs(): for d in (OUT_SVG, OUT_PNG): if not os.path.isdir(d): os.makedirs(d) def download_svg(name): url = URL_TPL.format(name=name) req = Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urlopen(req, timeout=10) as r: return r.read() def have(cmd): return shutil.which(cmd) is not None def convert_to_png(svg_path, png_path, size=32): """Konvertiert SVG -> PNG. Probiert rsvg-convert, sonst qlmanage (Mac).""" if have("rsvg-convert"): try: subprocess.check_call( ["rsvg-convert", "-w", str(size), "-h", str(size), svg_path, "-o", png_path], stderr=subprocess.DEVNULL, ) return "rsvg-convert" except subprocess.CalledProcessError: pass if have("qlmanage"): # qlmanage erzeugt {svg_path}.png im out-dir out_dir = os.path.dirname(png_path) try: subprocess.check_call( ["qlmanage", "-t", "-s", str(size), "-o", out_dir, svg_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) generated = svg_path + ".png" generated_in_outdir = os.path.join(out_dir, os.path.basename(generated)) if os.path.isfile(generated_in_outdir): shutil.move(generated_in_outdir, png_path) return "qlmanage" except subprocess.CalledProcessError: pass return None def main(): ensure_dirs() print("[icons] Ziel: " + os.path.abspath(OUT_ROOT)) n_ok = 0 n_png = 0 n_fail = [] converter_used = None for name, label in sorted(ICONS.items()): svg_path = os.path.join(OUT_SVG, name + ".svg") try: data = download_svg(name) with open(svg_path, "wb") as f: f.write(data) n_ok += 1 # SVG -> PNG png_path = os.path.join(OUT_PNG, name + ".png") used = convert_to_png(svg_path, png_path, size=32) if used: converter_used = used n_png += 1 print(" OK {:<24} → {}".format(name, label)) except Exception as ex: n_fail.append((name, str(ex))) print(" FAIL {:<24} → {} ({})".format(name, label, ex)) print("") print("[icons] SVGs: {} ok / {} fail".format(n_ok, len(n_fail))) if n_png: print("[icons] PNGs: {} via {}".format(n_png, converter_used)) elif n_ok: print("[icons] PNG-Konvertierung uebersprungen — kein rsvg-convert/qlmanage gefunden.") print(" Installiere via: brew install librsvg") if n_fail: print("") print("[icons] Fehlgeschlagene Icons (vielleicht andere Namen im Symbols-Repo):") for n, err in n_fail: print(" - {} : {}".format(n, err)) if __name__ == "__main__": main()