#!/usr/bin/env python from argparse import ArgumentParser from math import ceil, floor from random import randrange, choice from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import A4 from reportlab.graphics.shapes import Drawing from reportlab.graphics.barcode.qr import QrCodeWidget from reportlab.graphics import renderPDF from svglib.svglib import svg2rlg from urllib.parse import urljoin def generate_random_username(female_nouns, male_nouns, adjectives, used_usernames): random_username = None while True: nouns = choice([female_nouns, male_nouns]) random_username = f"{adjectives[randrange(len(adjectives)-1)]}{'' if nouns is female_nouns else 'r'}-{nouns[randrange(len(nouns)-1)].lower()}" if random_username not in used_usernames: used_usernames.add(random_username) print(random_username) return random_username if __name__ == "__main__": parser = ArgumentParser(description="Generates a QR code PDF with random usernames and prints the names to stdout.") parser.add_argument("url", help="Base URL, e.g. 'https://url.com'.") parser.add_argument("-n", "--number", type=int, help="Amount of requested usernames, defaults to 50.", default=50) parser.add_argument("-o", "--output", type=str, help="Output file, defaults to 'qrcodes.pdf'.", default="qrcodes.pdf") parser.add_argument("-s", "--size", type=int, help="Ticket height, defaults to 150.", default=150) parser.add_argument("-m", "--margin", type=int, help="Margin (depends on printer), defaults to 0.", default=0) args = parser.parse_args() adjectives = set() female_nouns = set() male_nouns = set() with open('adjektive-weiblich.txt', 'r') as file: for line in file: adjectives.add(line.strip()) with open('nomen-weiblich.txt', 'r') as file: for line in file: female_nouns.add(line.strip()) with open('nomen-maennlich.txt', 'r') as file: for line in file: male_nouns.add(line.strip()) adjectives = list(adjectives) female_nouns = list(female_nouns) male_nouns = list(male_nouns) pdf = canvas.Canvas(args.output, pagesize=A4) page_width, page_height = A4 used_usernames = set() ticket_height = args.size qr_code_size = ticket_height/2 logo = svg2rlg("img/karaoke-outline.svg") scaling_factor = ticket_height/logo.height logo.scale(scaling_factor, scaling_factor) logo_width = logo.width*scaling_factor logo_height = logo.height*scaling_factor ticket_width = logo_width + qr_code_size codes_per_row = floor((page_width-args.margin*2)/ticket_width) codes_per_col = floor((page_height-args.margin*2)/ticket_height) if codes_per_col == 0 or codes_per_row == 0: raise Exception(f"There is not enough space on A4 page to fit a QR code of size {ticket_width}x{ticket_height}!") codes_per_page = codes_per_row*codes_per_col required_pages = ceil(args.number/codes_per_page) generated_codes = 0 for page in range(required_pages): for y in range(codes_per_col): for x in range(codes_per_row): url = urljoin(args.url, generate_random_username(female_nouns, male_nouns, adjectives, used_usernames)) qr_code = QrCodeWidget(url) bounds = qr_code.getBounds() code_width = bounds[2] - bounds[0] code_height = bounds[3] - bounds[1] drawing = Drawing(ticket_height, ticket_height, transform=[qr_code_size/code_width, 0, 0, qr_code_size/code_height, 0, 0]) drawing.add(qr_code) renderPDF.draw(logo, pdf, args.margin+ticket_width*(x%codes_per_row), args.margin+ticket_height*(y%codes_per_col)) pdf.drawString(args.margin+ticket_width*(x%codes_per_row), args.margin+ticket_height*(y%codes_per_col), url) pdf.drawString(args.margin+ticket_width*(x%codes_per_row), args.margin+ticket_height*(y%codes_per_col)+logo_height, "Hier Code scannen") pdf.drawString(args.margin+ticket_width*(x%codes_per_row), args.margin+ticket_height*(y%codes_per_col)+logo_height-10, "und Song anmelden!") renderPDF.draw(drawing, pdf, args.margin+ticket_width*(x%codes_per_row)+logo_width, args.margin+ticket_height*(y%codes_per_col)) generated_codes += 1 if generated_codes >= args.number: pdf.save() exit() pdf.showPage() pdf.save()