feat(store): branded feature graphic (1024x500) + 512 store icon
Noto Sans wordmark on brand green (#2F7D34), white sprout, and the official
value tagline ('keep and share traditional seeds' / 'guarda y comparte...').
Generated by tool/gen_feature_graphic.py for en-US and es-ES.
This commit is contained in:
parent
fd6b9d5f0d
commit
eef99975bf
5 changed files with 101 additions and 0 deletions
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
apps/app_seeds/fastlane/metadata/android/en-US/images/icon.png
Normal file
BIN
apps/app_seeds/fastlane/metadata/android/en-US/images/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
apps/app_seeds/fastlane/metadata/android/es-ES/images/icon.png
Normal file
BIN
apps/app_seeds/fastlane/metadata/android/es-ES/images/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
101
apps/app_seeds/tool/gen_feature_graphic.py
Normal file
101
apps/app_seeds/tool/gen_feature_graphic.py
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Generate Play Store feature graphics (1024x500) + store icon (512) for Tane.
|
||||||
|
|
||||||
|
Brand green #2F7D34, white sprout from the adaptive foreground, 'Tane' wordmark
|
||||||
|
in Noto Sans (the site's brand typeface), and the official value-proposition
|
||||||
|
tagline. On-brand and replaceable with a designed asset later.
|
||||||
|
|
||||||
|
Run from apps/app_seeds/: python3 tool/gen_feature_graphic.py
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
REPO_APP = "/home/vjrj/proyectos/dev/tane/.claude/worktrees/interesting-cray-6261fd/apps/app_seeds"
|
||||||
|
NOTO = "/usr/share/fonts/truetype/noto"
|
||||||
|
F_BOLD = f"{NOTO}/NotoSans-Bold.ttf"
|
||||||
|
F_MED = f"{NOTO}/NotoSans-Medium.ttf"
|
||||||
|
F_REG = f"{NOTO}/NotoSans-Regular.ttf"
|
||||||
|
FG = f"{REPO_APP}/assets/icon_foreground.png"
|
||||||
|
ICON = f"{REPO_APP}/assets/icon.png"
|
||||||
|
|
||||||
|
GREEN = (47, 125, 52) # #2F7D34
|
||||||
|
GREEN_DARK = (34, 82, 30) # #22521E
|
||||||
|
WHITE = (255, 255, 255)
|
||||||
|
FAINT = (208, 228, 210)
|
||||||
|
|
||||||
|
W, H = 1024, 500
|
||||||
|
|
||||||
|
# value line = what the app is (explains it); attrs = the differentiators.
|
||||||
|
COPY = {
|
||||||
|
"en-US": ("Keep and share traditional seeds", "Offline · Encrypted · No account"),
|
||||||
|
"es-ES": ("Guarda y comparte semillas tradicionales", "Sin conexión · Cifrado · Sin cuenta"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def sprout(height):
|
||||||
|
im = Image.open(FG).convert("RGBA")
|
||||||
|
bb = im.getbbox()
|
||||||
|
if bb:
|
||||||
|
im = im.crop(bb)
|
||||||
|
s = height / im.height
|
||||||
|
return im.resize((max(1, int(im.width * s)), height), Image.LANCZOS)
|
||||||
|
|
||||||
|
|
||||||
|
def bg():
|
||||||
|
top = Image.new("RGB", (W, H), GREEN)
|
||||||
|
bot = Image.new("RGB", (W, H), GREEN_DARK)
|
||||||
|
mask = Image.new("L", (W, H))
|
||||||
|
md = ImageDraw.Draw(mask)
|
||||||
|
for y in range(H):
|
||||||
|
md.line([(0, y), (W, y)], fill=int(60 * (y / H)))
|
||||||
|
return Image.composite(bot, top, mask)
|
||||||
|
|
||||||
|
|
||||||
|
def center_line(d, text, font, top, fill):
|
||||||
|
b = d.textbbox((0, 0), text, font=font)
|
||||||
|
w = b[2] - b[0]
|
||||||
|
d.text(((W - w) / 2 - b[0], top - b[1]), text, font=font, fill=fill)
|
||||||
|
return b[3] - b[1]
|
||||||
|
|
||||||
|
|
||||||
|
def feature_graphic(locale, out):
|
||||||
|
img = bg()
|
||||||
|
d = ImageDraw.Draw(img)
|
||||||
|
value, attrs = COPY[locale]
|
||||||
|
|
||||||
|
# Row 1: sprout + 'Tane', centered as a group in the upper half.
|
||||||
|
spr = sprout(150)
|
||||||
|
wf = ImageFont.truetype(F_BOLD, 120)
|
||||||
|
wb = d.textbbox((0, 0), "Tane", font=wf)
|
||||||
|
ww, wh = wb[2] - wb[0], wb[3] - wb[1]
|
||||||
|
gap = 26
|
||||||
|
gw = spr.width + gap + ww
|
||||||
|
gx = (W - gw) // 2
|
||||||
|
row_top = 92
|
||||||
|
cy = row_top + spr.height / 2
|
||||||
|
img.paste(spr, (gx, row_top), spr)
|
||||||
|
d.text((gx + spr.width + gap - wb[0], cy - wh / 2 - wb[1]), "Tane", font=wf, fill=WHITE)
|
||||||
|
y = row_top + spr.height + 34
|
||||||
|
|
||||||
|
# Row 2: value proposition (explains the app).
|
||||||
|
vf = ImageFont.truetype(F_MED, 42)
|
||||||
|
y += center_line(d, value, vf, y, WHITE) + 18
|
||||||
|
|
||||||
|
# Row 3: differentiators, quieter.
|
||||||
|
af = ImageFont.truetype(F_REG, 30)
|
||||||
|
center_line(d, attrs, af, y, FAINT)
|
||||||
|
|
||||||
|
img.save(out, "PNG")
|
||||||
|
print("wrote", out, img.size)
|
||||||
|
|
||||||
|
|
||||||
|
def store_icon(out):
|
||||||
|
Image.open(ICON).convert("RGB").resize((512, 512), Image.LANCZOS).save(out, "PNG")
|
||||||
|
print("wrote", out)
|
||||||
|
|
||||||
|
|
||||||
|
for loc in ("en-US", "es-ES"):
|
||||||
|
d = f"{REPO_APP}/fastlane/metadata/android/{loc}/images"
|
||||||
|
os.makedirs(d, exist_ok=True)
|
||||||
|
feature_graphic(loc, f"{d}/featureGraphic.png")
|
||||||
|
store_icon(f"{d}/icon.png")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue