[script] Add generation of english posters
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,7 +7,10 @@ poster.html
|
|||||||
poster.pdf
|
poster.pdf
|
||||||
poster_light.png
|
poster_light.png
|
||||||
poster_dark.png
|
poster_dark.png
|
||||||
|
poster_light_en.png
|
||||||
|
poster_dark_en.png
|
||||||
poster.txt
|
poster.txt
|
||||||
|
poster_en.txt
|
||||||
http.access.log
|
http.access.log
|
||||||
http.error.log
|
http.error.log
|
||||||
events.ical
|
events.ical
|
||||||
|
|||||||
172
image_poster.py
172
image_poster.py
@@ -1,7 +1,6 @@
|
|||||||
#! /usr/bin/env python3
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import freetype
|
|
||||||
import io
|
import io
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
import csv
|
import csv
|
||||||
@@ -12,16 +11,38 @@ from cairosvg import svg2png
|
|||||||
CURRENT_TIME = dt.date.today()
|
CURRENT_TIME = dt.date.today()
|
||||||
NEXT_MONTH = CURRENT_TIME + relativedelta.relativedelta(months=1, day=1)
|
NEXT_MONTH = CURRENT_TIME + relativedelta.relativedelta(months=1, day=1)
|
||||||
DAYS_OF_WEEK_SR = ("PON", "UTO", "SRE", "ČET", "PET", "SUB", "NED")
|
DAYS_OF_WEEK_SR = ("PON", "UTO", "SRE", "ČET", "PET", "SUB", "NED")
|
||||||
MONTHS_SR = ("Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust",\
|
DAYS_OF_WEEK_EN = ("MON", "TUE", "WED", "THU", "FRI", "SAT", "SUn")
|
||||||
"Septembar", "Oktobar", "Novembar", "Decembar")
|
|
||||||
|
MONTHS_SR = ("Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul",
|
||||||
|
"Avgust", "Septembar", "Oktobar", "Novembar", "Decembar")
|
||||||
|
MONTHS_EN = ("January", "February", "March", "April", "May", "June", "July",
|
||||||
|
"August", "September", "October", "November", "December")
|
||||||
|
|
||||||
|
HEADER_SR = "Plan za {}"
|
||||||
|
|
||||||
|
SUBHEADER_SR = """
|
||||||
|
Ponedeljak u 19h u XECUT Jovana Ćirilova 15
|
||||||
|
Utorak u 18h u JAG3 Vatroslava Jagića 5
|
||||||
|
Svi dogadjaji su uvek besplatni
|
||||||
|
"""
|
||||||
|
HEADER_EN = "Plan for {}"
|
||||||
|
|
||||||
|
SUBHEADER_EN = """
|
||||||
|
Mondays at 19h at XECUT Jovana Ćirilova 15
|
||||||
|
Tuesdays at 18h at JAG3 Vatroslava Jagića 5
|
||||||
|
All events are always free
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def parseArgs(parser):
|
def parseArgs(parser):
|
||||||
"""
|
"""
|
||||||
Parse all arguments and return the list of argument values
|
Parse all arguments and return the list of argument values
|
||||||
"""
|
"""
|
||||||
parser.add_argument("month", metavar = "MM", help = "two digit number representing the month for which to generate poster", default = "empty", nargs = "?")
|
parser.add_argument("month", metavar="MM",
|
||||||
|
help="two digit number representing the month for which to generate poster", default="empty", nargs="?")
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def load_events(csv_path: str, month: int) -> list[dict]:
|
def load_events(csv_path: str, month: int) -> list[dict]:
|
||||||
monthafter = month + relativedelta.relativedelta(months=1, day=1)
|
monthafter = month + relativedelta.relativedelta(months=1, day=1)
|
||||||
events = []
|
events = []
|
||||||
@@ -30,72 +51,28 @@ def load_events(csv_path:str, month:int) -> list[dict]:
|
|||||||
next(csv_reader, None)
|
next(csv_reader, None)
|
||||||
for event in csv_reader:
|
for event in csv_reader:
|
||||||
event_date = event[0]
|
event_date = event[0]
|
||||||
event_date_parsed = dt.datetime.strptime(event_date, "%d-%m-%Y").date()
|
event_date_parsed = dt.datetime.strptime(
|
||||||
|
event_date, "%d-%m-%Y").date()
|
||||||
event_time = event[1]
|
event_time = event[1]
|
||||||
event_title = event[3]
|
event_title = event[3]
|
||||||
|
event_title_en = event[3]
|
||||||
|
if len(event) > 6:
|
||||||
|
event_title_en = event[6]
|
||||||
|
|
||||||
current_event = {"date": event_date_parsed,
|
current_event = {"date": event_date_parsed,
|
||||||
"time": event_time,
|
"time": event_time,
|
||||||
"title":event_title.strip()}
|
"title": event_title.strip(),
|
||||||
|
"title_en": event_title_en.strip()}
|
||||||
if event_date_parsed >= month and event_date_parsed < monthafter:
|
if event_date_parsed >= month and event_date_parsed < monthafter:
|
||||||
events.append(current_event)
|
events.append(current_event)
|
||||||
return events
|
return events
|
||||||
|
|
||||||
def drawPoster(events, bg, fg, month:int):
|
|
||||||
fontFacade = ImageFont.truetype('./site/font/Facade-Sud.woff', size=365)
|
|
||||||
fontIosevka = ImageFont.truetype('./site/font/iosevka-regular.woff', size=200)
|
|
||||||
fontIosevkaSmall = ImageFont.truetype('./site/font/iosevka-regular.woff', size=150)
|
|
||||||
|
|
||||||
W = 3508
|
|
||||||
H = 4960
|
|
||||||
img = Image.new('RGB', (W, H), bg)
|
|
||||||
draw = ImageDraw.Draw(img)
|
|
||||||
|
|
||||||
header = "DECENTRALA"
|
|
||||||
_, _, w, _ = draw.textbbox((0, 0), header, font=fontFacade)
|
|
||||||
draw.text(((W-w)/2, 165), header, font=fontFacade, fill=fg)
|
|
||||||
|
|
||||||
subheader = f"Plan za {MONTHS_SR[month.month - 1]}"
|
|
||||||
_, _, w, _ = draw.textbbox((0, 0), subheader, font=fontIosevka)
|
|
||||||
draw.text(((W-w)/2, 560), subheader, font=fontIosevka, fill=fg)
|
|
||||||
|
|
||||||
height = 990
|
|
||||||
|
|
||||||
draw.text((165, height), "Pondeljkom u 19h i utorkom u 18h ", font=fontIosevkaSmall, fill=fg)
|
|
||||||
height += 200
|
|
||||||
|
|
||||||
# draw.text((165, height), "Sredom u 18h na MATF-u", font=fontIosevkaSmall, fill=fg)
|
|
||||||
# height += 200
|
|
||||||
|
|
||||||
draw.text((165, height), "Svi dogadjaji su uvek besplatni", font=fontIosevkaSmall, fill=fg)
|
|
||||||
height += 300
|
|
||||||
|
|
||||||
# Write list of events to sperate text file as well
|
|
||||||
textfile=open("poster.txt","w")
|
|
||||||
|
|
||||||
textfile.write(f"Plan za {MONTHS_SR[month.month - 1]}\n\n")
|
|
||||||
textfile.write("Radionice pocinju u 19h u DC Krovu\n")
|
|
||||||
textfile.write("Svi dogadjaji su uvek besplatni\n\n")
|
|
||||||
|
|
||||||
# Loop to write events both to poster image and text file
|
|
||||||
for event in events:
|
|
||||||
|
|
||||||
# Add event to image poster
|
|
||||||
date = DAYS_OF_WEEK_SR[event["date"].weekday()]
|
|
||||||
day = event["date"].day
|
|
||||||
title = event["title"]
|
|
||||||
pad = " " if event["date"].day < 10 else ""
|
|
||||||
eventText = f"{date} {day}. {pad}{title}"
|
|
||||||
draw.text((165, height), eventText, font=fontIosevkaSmall, fill=fg)
|
|
||||||
height += 200
|
|
||||||
|
|
||||||
# Add event to textfile
|
|
||||||
textfile.write(eventText + "\n")
|
|
||||||
|
|
||||||
textfile.close()
|
|
||||||
|
|
||||||
|
def drawMesh(draw, img, fg, bg, font, W, H):
|
||||||
def drawCircle(x, y):
|
def drawCircle(x, y):
|
||||||
r = 50
|
r = 50
|
||||||
draw.ellipse((x - r, y - r, x + r, y+r), fill=fg, outline=(0, 0, 0), width=0)
|
draw.ellipse((x - r, y - r, x + r, y+r),
|
||||||
|
fill=fg, outline=(0, 0, 0), width=0)
|
||||||
|
|
||||||
LCX = 415 # logo center x
|
LCX = 415 # logo center x
|
||||||
LCY = 4350 # logo center y
|
LCY = 4350 # logo center y
|
||||||
@@ -107,8 +84,9 @@ def drawPoster(events, bg, fg, month:int):
|
|||||||
drawCircle(LCX + d, LCY)
|
drawCircle(LCX + d, LCY)
|
||||||
|
|
||||||
draw.line([(LCX - d, LCY), (LCX + d, LCY)], fill=fg, width=20, joint=None)
|
draw.line([(LCX - d, LCY), (LCX + d, LCY)], fill=fg, width=20, joint=None)
|
||||||
draw.line([(LCX, LCY), (LCX, LCY + d), (LCX + d, LCY), (LCX, LCY - d)], fill=fg, width=20, joint=None)
|
draw.line([(LCX, LCY), (LCX, LCY + d), (LCX + d, LCY),
|
||||||
draw.text((LCX - 1.7*d, LCY + 1.5*d), "dmz.rs", font=fontIosevka, fill=fg)
|
(LCX, LCY - d)], fill=fg, width=20, joint=None)
|
||||||
|
draw.text((LCX - 1.7*d, LCY + 1.5*d), "dmz.rs", font=font, fill=fg)
|
||||||
|
|
||||||
mesh_svg = svg2png(url='site/img/mesh-light.svg')
|
mesh_svg = svg2png(url='site/img/mesh-light.svg')
|
||||||
mesh_svg_bytes = io.BytesIO(mesh_svg)
|
mesh_svg_bytes = io.BytesIO(mesh_svg)
|
||||||
@@ -127,11 +105,70 @@ def drawPoster(events, bg, fg, month:int):
|
|||||||
mesh_position = (W - mesh_w, H - mesh_h)
|
mesh_position = (W - mesh_w, H - mesh_h)
|
||||||
img.paste(mesh_img, mesh_position, mesh_img)
|
img.paste(mesh_img, mesh_position, mesh_img)
|
||||||
|
|
||||||
|
|
||||||
|
def drawPoster(events, bg, fg, month: int, en: bool):
|
||||||
|
fontFacade = ImageFont.truetype('./site/font/Facade-Sud.woff', size=365)
|
||||||
|
fontIosevka = ImageFont.truetype(
|
||||||
|
'./site/font/iosevka-regular.woff', size=200)
|
||||||
|
fontIosevkaSmall = ImageFont.truetype(
|
||||||
|
'./site/font/iosevka-regular.woff', size=150)
|
||||||
|
|
||||||
|
W = 3508
|
||||||
|
H = 4960
|
||||||
|
img = Image.new('RGB', (W, H), bg)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
drawMesh(draw, img, fg, bg, fontIosevka, W, H)
|
||||||
|
|
||||||
|
title = "DECENTRALA"
|
||||||
|
_, _, w, _ = draw.textbbox((0, 0), title, font=fontFacade)
|
||||||
|
draw.text(((W-w)/2, 165), title, font=fontFacade, fill=fg)
|
||||||
|
|
||||||
|
header = HEADER_EN if en else HEADER_SR
|
||||||
|
months = MONTHS_EN if en else MONTHS_SR
|
||||||
|
header = header.format(months[month.month - 1])
|
||||||
|
|
||||||
|
_, _, w, _ = draw.textbbox((0, 0), header, font=fontIosevka)
|
||||||
|
draw.text(((W-w)/2, 560), header, font=fontIosevka, fill=fg)
|
||||||
|
|
||||||
|
height = 890
|
||||||
|
|
||||||
|
sub_header = SUBHEADER_EN if en else SUBHEADER_SR
|
||||||
|
draw.text((165, height), sub_header,
|
||||||
|
font=fontIosevkaSmall, fill=fg)
|
||||||
|
height += 800
|
||||||
|
|
||||||
|
# Write list of events to sperate text file as well
|
||||||
|
textfile = open(f"poster{"_en" if en else ""}.txt", "w")
|
||||||
|
|
||||||
|
sub_header = SUBHEADER_EN if en else SUBHEADER_SR
|
||||||
|
textfile.write(sub_header.format(months[month.month - 1]))
|
||||||
|
|
||||||
|
days_of_week = DAYS_OF_WEEK_EN if en else DAYS_OF_WEEK_SR
|
||||||
|
# Loop to write events both to poster image and text file
|
||||||
|
for event in events:
|
||||||
|
|
||||||
|
# Add event to image poster
|
||||||
|
date = days_of_week[event["date"].weekday()]
|
||||||
|
day = event["date"].day
|
||||||
|
title = event["title_en"] if en else event["title"]
|
||||||
|
pad = " " if event["date"].day < 10 else ""
|
||||||
|
eventText = f"{date} {day}. {pad}{title}"
|
||||||
|
draw.text((165, height), eventText, font=fontIosevkaSmall, fill=fg)
|
||||||
|
height += 200
|
||||||
|
|
||||||
|
# Add event to textfile
|
||||||
|
textfile.write(eventText + "\n")
|
||||||
|
|
||||||
|
textfile.close()
|
||||||
|
|
||||||
return img
|
return img
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(description="Generate images of the poster")
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Generate images of the poster")
|
||||||
args = parseArgs(parser)
|
args = parseArgs(parser)
|
||||||
|
|
||||||
# Set month based on user input
|
# Set month based on user input
|
||||||
@@ -144,11 +181,18 @@ def main():
|
|||||||
# Load events and draw a poseter
|
# Load events and draw a poseter
|
||||||
events = load_events("dogadjaji.csv", month)
|
events = load_events("dogadjaji.csv", month)
|
||||||
|
|
||||||
img = drawPoster(events, (0, 0, 0), (20, 250, 50), month)
|
img = drawPoster(events, (0, 0, 0), (20, 250, 50), month, False)
|
||||||
img.save('poster_dark.png')
|
img.save('poster_dark.png')
|
||||||
|
|
||||||
img = drawPoster(events, (255, 255, 255), (0, 0, 0), month)
|
img = drawPoster(events, (255, 255, 255), (0, 0, 0), month, False)
|
||||||
img.save('poster_light.png')
|
img.save('poster_light.png')
|
||||||
|
|
||||||
|
img = drawPoster(events, (0, 0, 0), (20, 250, 50), month, True)
|
||||||
|
img.save('poster_dark_en.png')
|
||||||
|
|
||||||
|
img = drawPoster(events, (255, 255, 255), (0, 0, 0), month, True)
|
||||||
|
img.save('poster_light_en.png')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user