How to automatically screenshot KiCad library visual diffs

  1. Download the visual diff artifacts file from the relevant CI job.
  2. Unzip the file.
  3. Run the following Python script in the unzipped directory:
python ScreenshotVisualDiff.py diffs
#!/usr/bin/env python3
# Find HTML files in "diffs" dir recursively
import os
import asyncio
from pyppeteer import launch
from urllib.parse import quote
from tqdm import tqdm

import argparse

parser = argparse.ArgumentParser(description='Screenshot Visual Diff')
parser.add_argument('diffs_dir', type=str, help='Directory containing visual diff HTMLs. Just download & unzip the artifacts.')
args = parser.parse_args()

def find_diff_html_files(directory):
    html_files = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith('.html') and not "index.html" in file:
                html_files.append(os.path.join(root, file))
    return html_files

diff_files = find_diff_html_files(args.diffs_dir)

async def screenshot_file(diff_file):
    browser = await launch({
        "defaultViewport": {"width": 1920, "height": 1080}
    })
    page = await browser.newPage()
    # Open file
    encoded_diff_file = quote(diff_file)
    url = f"file://{os.path.abspath(encoded_diff_file)}#visual-diff"  
    await page.goto(url)
    # Make screenshot
    await page.screenshot({'path': diff_file.replace(".html", ".png")})
    # Cleanup
    await browser.close()

# Check if an event loop is already running

def get_or_create_eventloop():
    try:
        return asyncio.get_event_loop()
    except RuntimeError as ex:
        if "There is no current event loop in thread" in str(ex):
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            return asyncio.get_event_loop()
        else:
            raise ex


async def run():
    loop = get_or_create_eventloop()
    for diff_file in tqdm(diff_files, desc="Processing files"):
        tqdm.write(f"Processing: {diff_file}")
        future = loop.create_task(screenshot_file(diff_file))
        await future

asyncio.run(run())