Skip to content

Commit e4a1e6d

Browse files
author
CalorieApp Maintainer
committed
feat: add branded social image generator + super short post
1 parent b48b1cb commit e4a1e6d

3 files changed

Lines changed: 131 additions & 0 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Super Short Social Post (2025-11-18)
2+
3+
CalorieApp UX & Docs upgrade LIVE → faster flows, stronger security, improved mnemonic UX, public-safe docs. Focus: Security • Speed • UX. #CalorieApp #XRPL
4+
5+
Use for: tight character limits (X quick reply / Discord blurb / alt text).
6+
7+
Image pairing: `square-1080x1080.png` generated via `python tools/generate_social_image.py`.

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,5 @@ aiohttp
3232

3333
# Note: shelve and json are part of Python standard library
3434
# Note: pyjnius is installed automatically by buildozer when building for Android
35+
# Image generation utility (local social asset automation)
36+
pillow>=10.3.0

tools/generate_social_image.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
"""Generate a branded 1080x1080 social image with CalorieApp logo and headline.
2+
3+
Usage:
4+
python tools/generate_social_image.py
5+
6+
Outputs:
7+
assets/social-media/2025-11-18-docs-update/square-1080x1080.png (overwrites)
8+
9+
If Pillow is missing:
10+
pip install pillow
11+
12+
Logo selection:
13+
Tries CalorieAppLogoTranspa.png then CalorieLogoTranspa.png in assets/images.
14+
"""
15+
16+
from pathlib import Path
17+
from datetime import datetime
18+
19+
try:
20+
from PIL import Image, ImageDraw, ImageFont
21+
except ImportError:
22+
raise SystemExit("Pillow not installed. Run: pip install pillow")
23+
24+
OUT_DIR = Path("assets/social-media/2025-11-18-docs-update")
25+
OUT_DIR.mkdir(parents=True, exist_ok=True)
26+
OUT_FILE = OUT_DIR / "square-1080x1080.png"
27+
28+
LOGO_DIR = Path("assets/images")
29+
LOGO_CANDIDATES = ["CalorieAppLogoTranspa.png", "CalorieLogoTranspa.png"]
30+
31+
# Brand colors
32+
NAVY = (30, 58, 138) # #1E3A8A
33+
GREEN = (0, 166, 81) # #00A651
34+
YELLOW = (252, 211, 77) # #FCD34D
35+
36+
WIDTH = HEIGHT = 1080
37+
38+
def load_logo() -> Image.Image | None:
39+
for name in LOGO_CANDIDATES:
40+
p = LOGO_DIR / name
41+
if p.exists():
42+
try:
43+
return Image.open(p).convert("RGBA")
44+
except Exception:
45+
pass
46+
return None
47+
48+
def get_font(size: int) -> ImageFont.FreeTypeFont:
49+
# Try common fonts; fallback to default.
50+
for candidate in ["Montserrat-Bold.ttf", "Poppins-Bold.ttf", "Arial.ttf", "DejaVuSans-Bold.ttf"]:
51+
try:
52+
return ImageFont.truetype(candidate, size)
53+
except Exception:
54+
continue
55+
return ImageFont.load_default()
56+
57+
def main():
58+
base = Image.new("RGB", (WIDTH, HEIGHT), NAVY)
59+
draw = ImageDraw.Draw(base)
60+
61+
# Background accent ring
62+
ring_margin = 90
63+
draw.ellipse(
64+
[ring_margin, ring_margin, WIDTH - ring_margin, HEIGHT - ring_margin],
65+
outline=GREEN,
66+
width=8,
67+
)
68+
69+
# Subtle diagonal lines pattern
70+
for x in range(0, WIDTH, 140):
71+
draw.line([(x, 0), (x - 200, HEIGHT)], fill=(40, 75, 160), width=2)
72+
73+
logo = load_logo()
74+
if logo:
75+
# Resize logo proportionally
76+
max_logo_w = 260
77+
ratio = max_logo_w / logo.width
78+
logo_h = int(logo.height * ratio)
79+
logo_resized = logo.resize((max_logo_w, logo_h), Image.LANCZOS)
80+
base.paste(logo_resized, (60, 60), logo_resized)
81+
else:
82+
# Fallback simple emblem
83+
draw.rectangle([60, 60, 320, 320], outline=GREEN, width=6)
84+
draw.text((80, 170), "CT", font=get_font(120), fill=GREEN)
85+
86+
headline_font = get_font(92)
87+
sub_font = get_font(44)
88+
foot_font = get_font(30)
89+
90+
headline = "CalorieApp Upgrade"
91+
subline = "Security • Speed • UX"
92+
# Center headline area
93+
head_w, head_h = draw.textbbox((0, 0), headline, font=headline_font)[2:]
94+
draw.text(
95+
((WIDTH - head_w) / 2, HEIGHT / 2 - 140),
96+
headline,
97+
font=headline_font,
98+
fill=GREEN,
99+
)
100+
sub_w, sub_h = draw.textbbox((0, 0), subline, font=sub_font)[2:]
101+
draw.text(
102+
((WIDTH - sub_w) / 2, HEIGHT / 2 - 40),
103+
subline,
104+
font=sub_font,
105+
fill=YELLOW,
106+
)
107+
108+
footer = f"Docs & UX Hardening • {datetime.now().date()}"
109+
foot_w, foot_h = draw.textbbox((0, 0), footer, font=foot_font)[2:]
110+
draw.text(
111+
((WIDTH - foot_w) / 2, HEIGHT - 140),
112+
footer,
113+
font=foot_font,
114+
fill=(200, 210, 230),
115+
)
116+
117+
# Save
118+
base.save(OUT_FILE, "PNG")
119+
print(f"Generated: {OUT_FILE}")
120+
121+
if __name__ == "__main__":
122+
main()

0 commit comments

Comments
 (0)