Wrote a little slideshow maker in python to convert a series of screenshots into a webpage. useful to capture screenshots of talks and convert them into a web page. written with the help of chatgpt. You can see one in action here.

#!/usr/bin/env python3
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "pillow",
# ]
# ///
 
import os
import sys
import argparse
from PIL import Image
from pathlib import Path
from xml.dom.minidom import Document
 
def get_creation_time(filepath):
    return int(os.path.getmtime(filepath))
 
def compress_to_webp(image_path, output_path):
    img = Image.open(image_path).convert("RGB")
    img.save(output_path, "webp", quality=85, method=6)
 
def generate_html(slide_title, images, output_path):
    doc = Document()
    html = doc.createElement("html")
    doc.appendChild(html)
 
    head = doc.createElement("head")
    meta = doc.createElement("meta")
    meta.setAttribute("charset", "UTF-8")
    meta2 = doc.createElement("meta")
    meta2.setAttribute("name", "viewport")
    meta2.setAttribute("content", "width=device-width, initial-scale=1.0")
    script = doc.createElement("script")
    script.appendChild(doc.createTextNode(""))
    script.setAttribute("src", "https://cdn.tailwindcss.com")
    title = doc.createElement("title")
    title.appendChild(doc.createTextNode(slide_title))
 
    for el in [meta, meta2, script, title]:
        head.appendChild(el)
    html.appendChild(head)
 
    body = doc.createElement("body")
    body.setAttribute("class", "bg-gray-100")
    # Page title
    page_title = doc.createElement("h1")
    page_title.setAttribute("class", "text-4xl font-bold text-center text-gray-900 mb-12")
    page_title.appendChild(doc.createTextNode(slide_title))
    container = doc.createElement("div")
    container.setAttribute("class", "max-w-screen-lg mx-auto p-8 space-y-16")
    container.appendChild(page_title)
 
    for img in images:
        slide = doc.createElement("div")
        slide.setAttribute("class", "bg-white rounded-lg shadow-lg p-4 flex justify-center")
 
        img_tag = doc.createElement("img")
        img_tag.setAttribute("src", img)
        img_tag.setAttribute("class", "max-w-full max-h-screen object-contain")
        slide.appendChild(img_tag)
        container.appendChild(slide)
 
    body.appendChild(container)
    html.appendChild(body)
 
    with open(output_path, "w") as f:
        f.write(doc.toprettyxml(indent="  "))
 
def main():
    parser = argparse.ArgumentParser(description="Compress images and generate a Tailwind-styled HTML slideshow")
    parser.add_argument("input_dir", help="Directory containing input images")
    parser.add_argument("output_dir", help="Directory to save output images and index.html")
    parser.add_argument("--skip", action="store_true", help="Skip compression and renaming, use existing images")
    # add a title argument
    parser.add_argument("--title", default="Slideshow",help="Title of the slideshow")
 
    args = parser.parse_args()
 
    input_dir = Path(args.input_dir)
    output_dir = Path(args.output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)
 
    supported_exts = [".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".webp"]
    images = [f for f in input_dir.iterdir() if f.suffix.lower() in supported_exts]
    if args.skip:
            sorted_imgs = [str(f.name) for f in sorted(images)]
            for f in images:
                target = output_dir / f.name
                if not target.exists():
                    target.write_bytes(f.read_bytes())
    else:
        timestamp_to_file = {}
        for img in images:
            ts = get_creation_time(img)
            new_name = f"{ts}.webp"
            output_file = output_dir / new_name
            compress_to_webp(img, output_file)
            timestamp_to_file[ts] = new_name
        sorted_imgs = [str(timestamp_to_file[k]) for k in sorted(timestamp_to_file)]
    generate_html(args.title, sorted_imgs, output_dir / "index.html")
 
if __name__ == "__main__":
    main()