返回 html-ppt-skill
render.sh
根目录 / scripts / render.sh
1 #!/usr/bin/env bash
2 # html-ppt :: render.sh — headless Chrome screenshot(s)
3 #
4 # Usage:
5 # render.sh <html-file> # one PNG, slide 1
6 # render.sh <html-file> <N> # N PNGs, slides 1..N, via #/k
7 # render.sh <html-file> all # autodetect .slide count
8 # render.sh <html-file> <N> <out-dir> # custom output dir
9 #
10 # Requires: Google Chrome at /Applications/Google Chrome.app (macOS).
11
12 set -euo pipefail
13
14 CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
15 if [[ ! -x "$CHROME" ]]; then
16 echo "error: Chrome not found at $CHROME" >&2
17 exit 1
18 fi
19
20 FILE="${1:-}"
21 if [[ -z "$FILE" ]]; then
22 echo "usage: render.sh <html> [N|all] [out-dir]" >&2
23 exit 1
24 fi
25 if [[ ! -f "$FILE" ]]; then
26 echo "error: $FILE not found" >&2
27 exit 1
28 fi
29
30 COUNT="${2:-1}"
31 OUT="${3:-}"
32
33 ABS="$(cd "$(dirname "$FILE")" && pwd)/$(basename "$FILE")"
34 STEM="$(basename "${FILE%.*}")"
35
36 # Count <section> elements whose class attribute carries "slide" as a whole
37 # token. A plain `class="slide"` match misses every slide with an extra class
38 # (slide is-active, slide dark, slide t-violet …), and a loose \bslide\b would
39 # also match class="slide-number".
40 count_slides() {
41 grep -Eco '<section[^>]*class="([^"]*[[:space:]])?slide([[:space:]][^"]*)?"' "$1" || true
42 }
43
44 if [[ "$COUNT" == "all" ]]; then
45 COUNT="$(count_slides "$FILE")"
46 if [[ -z "$COUNT" || "$COUNT" -lt 1 ]]; then
47 echo "warning: no <section class=\"slide\"> found in $FILE — rendering 1 page" >&2
48 COUNT=1
49 fi
50 fi
51
52 if ! [[ "$COUNT" =~ ^[0-9]+$ ]] || [[ "$COUNT" -lt 1 ]]; then
53 echo "error: slide count must be a positive integer or 'all' (got: $COUNT)" >&2
54 exit 1
55 fi
56
57 if [[ -z "$OUT" && "$COUNT" -gt 1 ]]; then
58 OUT="$(dirname "$FILE")/${STEM}-png"
59 fi
60
61 # Chrome does not create the target directory; without this it exits 0 having
62 # written nothing.
63 if [[ -n "$OUT" ]]; then
64 if [[ "$OUT" == *.png ]]; then
65 mkdir -p "$(dirname "$OUT")"
66 else
67 mkdir -p "$OUT"
68 fi
69 fi
70
71 render_one() {
72 local url="$1" target="$2"
73 "$CHROME" \
74 --headless=new \
75 --disable-gpu \
76 --hide-scrollbars \
77 --no-sandbox \
78 --virtual-time-budget=4000 \
79 --window-size=1920,1080 \
80 --screenshot="$target" \
81 "$url" >/dev/null 2>&1 || true
82 # Chrome reports success even when it could not write the file, so the only
83 # trustworthy signal is the file itself.
84 if [[ ! -s "$target" ]]; then
85 echo " ✗ $target — not written" >&2
86 return 1
87 fi
88 echo " ✔ $target"
89 }
90
91 FAILED=0
92
93 if [[ "$COUNT" == "1" ]]; then
94 if [[ -z "$OUT" ]]; then
95 OUT_FILE="$(dirname "$FILE")/${STEM}.png"
96 elif [[ "$OUT" == *.png ]]; then
97 OUT_FILE="$OUT"
98 else
99 OUT_FILE="$OUT/${STEM}.png"
100 fi
101 render_one "file://$ABS" "$OUT_FILE" || FAILED=$((FAILED + 1))
102 else
103 for i in $(seq 1 "$COUNT"); do
104 render_one "file://$ABS#/$i" "$OUT/${STEM}_$(printf '%02d' "$i").png" \
105 || FAILED=$((FAILED + 1))
106 done
107 fi
108
109 if [[ "$FAILED" -gt 0 ]]; then
110 echo "error: $FAILED of $COUNT slide(s) were not written from $FILE" >&2
111 exit 1
112 fi
113
114 echo "done: rendered $COUNT slide(s) from $FILE"
115
115 lines BASH