calendar-generator-pdf/app.py

171 lines
6.3 KiB
Python

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.pdfgen import canvas
from reportlab.lib.units import mm
from datetime import datetime
import os
import re
import textwrap
# Konstanten für die Abmessungen
CIRCLE_RADIUS = 3 * mm
CIRCLE_DISTANCE = 80 * mm
TOP_MARGIN_TO_CENTER = 12 * mm
IMAGE_TOP_MARGIN = 28 * mm
IMAGE_HEIGHT = 60 * mm
TEXT_MARGIN = 5 * mm
LEFT_MARGIN_TO_CENTER = (A4[0] / 4) - (CIRCLE_DISTANCE / 2) # Zentriert zwischen den Tagen
IMAGE_SHIFT_UP = 1 * mm # Bild nach oben verschieben
DATE_SHIFT_DOWN = 8 * mm # Datum nach unten verschieben
TEXT_SHIFT_DOWN = 8 * mm # Text nach unten verschieben
def get_dates_from_images(image_directory):
# Regular expression to match files with a date format YYYY-MM-DD
date_pattern = re.compile(r'(\d{4}-\d{2}-\d{2})')
# List to store the dates
dates = []
# Iterate over each file in the images directory
for filename in os.listdir(image_directory):
# Search for the pattern in the filename
match = date_pattern.search(filename)
if match:
# Extract the date from the filename
try:
date = datetime.strptime(match.group(), '%Y-%m-%d')
dates.append(date)
except ValueError:
# If the date format is incorrect, ignore the file
continue
# Return the sorted list of dates
return sorted(dates)
def get_image_and_text_for_date(date, image_directory, text_directory):
formatted_date = date.strftime('%Y-%m-%d')
image_file = None
text_content = None
# Check for image file
for ext in ['jpg', 'jpeg', 'png']:
# Check using full path, but store relative path for HTML
image_full_path = os.path.join(image_directory, f"{formatted_date}.{ext}")
if os.path.isfile(image_full_path):
# Store the relative path from within the 'static' directory
image_file = f"images/{formatted_date}.{ext}"
break
# Check for text file
text_path = os.path.join(text_directory, f"{formatted_date}.txt")
if os.path.isfile(text_path):
with open(text_path, 'r') as file:
text_content = file.read()
return image_file, text_content
def draw_circle(c, x, y):
c.circle(x, y, CIRCLE_RADIUS, stroke=1, fill=0)
def create_pdf(pages_data, output_filename):
c = canvas.Canvas(output_filename, pagesize=A4)
c.setCreator('Lorenz B.')
c.setTitle('Calendar')
c.setAuthor('Lorenz B.')
c.setSubject('calendar generator')
width, height = A4
max_text_width = (width / 2) - (2 * TEXT_MARGIN)
DATE_FONT_SIZE = 20
DATE_FONT = "Helvetica-Bold"
for page in pages_data:
for index, day in enumerate(page):
c.setDash(1, 0)
c.setStrokeColor(colors.black)
# Berechnung der Positionen für jeden Tag
x = (index % 2) * (width / 2)
y = height - (index // 2 + 1) * (height / 2)
# Höhere Position für das Bild
image_y_position = y + (height / 2 - IMAGE_TOP_MARGIN - IMAGE_HEIGHT) + IMAGE_SHIFT_UP
# Kreise zeichnen
draw_circle(c, x + LEFT_MARGIN_TO_CENTER, y + height / 2 - TOP_MARGIN_TO_CENTER)
draw_circle(c, x + width / 2 - LEFT_MARGIN_TO_CENTER, y + height / 2 - TOP_MARGIN_TO_CENTER)
# Bild einfügen
if day['image_file']:
c.drawImage(day['image_file'], x, image_y_position, width=width / 2, height=IMAGE_HEIGHT, preserveAspectRatio=True, anchor='n')
# Datum direkt unter dem Bild einfügen
date_x_position = x + (width / 4) # Zentrum des Tagesbereichs
date_y_position = image_y_position - DATE_SHIFT_DOWN
date_str = day['date'].strftime('%A, %d.%m.%Y')
c.setFont(DATE_FONT, DATE_FONT_SIZE) # Schriftart und Schriftgröße setzen
date_width = c.stringWidth(date_str, DATE_FONT, DATE_FONT_SIZE)
c.drawString(date_x_position - (date_width / 2), date_y_position, date_str)
# Text unter dem Datum einfügen
text_y_position = date_y_position - TEXT_SHIFT_DOWN - 5 * mm # Extra Abstand nach einem größeren Datum
if day['text_content']:
c.setFont("Helvetica", 12) # Schriftart zurücksetzen für den Text
wrapped_text = textwrap.fill(day['text_content'], width=50) # Anpassen für die passende Zeilenlänge
text = c.beginText(x + TEXT_MARGIN, text_y_position)
for line in wrapped_text.split('\n'):
text.textLine(line)
c.drawText(text)
# Gestrichelte Linien zeichnen, falls notwendig
c.setDash(1, 2)
c.setStrokeColor(colors.grey)
if index % 2 == 0: # Vertikale Linie rechts für den Tag
c.line(x + width / 2, y, x + width / 2, y + height / 2)
if index < 2: # Horizontale Linie unten für den Tag
c.line(x, y, x + width / 2, y)
c.showPage()
c.save()
def main():
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
image_directory = os.path.join(BASE_DIR, 'images')
text_directory = os.path.join(BASE_DIR, 'texts')
# Get sorted dates from image files
dates = get_dates_from_images(image_directory)
if not dates:
print("No images found with the correct date format in the name.")
return
# Generate data for each date
pages_data = []
days_data = []
for date in dates:
image_file, text_content = get_image_and_text_for_date(date, image_directory, text_directory)
days_data.append({
'date': date,
'image_file': image_file,
'text_content': text_content
})
# Check if we have collected data for 4 days, then start a new page
if len(days_data) == 4:
pages_data.append(days_data)
days_data = []
# Add any remaining days to the last page
if days_data:
pages_data.append(days_data)
# Create the PDF
output_filename = os.path.join(BASE_DIR, 'calendar.pdf')
create_pdf(pages_data, output_filename)
print("PDF created successfully.")
if __name__ == '__main__':
main()