feat: vsetky sablony cenoviek z novych SVG (zakladne, appkaci, vernostna karta)
- 22 sablon: Super cena / Super vyhodne / Zakladna v 3 farbach so SK aj bez,
Appkaci (SK / bez), Vernostna karta (so zlavou / bez); orezane na viditelny
obsah, rovnaka mierka (sirka = viewBox x 130 / 80,1)
- nove premenne {zlava_app}, {jednotkova_cena_app}, {cena_bez_karty},
{zlava_bez_karty}, {jednotkova_cena_s_kartou}, {jednotkova_cena_bez_karty};
zvisle natiahnutie textu (scaleY), viac nazvov pisma, napis zlava len pri zlave
- Vernostna karta je predvolena cenovka sekcie Vernostne zlavy
- produkty pri nacitani dostanu aktualnu verziu svojej sablony
- import: zlava pre appkacov a s vernostnou kartou z poznamky, jednotkova cena
pre appkacov prepocitana, sirka cenovky podla sablony
- okraj stitkov predajni podla mierky cenovky
- postup prevodu v scripts/badges
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
50af94f954
commit
af35334688
13 files changed
+300
-107
No files matched your search
@@ -1,12 +1,12 @@
|
||||
# Prevod testovacích SVG cenoviek z Illustratora na pozadia šablón:
|
||||
# - ceny, zľava % a „zľava“ sa odstránia (budú z nich vrstvy editora),
|
||||
# - statické nápisy (SUPER / CENA / VÝHODNÉ, písmo Gilroy-Heavy) sa prevedú na krivky,
|
||||
# - triedy a id dostanú jedinečnú predponu (inak by sa viaceré cenovky na stránke prebíjali),
|
||||
# - obsah sa posunie tak, aby telo cenovky bolo vo všetkých šablónach na rovnakom mieste.
|
||||
# Prevod SVG cenoviek z Illustratora na pozadia šablón cenoviek:
|
||||
# - texty v písmach Aptly / Korolev (ceny, zľavy, „zľava“, jednotkové ceny, popisy) sa z pozadia odstránia
|
||||
# a zapíšu sa do výstupu – vznikne z nich vrstva editora (premenná alebo pevný text),
|
||||
# - statické nápisy v písme Gilroy (SUPER / CENA / VÝHODNÉ) sa prevedú na krivky (Gilroy je nainštalovaný),
|
||||
# - triedy a id dostanú jedinečnú predponu (inak by sa viaceré cenovky na jednej stránke prebíjali).
|
||||
# Orezanie na viditeľný obsah (bez priehľadného okraja) a meranie polôh textov sa robí v prehliadači
|
||||
# (scripts/badges/README.md), lebo potrebuje vykreslenie s písmom Aptly.
|
||||
#
|
||||
# Použitie: pip install fonttools; python convert-illustrator-svg.py <priečinok so SVG> <výstup.json>
|
||||
# (Gilroy-Heavy musí byť nainštalovaný; priradenie súborov k typu/farbe/pôvodu je v ASSETS nižšie.)
|
||||
# Výstup obsahuje vyčistené SVG a namerané polohy textov – z nich sa vyrobili šablóny v tabuľke badges.
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
@@ -24,20 +24,30 @@ glyphs = font.getGlyphSet()
|
||||
cmap = font.getBestCmap()
|
||||
upem = font['head'].unitsPerEm
|
||||
|
||||
# referenčná poloha tela cenovky (zhora ľavý roh rámika s cenou)
|
||||
REF_X = 27.98
|
||||
|
||||
# súbor → (názov šablóny, tagy pre import)
|
||||
ASSETS = {
|
||||
'Asset 2.svg': ('SUPER CENA', 'cervena', 'SK'),
|
||||
'Asset 3.svg': ('SUPER VÝHODNÉ', 'cervena', 'SK'),
|
||||
'Asset 4.svg': ('SUPER CENA', 'oranzova', 'SK'),
|
||||
'Asset 5.svg': ('SUPER CENA', 'zelena', 'SK'),
|
||||
'Asset 6.svg': ('SUPER CENA', 'cervena', ''),
|
||||
'Asset 7.svg': ('SUPER VÝHODNÉ', 'cervena', ''),
|
||||
'Asset 8.svg': ('SUPER CENA', 'oranzova', ''),
|
||||
'Asset 9.svg': ('SUPER VÝHODNÉ', 'zelena', ''),
|
||||
'Asset 10.svg': ('SUPER VÝHODNÉ', 'oranzova', 'SK'),
|
||||
'Asset 11.svg': ('SUPER VÝHODNÉ', 'oranzova', ''),
|
||||
'Asset 12.svg': ('Super cena | Červená | SK', {'type': 'SUPER CENA', 'color': 'cervena', 'origin': 'SK'}),
|
||||
'Asset 18.svg': ('Super cena | Červená', {'type': 'SUPER CENA', 'color': 'cervena', 'origin': ''}),
|
||||
'Asset 14.svg': ('Super cena | Oranžová | SK', {'type': 'SUPER CENA', 'color': 'oranzova', 'origin': 'SK'}),
|
||||
'Asset 20.svg': ('Super cena | Oranžová', {'type': 'SUPER CENA', 'color': 'oranzova', 'origin': ''}),
|
||||
'Asset 16.svg': ('Super cena | Zelená | SK', {'type': 'SUPER CENA', 'color': 'zelena', 'origin': 'SK'}),
|
||||
'Asset 22.svg': ('Super cena | Zelená', {'type': 'SUPER CENA', 'color': 'zelena', 'origin': ''}),
|
||||
'Asset 13.svg': ('Super výhodné | Červená | SK', {'type': 'SUPER VÝHODNÉ', 'color': 'cervena', 'origin': 'SK'}),
|
||||
'Asset 19.svg': ('Super výhodné | Červená', {'type': 'SUPER VÝHODNÉ', 'color': 'cervena', 'origin': ''}),
|
||||
'Asset 15.svg': ('Super výhodné | Oranžová | SK', {'type': 'SUPER VÝHODNÉ', 'color': 'oranzova', 'origin': 'SK'}),
|
||||
'Asset 21.svg': ('Super výhodné | Oranžová', {'type': 'SUPER VÝHODNÉ', 'color': 'oranzova', 'origin': ''}),
|
||||
'Asset 17.svg': ('Super výhodné | Zelená | SK', {'type': 'SUPER VÝHODNÉ', 'color': 'zelena', 'origin': 'SK'}),
|
||||
'Asset 23.svg': ('Super výhodné | Zelená', {'type': 'SUPER VÝHODNÉ', 'color': 'zelena', 'origin': ''}),
|
||||
'Asset 27.svg': ('Základná | Červená | SK', {'type': 'ZÁKLADNÁ', 'color': 'cervena', 'origin': 'SK'}),
|
||||
'Asset 28.svg': ('Základná | Červená', {'type': 'ZÁKLADNÁ', 'color': 'cervena', 'origin': ''}),
|
||||
'Asset 30.svg': ('Základná | Oranžová | SK', {'type': 'ZÁKLADNÁ', 'color': 'oranzova', 'origin': 'SK'}),
|
||||
'Asset 29.svg': ('Základná | Oranžová', {'type': 'ZÁKLADNÁ', 'color': 'oranzova', 'origin': ''}),
|
||||
'Asset 32.svg': ('Základná | Zelená | SK', {'type': 'ZÁKLADNÁ', 'color': 'zelena', 'origin': 'SK'}),
|
||||
'Asset 31.svg': ('Základná | Zelená', {'type': 'ZÁKLADNÁ', 'color': 'zelena', 'origin': ''}),
|
||||
'Asset 33.svg': ('Appkáči | SK', {'type': 'ZÁKLADNÁ', 'origin': 'SK', 'app': True}),
|
||||
'Asset 36.svg': ('Appkáči', {'type': 'ZÁKLADNÁ', 'origin': '', 'app': True}),
|
||||
'Asset 34.svg': ('Vernostná karta', {'loyalty': True}),
|
||||
'Asset 35.svg': ('Vernostná karta | bez zľavy', {'loyalty': True}),
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +55,7 @@ def parse_css(svg):
|
||||
style = re.search(r'<style>(.*?)</style>', svg, re.S).group(1)
|
||||
props = {}
|
||||
for sel, body in re.findall(r'([^{}]+)\{([^}]*)\}', style):
|
||||
decl = dict(
|
||||
(k.strip(), v.strip()) for k, v in (d.split(':', 1) for d in body.split(';') if ':' in d)
|
||||
)
|
||||
decl = dict((k.strip(), v.strip()) for k, v in (d.split(':', 1) for d in body.split(';') if ':' in d))
|
||||
for cls in sel.split(','):
|
||||
props.setdefault(cls.strip().lstrip('.'), {}).update(decl)
|
||||
return props
|
||||
@@ -70,70 +78,55 @@ def text_to_path(transform, runs, size, fill):
|
||||
|
||||
|
||||
result = []
|
||||
for fname, (btype, color, origin) in ASSETS.items():
|
||||
for fname, (name, tags) in ASSETS.items():
|
||||
svg = open(f'{SRC}/{fname}', encoding='utf-8').read()
|
||||
key = 'b' + re.sub(r'\D', '', fname)
|
||||
key = 'k' + re.sub(r'\D', '', fname)
|
||||
css = parse_css(svg)
|
||||
texts = []
|
||||
|
||||
texts = {} # rola → údaje
|
||||
def replace_text(m):
|
||||
classes = m.group(1).split()
|
||||
transform = m.group(2)
|
||||
body = m.group(3)
|
||||
p = {}
|
||||
for c in classes:
|
||||
for c in m.group(1).split():
|
||||
p.update(css.get(c, {}))
|
||||
transform, body = m.group(2), m.group(3)
|
||||
size = float(p.get('font-size', '0').replace('px', ''))
|
||||
family = p.get('font-family', '')
|
||||
fill = p.get('fill', '#000')
|
||||
runs = []
|
||||
for tcls, x, txt in re.findall(r'<tspan(?: class="([^"]*)")? x="([\d.\-]+)" y="[\d.\-]+">([^<]*)</tspan>', body):
|
||||
ls = css.get(tcls, {}).get('letter-spacing', '0em').replace('em', '') if tcls else '0'
|
||||
runs.append((float(x), txt, float(ls or 0)))
|
||||
if not runs:
|
||||
runs = [(0.0, re.sub(r'<[^>]+>', '', body), 0.0)]
|
||||
content = ''.join(r[1] for r in runs)
|
||||
tr = re.match(r'translate\(([\d.\-]+) ([\d.\-]+)\)', transform)
|
||||
tx, ty = float(tr.group(1)), float(tr.group(2))
|
||||
if not content.strip():
|
||||
return ''
|
||||
if 'Gilroy' in family:
|
||||
return text_to_path(transform, runs, size, fill)
|
||||
# Aptly: ceny, zľava % a „zľava“ → vrstvy editora
|
||||
if '%' in content:
|
||||
role = 'discount'
|
||||
elif content.isdigit() and size >= 25:
|
||||
role = 'main'
|
||||
elif content.isdigit():
|
||||
role = 'cents'
|
||||
else:
|
||||
role = 'label'
|
||||
texts[role] = {'text': content, 'x': tx, 'y': ty, 'size': size, 'fill': fill, 'runs': runs}
|
||||
return text_to_path(transform, runs, size, p.get('fill', '#000'))
|
||||
tr = re.match(r'translate\(([\d.\-]+) ([\d.\-]+)\)(?: scale\(([\d.]+) ([\d.]+)\))?', transform)
|
||||
texts.append({
|
||||
'text': content, 'x': float(tr.group(1)), 'y': float(tr.group(2)),
|
||||
'scaleY': float(tr.group(4)) if tr.group(4) else 1,
|
||||
'size': size, 'fill': p.get('fill', '#000'), 'family': family,
|
||||
'weight': p.get('font-weight', ''), 'transform': transform, 'markup': m.group(0),
|
||||
})
|
||||
return ''
|
||||
|
||||
svg = re.sub(r'<text class="([^"]+)" transform="([^"]+)">(.*?)</text>', replace_text, svg, flags=re.S)
|
||||
clean = re.sub(r'<text class="([^"]+)" transform="([^"]+)">(.*?)</text>', replace_text, svg, flags=re.S)
|
||||
original = svg
|
||||
|
||||
# posun obsahu: rámik s cenou vždy na REF_X a jeho horná hrana na rovnakej výške v rámci druhu cenovky
|
||||
rects = re.findall(r'<rect class="(cls-\d+)" x="([\d.]+)" y="([\d.]+)" width="48.53" height="41.94"/>', svg)
|
||||
box_x, box_y = float(rects[0][1]), float(rects[0][2])
|
||||
dx = REF_X - box_x
|
||||
dy = (92.67 if btype == 'SUPER CENA' else 44.98) - box_y
|
||||
# jedinečné triedy a id (vo vyčistenom aj v pôvodnom SVG – pôvodné slúži na meranie textov)
|
||||
def uniq(s):
|
||||
s = re.sub(r'\bcls-(\d+)\b', rf'{key}-c\1', s)
|
||||
for ident in set(re.findall(r'id="([^"]+)"', s)):
|
||||
s = re.sub(rf'(id="|url\(#|xlink:href="#){re.escape(ident)}(["\)])', rf'\1{key}-{ident}\2', s)
|
||||
return s
|
||||
|
||||
# jedinečné triedy a id
|
||||
svg = re.sub(r'\bcls-(\d+)\b', rf'{key}-c\1', svg)
|
||||
for ident in set(re.findall(r'id="([^"]+)"', svg)):
|
||||
svg = re.sub(rf'(id="|url\(#|xlink:href="#){re.escape(ident)}(["\)])', rf'\1{key}-{ident}\2', svg)
|
||||
|
||||
inner = re.sub(r'^.*?<svg[^>]*>', '', svg, flags=re.S)
|
||||
inner = re.sub(r'</svg>\s*$', '', inner)
|
||||
defs = re.search(r'<defs>.*?</defs>', inner, re.S).group(0)
|
||||
body = inner.replace(defs, '')
|
||||
clean, original = uniq(clean), uniq(original)
|
||||
inner = re.sub(r'</svg>\s*$', '', re.sub(r'^.*?<svg[^>]*>', '', clean, flags=re.S))
|
||||
vb = [float(v) for v in re.search(r'viewBox="([^"]+)"', svg).group(1).split()]
|
||||
result.append({'file': fname, 'key': key, 'name': name, 'tags': tags, 'vb': vb, 'texts': texts,
|
||||
'inner': inner.strip(), 'original': original})
|
||||
|
||||
result.append({
|
||||
'file': fname, 'key': key, 'type': btype, 'color': color, 'origin': origin,
|
||||
'dx': dx, 'dy': dy, 'boxY': box_y, 'vb': vb, 'texts': texts,
|
||||
'svg': f'{defs}<g transform="translate({dx:.2f} {dy:.2f})">{body.strip()}</g>',
|
||||
})
|
||||
|
||||
json.dump(result, open(OUT, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
|
||||
json.dump(result, open(OUT, 'w', encoding='utf-8'), ensure_ascii=False)
|
||||
for r in result:
|
||||
print(r['file'], r['type'], r['color'], r['origin'], 'dx', round(r['dx'], 2), 'dy', round(r['dy'], 2), 'boxY', r['boxY'], 'texts', {k: v['text'] for k, v in r['texts'].items()}, len(r['svg']))
|
||||
print(r['file'], r['name'], [t['text'] for t in r['texts']])
|
||||
Reference in new issue
Block a user