dev
sh 88 lines 2.22 KB
Raw
1 #!/usr/bin/env bash
2
3 set -euo pipefail
4
5 INPUT_STRING="${1:?Usage: $0 <seed_string> <result.png>}"
6 OUTPUT="${2:?Usage: $0 <seed_string> <result.png>}"
7
8 if [[ ! -f "$OUTPUT" ]]; then
9 echo "Error: '$OUTPUT' not found." >&2
10 exit 1
11 fi
12
13 read -r IMG_W IMG_H < <(
14 ffprobe -v error \
15 -select_streams v:0 \
16 -show_entries stream=width,height \
17 -of csv=p=0 \
18 "$OUTPUT" | tr ',' ' '
19 )
20
21 if [[ -z "$IMG_W" || -z "$IMG_H" ]]; then
22 echo "Error: could not read dimensions from '$OUTPUT'." >&2
23 exit 1
24 fi
25
26 HASH=$(printf '%s' "$INPUT_STRING" | sha256sum | awk '{print $1}')
27
28 chunk1=$(( 16#${HASH:0:8} ))
29 chunk2=$(( 16#${HASH:8:8} ))
30 chunk3=$(( 16#${HASH:16:8} ))
31 chunk4=$(( 16#${HASH:24:8} ))
32
33 R=$(( chunk1 % 256 ))
34 G=$(( chunk2 % 256 ))
35 B=$(( chunk3 % 256 ))
36
37 ROTATION=$(( chunk4 % 360 ))
38
39 R2=$(( (chunk1 / 256) % 256 ))
40 G2=$(( (chunk2 / 256) % 256 ))
41 B2=$(( (chunk3 / 256) % 256 ))
42
43 STRLEN=${#INPUT_STRING}
44 TILE_SIZE=$(( 64 + (STRLEN % 192) ))
45
46 GEQ_R="between(mod((X+Y),${TILE_SIZE}),0,$(( TILE_SIZE / 2 )))*${R} + between(mod((X+Y),${TILE_SIZE}),$(( TILE_SIZE / 2 + 1 )),${TILE_SIZE})*${R2}"
47 GEQ_G="between(mod((X+Y),${TILE_SIZE}),0,$(( TILE_SIZE / 2 )))*${G} + between(mod((X+Y),${TILE_SIZE}),$(( TILE_SIZE / 2 + 1 )),${TILE_SIZE})*${G2}"
48 GEQ_B="between(mod((X+Y),${TILE_SIZE}),0,$(( TILE_SIZE / 2 )))*${B} + between(mod((X+Y),${TILE_SIZE}),$(( TILE_SIZE / 2 + 1 )),${TILE_SIZE})*${B2}"
49
50 ROTATION_RAD=$(awk "BEGIN { printf \"%.6f\", ${ROTATION} * 3.14159265358979 / 180 }")
51
52 TMPFILE=$(mktemp "${OUTPUT}.tmp.XXXXXX.png")
53 trap 'rm -f "$TMPFILE"' EXIT
54
55 ffmpeg -y \
56 -f lavfi -i "nullsrc=size=${IMG_W}x${IMG_H}:rate=1" \
57 -i "$OUTPUT" \
58 -filter_complex "
59 [0:v]geq=
60 r='${GEQ_R}':
61 g='${GEQ_G}':
62 b='${GEQ_B}':
63 a=255,
64 format=rgba[bg];
65
66 [1:v]format=rgba,
67 geq=
68 r='r(X,Y)':
69 g='g(X,Y)':
70 b='b(X,Y)':
71 a='if(gte(r(X,Y)+g(X,Y)+b(X,Y),720),0,if(lte(r(X,Y)+g(X,Y)+b(X,Y),15)*gte(alpha(X,Y),250),0,alpha(X,Y)))',
72 rotate=
73 angle=${ROTATION_RAD}:
74 fillcolor=none:
75 ow=rotw(${ROTATION_RAD}):
76 oh=roth(${ROTATION_RAD})[ovr];
77
78 [bg][ovr]overlay=
79 x=(W-w)/2:
80 y=(H-h)/2:
81 format=auto[out]
82 " \
83 -map "[out]" \
84 -frames:v 1 \
85 -update 1 \
86 "$TMPFILE"
87
88 mv "$TMPFILE" "$OUTPUT"