Files
maps-saas/infrastructure/scripts/build-sprite.py
T

95 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
build-sprite.py — يبني sprite sheet لـ MapLibre من مجلد SVG.
لماذا: MapLibre لا يقرأ ملفات SVG مفردة. يحتاج صورة PNG واحدة تُرصف فيها كل
الآيقونات + فهرس JSON يحدد موضع وحجم كل واحدة. كان الستايل يشير إلى
demotiles.maplibre.org (خادم تجريبي)، وحين يفشل تحميله يرسم MapLibre النص
بلا آيقونة وبصمت — فتبدو الخريطة بأسماء بلا رموز.
الاستخدام:
pip install cairosvg pillow
python3 infrastructure/scripts/build-sprite.py
المخرجات في apps/web/public/:
sprite.png / sprite.json (1x)
sprite@2x.png / sprite@2x.json (شاشات Retina — MapLibre يطلبها تلقائياً)
ثم في الستايل: "sprite": "https://map-saas.intaleqapp.com/sprite"
(بلا امتداد — MapLibre يضيف .png/.json و@2x بنفسه)
"""
import json
import os
import sys
try:
import cairosvg
from PIL import Image
except ImportError:
sys.exit("ينقص: pip install cairosvg pillow")
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
ICONS_DIR = os.path.join(ROOT, "apps", "web", "public", "icons")
OUT_DIR = os.path.join(ROOT, "apps", "web", "public")
BASE_SIZE = 24 # بكسل للآيقونة عند 1x
PADDING = 2 # فاصل يمنع نزّ ألوان الجيران عند التصغير (bleeding)
def build(scale: int, suffix: str) -> None:
size = BASE_SIZE * scale
pad = PADDING * scale
svgs = sorted(f for f in os.listdir(ICONS_DIR) if f.endswith(".svg"))
if not svgs:
sys.exit(f"لا توجد ملفات SVG في {ICONS_DIR}")
rendered = []
for fname in svgs:
name = os.path.splitext(fname)[0]
png_bytes = cairosvg.svg2png(
url=os.path.join(ICONS_DIR, fname),
output_width=size,
output_height=size,
)
import io
rendered.append((name, Image.open(io.BytesIO(png_bytes)).convert("RGBA")))
# شبكة مربعة تقريباً: أقل هدراً من صف واحد طويل
cols = max(1, int(len(rendered) ** 0.5 + 0.999))
rows = (len(rendered) + cols - 1) // cols
sheet = Image.new(
"RGBA",
(cols * (size + pad) - pad, rows * (size + pad) - pad),
(0, 0, 0, 0),
)
index = {}
for i, (name, img) in enumerate(rendered):
x = (i % cols) * (size + pad)
y = (i // cols) * (size + pad)
sheet.paste(img, (x, y))
index[name] = {
"x": x, "y": y,
"width": size, "height": size,
"pixelRatio": scale,
"sdf": False,
}
sheet.save(os.path.join(OUT_DIR, f"sprite{suffix}.png"))
with open(os.path.join(OUT_DIR, f"sprite{suffix}.json"), "w") as fh:
json.dump(index, fh, indent=2)
print(f"✅ sprite{suffix}: {len(index)} آيقونة، {sheet.width}×{sheet.height}px")
return list(index)
if __name__ == "__main__":
names = build(1, "")
build(2, "@2x")
print("\nالآيقونات المتاحة لـ icon-image:")
print(" " + ", ".join(names))
print("\n⚠️ طبقات الستايل تطلب أسماء قد لا تكون موجودة أعلاه")
print(" (college, rail, tourist ...) — راجعها أو أضف SVG مقابلاً لكل ناقص.")