import base64 import logging import re import subprocess import tomllib from pathlib import Path from jinja2 import Environment, FileSystemLoader logger = logging.getLogger(__name__.split(".")[-1]) def get_default_user_image(image_path: Path) -> str: with open(image_path, "rb") as file: encoded_bytes = base64.b64encode(file.read()) return encoded_bytes.decode("utf-8") class BadgeGeneratorService: def __init__(self, config: str): with open(config, "rb") as file: config = tomllib.load(file) self.bg_config = config["badge_generator"] self.env = Environment(loader=FileSystemLoader("template")) self.output_path = Path("output_badges") self.output_path.mkdir(parents=True, exist_ok=True) self.svg_template = self.env.get_template(Path(self.bg_config["svg_template"]).name) self.html_template = self.env.get_template(Path(self.bg_config["html_template"]).name) self.browser_path = Path(self.bg_config["browser_path"]) self.default_image = get_default_user_image(Path(self.bg_config["default_user_image"])) self._badge_count = 0 def _get_user_svg(self, user_name: str, seat_id: str, user_image: bytes) -> str: if user_image: user_image = base64.b64encode(user_image).decode("utf-8") else: user_image = self.default_image svg = self.svg_template.render( picture=user_image, username=user_name, seat_id=seat_id ) return svg def _get_html_from_svg(self, user_svg: str) -> str: width = re.search(r'width="([^"]+)"', user_svg).group(1) height = re.search(r'height="([^"]+)"', user_svg).group(1) html = self.html_template.render( width=width, height=height, svg=user_svg ) return html def _html_to_pdf(self, user_html: str, output_path: Path) -> None: html_path = output_path.with_suffix(".html") html_path.write_text(user_html, encoding="utf-8") try: subprocess.run([ self.browser_path, "--headless", "--disable-gpu", f"--print-to-pdf={output_path.resolve()}", html_path.resolve() ], check=True) finally: html_path.unlink(missing_ok=True) def generate_badge(self, user_name, seat_id, picture) -> None: svg = self._get_user_svg(user_name, seat_id, picture) html = self._get_html_from_svg(svg) output_path = self.output_path / f"{user_name}.pdf" self._html_to_pdf(html, output_path) self._badge_count += 1 logger.info(f"({self._badge_count}) Created: {output_path}, {user_name}, {seat_id}, {str(picture)[:10]}")