mirror of
https://github.com/lewislulu/html-ppt-skill.git
synced 2026-09-14 18:25:55 +08:00
9516a811c6
Two independent defects, both of which hand the user a wrong artefact while reporting success. 1. `render.sh deck.html 3 out/png` wrote nothing and still printed three ✔. `mkdir -p "$OUT"` only ran in the branch that *derives* an output directory, so an explicitly-passed directory was never created. Chrome exits 0 when it cannot write the screenshot, and `render_one()`'s ✔ was unconditional — the run ended with "done: rendered 3 slide(s)" and zero files on disk. 2. `render.sh deck.html all` under-rendered 13 of the 15 bundled decks. `grep -c 'class="slide"'` is an exact-string match, but real slides carry extra classes (`slide is-active`, `slide dark`, `slide t-violet`). Across templates/full-decks that counted 95 of 119 slides; dir-key-nav-minimal counted 0, fell through to the `COUNT=1` fallback, and exported a single PNG for an 8-slide deck without a warning. Changes: - create the output directory on every path that has one (accepting either a directory, as documented, or an explicit *.png file path) - verify each screenshot exists and is non-empty before printing ✔; otherwise print ✗ to stderr and exit non-zero - count slides by matching `slide` as a whole class token on `<section>`, which yields 119/119 and does not match `class="slide-number"` - warn on stderr when the fallback count of 1 is used - single-slide renders with an out-dir now write <out-dir>/<stem>.png instead of treating the directory as the file name - reject a non-numeric slide count instead of passing it to seq Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
115 lines
3.0 KiB
Bash
Executable File
115 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# html-ppt :: render.sh — headless Chrome screenshot(s)
|
|
#
|
|
# Usage:
|
|
# render.sh <html-file> # one PNG, slide 1
|
|
# render.sh <html-file> <N> # N PNGs, slides 1..N, via #/k
|
|
# render.sh <html-file> all # autodetect .slide count
|
|
# render.sh <html-file> <N> <out-dir> # custom output dir
|
|
#
|
|
# Requires: Google Chrome at /Applications/Google Chrome.app (macOS).
|
|
|
|
set -euo pipefail
|
|
|
|
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
if [[ ! -x "$CHROME" ]]; then
|
|
echo "error: Chrome not found at $CHROME" >&2
|
|
exit 1
|
|
fi
|
|
|
|
FILE="${1:-}"
|
|
if [[ -z "$FILE" ]]; then
|
|
echo "usage: render.sh <html> [N|all] [out-dir]" >&2
|
|
exit 1
|
|
fi
|
|
if [[ ! -f "$FILE" ]]; then
|
|
echo "error: $FILE not found" >&2
|
|
exit 1
|
|
fi
|
|
|
|
COUNT="${2:-1}"
|
|
OUT="${3:-}"
|
|
|
|
ABS="$(cd "$(dirname "$FILE")" && pwd)/$(basename "$FILE")"
|
|
STEM="$(basename "${FILE%.*}")"
|
|
|
|
# Count <section> elements whose class attribute carries "slide" as a whole
|
|
# token. A plain `class="slide"` match misses every slide with an extra class
|
|
# (slide is-active, slide dark, slide t-violet …), and a loose \bslide\b would
|
|
# also match class="slide-number".
|
|
count_slides() {
|
|
grep -Eco '<section[^>]*class="([^"]*[[:space:]])?slide([[:space:]][^"]*)?"' "$1" || true
|
|
}
|
|
|
|
if [[ "$COUNT" == "all" ]]; then
|
|
COUNT="$(count_slides "$FILE")"
|
|
if [[ -z "$COUNT" || "$COUNT" -lt 1 ]]; then
|
|
echo "warning: no <section class=\"slide\"> found in $FILE — rendering 1 page" >&2
|
|
COUNT=1
|
|
fi
|
|
fi
|
|
|
|
if ! [[ "$COUNT" =~ ^[0-9]+$ ]] || [[ "$COUNT" -lt 1 ]]; then
|
|
echo "error: slide count must be a positive integer or 'all' (got: $COUNT)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "$OUT" && "$COUNT" -gt 1 ]]; then
|
|
OUT="$(dirname "$FILE")/${STEM}-png"
|
|
fi
|
|
|
|
# Chrome does not create the target directory; without this it exits 0 having
|
|
# written nothing.
|
|
if [[ -n "$OUT" ]]; then
|
|
if [[ "$OUT" == *.png ]]; then
|
|
mkdir -p "$(dirname "$OUT")"
|
|
else
|
|
mkdir -p "$OUT"
|
|
fi
|
|
fi
|
|
|
|
render_one() {
|
|
local url="$1" target="$2"
|
|
"$CHROME" \
|
|
--headless=new \
|
|
--disable-gpu \
|
|
--hide-scrollbars \
|
|
--no-sandbox \
|
|
--virtual-time-budget=4000 \
|
|
--window-size=1920,1080 \
|
|
--screenshot="$target" \
|
|
"$url" >/dev/null 2>&1 || true
|
|
# Chrome reports success even when it could not write the file, so the only
|
|
# trustworthy signal is the file itself.
|
|
if [[ ! -s "$target" ]]; then
|
|
echo " ✗ $target — not written" >&2
|
|
return 1
|
|
fi
|
|
echo " ✔ $target"
|
|
}
|
|
|
|
FAILED=0
|
|
|
|
if [[ "$COUNT" == "1" ]]; then
|
|
if [[ -z "$OUT" ]]; then
|
|
OUT_FILE="$(dirname "$FILE")/${STEM}.png"
|
|
elif [[ "$OUT" == *.png ]]; then
|
|
OUT_FILE="$OUT"
|
|
else
|
|
OUT_FILE="$OUT/${STEM}.png"
|
|
fi
|
|
render_one "file://$ABS" "$OUT_FILE" || FAILED=$((FAILED + 1))
|
|
else
|
|
for i in $(seq 1 "$COUNT"); do
|
|
render_one "file://$ABS#/$i" "$OUT/${STEM}_$(printf '%02d' "$i").png" \
|
|
|| FAILED=$((FAILED + 1))
|
|
done
|
|
fi
|
|
|
|
if [[ "$FAILED" -gt 0 ]]; then
|
|
echo "error: $FAILED of $COUNT slide(s) were not written from $FILE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "done: rendered $COUNT slide(s) from $FILE"
|