174 lines
6.1 KiB
Python
174 lines
6.1 KiB
Python
from pathlib import Path
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
OUTPUT = ROOT / "store-assets"
|
|
GREEN = "#075E54"
|
|
GREEN_LIGHT = "#83B6A5"
|
|
ORANGE = "#F97316"
|
|
INK = "#18342F"
|
|
PAPER = "#F7FAF5"
|
|
LINE = "#BCD3CB"
|
|
BLUE = "#DCEAF0"
|
|
|
|
|
|
def font(size: int, semibold: bool = False) -> ImageFont.FreeTypeFont:
|
|
name = "seguisb.ttf" if semibold else "segoeui.ttf"
|
|
return ImageFont.truetype(str(Path("C:/Windows/Fonts") / name), size)
|
|
|
|
|
|
def draw_mark(draw: ImageDraw.ImageDraw, box: tuple[int, int, int, int]) -> None:
|
|
left, top, right, bottom = box
|
|
width = right - left
|
|
height = bottom - top
|
|
|
|
map_points = [
|
|
(left + 0.04 * width, top + 0.30 * height),
|
|
(left + 0.32 * width, top + 0.18 * height),
|
|
(left + 0.64 * width, top + 0.30 * height),
|
|
(left + 0.94 * width, top + 0.18 * height),
|
|
(left + 0.94 * width, top + 0.76 * height),
|
|
(left + 0.64 * width, top + 0.88 * height),
|
|
(left + 0.32 * width, top + 0.76 * height),
|
|
(left + 0.04 * width, top + 0.88 * height),
|
|
]
|
|
draw.polygon(map_points, fill=PAPER, outline="#E1ECE5", width=max(4, width // 38))
|
|
draw.line(
|
|
[(left + 0.32 * width, top + 0.18 * height), (left + 0.32 * width, top + 0.76 * height)],
|
|
fill=GREEN_LIGHT,
|
|
width=max(4, width // 35),
|
|
)
|
|
draw.line(
|
|
[(left + 0.64 * width, top + 0.30 * height), (left + 0.64 * width, top + 0.88 * height)],
|
|
fill=GREEN_LIGHT,
|
|
width=max(4, width // 35),
|
|
)
|
|
|
|
cx = left + 0.50 * width
|
|
cy = top + 0.36 * height
|
|
radius = 0.20 * width
|
|
pin = [
|
|
(cx, cy + radius * 1.72),
|
|
(cx - radius * 0.86, cy + radius * 0.20),
|
|
(cx - radius, cy - radius * 0.18),
|
|
(cx - radius * 0.72, cy - radius * 0.72),
|
|
(cx - radius * 0.22, cy - radius),
|
|
(cx + radius * 0.22, cy - radius),
|
|
(cx + radius * 0.72, cy - radius * 0.72),
|
|
(cx + radius, cy - radius * 0.18),
|
|
(cx + radius * 0.86, cy + radius * 0.20),
|
|
]
|
|
draw.polygon(pin, fill=ORANGE)
|
|
draw.ellipse(
|
|
(cx - radius, cy - radius, cx + radius, cy + radius),
|
|
fill=ORANGE,
|
|
outline="white",
|
|
width=max(5, width // 32),
|
|
)
|
|
hole = radius * 0.34
|
|
draw.ellipse((cx - hole, cy - hole, cx + hole, cy + hole), fill="white")
|
|
|
|
|
|
def create_icon() -> None:
|
|
image = Image.new("RGB", (512, 512), GREEN)
|
|
draw = ImageDraw.Draw(image)
|
|
draw_mark(draw, (82, 78, 430, 434))
|
|
image.save(OUTPUT / "play-store-icon-512.png", optimize=True)
|
|
|
|
|
|
def create_feature_graphic() -> None:
|
|
image = Image.new("RGB", (1024, 500), "#F3F7F5")
|
|
draw = ImageDraw.Draw(image)
|
|
|
|
draw.rectangle((0, 0, 20, 500), fill=GREEN)
|
|
draw.rectangle((20, 0, 32, 500), fill=ORANGE)
|
|
|
|
draw.text((78, 107), "LME", font=font(34, True), fill=ORANGE)
|
|
draw.text((78, 154), "Mappe Catastali Pro", font=font(55, True), fill=INK)
|
|
draw.text((80, 234), "Mappe, GPS e progetti GIS", font=font(27), fill=GREEN)
|
|
draw.line((80, 290, 455, 290), fill=LINE, width=3)
|
|
draw.text((80, 315), "Consulta • misura • organizza", font=font(21), fill="#46635D")
|
|
|
|
panel = (595, 48, 965, 452)
|
|
draw.rounded_rectangle(panel, radius=8, fill="white", outline=LINE, width=3)
|
|
draw.polygon([(618, 86), (760, 65), (802, 164), (664, 190)], fill=BLUE, outline=GREEN_LIGHT)
|
|
draw.polygon([(806, 75), (940, 110), (923, 236), (784, 205)], fill="#E9EFE7", outline=GREEN_LIGHT)
|
|
draw.polygon([(625, 210), (779, 184), (817, 318), (665, 351)], fill="#F4E9D9", outline=GREEN_LIGHT)
|
|
draw.polygon([(820, 232), (929, 256), (946, 394), (853, 420), (798, 336)], fill=BLUE, outline=GREEN_LIGHT)
|
|
for x1, y1, x2, y2 in [
|
|
(630, 128, 932, 327),
|
|
(646, 310, 915, 128),
|
|
(704, 73, 857, 422),
|
|
(607, 267, 948, 181),
|
|
]:
|
|
draw.line((x1, y1, x2, y2), fill="#A4BDB5", width=3)
|
|
draw_mark(draw, (706, 136, 883, 340))
|
|
|
|
image.save(OUTPUT / "feature-graphic-1024x500.png", optimize=True)
|
|
|
|
|
|
def create_store_screenshot(raw_name: str, output_name: str, title: str, subtitle: str) -> None:
|
|
raw = Image.open(OUTPUT / raw_name).convert("RGB")
|
|
# Remove the Windows title bar and the desktop-only watermark/status area.
|
|
app_view = raw.crop((0, 32, raw.width, min(raw.height, 500)))
|
|
max_width, max_height = 1840, 760
|
|
scale = min(max_width / app_view.width, max_height / app_view.height)
|
|
app_view = app_view.resize(
|
|
(round(app_view.width * scale), round(app_view.height * scale)),
|
|
Image.Resampling.LANCZOS,
|
|
)
|
|
|
|
image = Image.new("RGB", (1920, 1080), "#F3F7F5")
|
|
draw = ImageDraw.Draw(image)
|
|
draw.rectangle((0, 0, 24, 1080), fill=GREEN)
|
|
draw.rectangle((24, 0, 38, 1080), fill=ORANGE)
|
|
draw.text((88, 54), title, font=font(52, True), fill=INK)
|
|
draw.text((90, 126), subtitle, font=font(26), fill="#46635D")
|
|
|
|
x = (1920 - app_view.width) // 2
|
|
y = 270
|
|
draw.rounded_rectangle(
|
|
(x - 8, y - 8, x + app_view.width + 8, y + app_view.height + 8),
|
|
radius=8,
|
|
fill="white",
|
|
outline=LINE,
|
|
width=4,
|
|
)
|
|
image.paste(app_view, (x, y))
|
|
image.save(OUTPUT / output_name, optimize=True)
|
|
|
|
|
|
def main() -> None:
|
|
OUTPUT.mkdir(exist_ok=True)
|
|
create_icon()
|
|
create_feature_graphic()
|
|
screenshots = [
|
|
(
|
|
"windows-map-raw.jpg",
|
|
"phone-01-map-1920x1080.png",
|
|
"Mappe catastali e cartografia",
|
|
"Consulta il territorio, cerca localita e lavora sulla mappa.",
|
|
),
|
|
(
|
|
"windows-data-drawings-raw.jpg",
|
|
"phone-02-data-drawings-1920x1080.png",
|
|
"Importa dati e disegna",
|
|
"KML, KMZ e GeoJSON insieme a misure e strumenti GIS.",
|
|
),
|
|
(
|
|
"windows-projects-raw.jpg",
|
|
"phone-03-projects-1920x1080.png",
|
|
"Organizza i tuoi progetti",
|
|
"Salva, riapri e condividi il lavoro sul campo.",
|
|
),
|
|
]
|
|
for raw_name, output_name, title, subtitle in screenshots:
|
|
if (OUTPUT / raw_name).exists():
|
|
create_store_screenshot(raw_name, output_name, title, subtitle)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|