Skip to content

Instantly share code, notes, and snippets.

@queercat
Last active February 2, 2025 08:13
Show Gist options
  • Select an option

  • Save queercat/d49c58049d82ab76380f5f00ec6cce3d to your computer and use it in GitHub Desktop.

Select an option

Save queercat/d49c58049d82ab76380f5f00ec6cce3d to your computer and use it in GitHub Desktop.
# Copyright (c) 2025 May Tusek
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
ART="
⠀⠀⢰⠊⠉⠲⣄⡴⠚⠉⢳⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠔⠒⠉⠉⠒⢦⡀⠀⠀⠀⣀⠀⠀⠀⠀⡀⠀⠀⠀⠀
⠀⠀⠘⣄⠀⠀⠈⠀⠀⢀⡼⠁⠀⠀⠀⠀⠀⢠⡤⠀⢤⢠⣼⣿⣷⡾⣥⡀⠀⠀⠀⠀⠀⡿⠀⢰⡻⠋⠙⡆⡞⠋⠙⣷⠀⠀⠀
⠀⠀⠀⠈⠑⢄⠀⢀⠔⠉⠀⠀⠀⠀⠀⠀⠀⠉⠀⠀⠀⠈⠹⣿⣿⣷⣿⠇⠀⠀⠀⠀⠀⠀⠀⠸⣧⡹⠤⠮⠧⠀⣠⠟⠀⡀⠀
⠀⡴⠀⠀⠀⠈⢣⠎⠀⠀⣤⠔⠁⠀⠀⠀⠢⣄⠀⠀⠀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠲⡄⣼⠉⠑⠴⠋⢩⠆
⠈⢀⣀⡀⡀⣀⠀⠀⠀⣮⠃⠀⠀⠀⠀⠀⠀⠈⢆⠀⠀⠺⠆⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠑⢄⢀⡔⠉⠀
⠀⢧⠀⠁⠀⡸⠀⠀⣀⣟⠀⠀⠀⠀⠀⠀⠀⠀⠀⡕⠟⣀⡀⠉⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⣀⡀⠀⢀⡀⠀⠀⠋⠀⠀⠀
⠀⠀⠑⣤⠊⠀⣰⡞⡏⠈⢳⡤⠄⠒⠒⠒⢄⠀⠀⠐⠀⠉⠁⠀⣀⡤⣤⡀⢀⣀⠀⠈⠀⠀⠀⠸⣅⡈⠀⣀⡼⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⢰⡿⠀⠱⢤⠌⢷⡀⠐⠒⠲⢄⠱⣀⡀⠀⣀⠤⠚⠁⣠⡾⠉⠉⠉⠉⠓⢦⡀⠀⠀⠈⠻⡼⠉⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠸⣧⠀⠀⠈⠧⣌⣷⣄⠀⠀⠀⠀⠀⠀⠉⠓⢤⡀⠀⠉⠀⠀⠀⠀⠀⠀⠈⢷⠀⠀⠀⠀⠀⣀⠤⢄⠀⠀⠀⠀⠀
⠀⢀⣞⡉⠙⡆⠙⣦⡀⠀⠀⠀⠐⠊⢳⡄⣰⣸⣴⠶⢤⡀⠀⠱⡠⠴⢲⡚⠒⢦⡀⠀⠀⢸⡆⠀⠀⠀⠀⢇⠀⠀⠁⠀⠀⠀⠀
⠀⠀⡠⣃⠜⠁⣀⣴⠟⠂⠀⠀⠀⠀⢀⡇⢱⡟⠚⣍⢢⢹⣄⠀⠀⠀⠀⣷⡀⠀⣧⠀⠀⡼⠆⠀⠀⠠⡒⠊⠓⢢⠀⠀⠀⠀⠀
⠀⢀⠟⠁⠀⢰⡿⣼⠀⠀⠀⣀⣄⣠⠎⠀⢸⣄⣴⣿⡆⡆⡿⠀⢀⣴⡛⡿⠇⣠⠃⣠⠞⠁⡀⠀⠀⠀⠱⡄⡰⠋⠁⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠘⣿⠸⡄⠀⠀⠉⠉⠙⣆⠀⠲⣿⣾⣿⠣⢱⠃⢠⣃⣼⡰⢡⣚⠁⢉⣓⡾⠋⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠸⣧⡙⠲⠤⡞⠀⠀⣸⢄⠀⠈⠉⠁⠒⣥⡀⣿⣿⡟⠁⠀⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⣀⣀⡀⠀⠀
⠀⠀⠀⠀⠀⠀⢀⡞⠉⠀⠀⢧⠀⢠⠏⠀⠑⠤⣀⠀⠀⡟⠀⠌⡻⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢼⡀⡠⠳⠟⢦⢠⡇⠀⠀
⢞⠉⠳⠔⠉⢹⠸⡇⠀⠀⠀⠠⢽⡃⠀⠀⢀⡤⠈⣏⣉⣫⡊⠉⠀⠀⠀⠀⣀⡴⠖⠛⠉⠙⠛⢦⡄⠀⠑⢾⣦⣴⠷⠋⠀⠀⠀
⠈⠓⢲⢀⠔⠃⢸⣝⠦⢄⣀⣀⣈⡧⠀⣰⠃⠀⠉⠀⠀⠀⢱⠀⠀⠀⢀⠞⠁⣀⣀⠤⣄⡀⠀⠀⠹⡆⠀⠀⠹⠏⠀⠀⠀⠀⠀
⠀⡠⠺⠏⠀⠀⠸⢎⡉⣱⠋⠁⠙⢢⡀⢇⠀⢀⠠⠄⡀⡰⢎⠀⠀⢀⣏⡴⣊⣥⣄⡀⠀⠈⢦⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⢀⡀⠉⢹⠀⠀⠀⢠⠱⣠⠏⠁⠀⠀⢠⡗⠉⠐⠐⠀⠔⢉⡁⡰⠋⠁⠀⠀⣸⠀⠀⣟⣸⡀⠉⡙⠀⠀⠀⠀⠀
⠀⠀⢀⢤⣶⣶⣦⠄⠸⣳⠀⠀⠀⠀⢧⠇⠀⠀⠀⠀⣞⠒⢺⠉⢰⠋⠉⡝⢰⡃⠀⠀⣀⣔⣁⠀⠈⠁⠀⠘⢿⡆⠀⠀⠀⠀⠀
⢸⣿⣿⢿⣯⡤⣼⣷⣦⢻⠀⠀⠀⠀⡎⠀⠀⠀⠀⢠⡏⠀⡎⠀⡎⠀⡼⠀⡜⣧⣀⣀⣀⠀⠈⢳⡀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀
⢼⣾⣿⣿⡿⣿⣿⣹⣏⠋⡇⠀⠀⢰⠁⠀⠀⠀⢀⡜⠃⢰⠁⢰⠁⢰⠁⡼⠋⠁⠙⠒⠞⠃⠀⢀⡇⠀⠀⠀⢠⠇⡔⠀⠀⠀⠀
⠈⢿⣷⣿⡟⡗⣒⡫⢾⠀⠛⡄⠀⠘⠲⣤⠔⠺⠁⠀⠀⠀⠀⠈⠀⠊⢰⡁⠀⠀⠀⢲⢄⣀⡤⠊⠀⠀⠀⣰⠏⠀⠙⢧⠀⠀⠀
⠀⠀⠉⠒⠊⠀⠀⠀⢸⠄⢸⠈⢩⠂⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⡃⠀⠀⢀⠞⠀⠀⠀⠀⠀⠰⣎⠁⠀⠀⠀⠀⠀⠀⠀
"
#!/bin/bash
if [ "$1" = "--help" ] || [ "$1" = "-h" ] || [ "$1" = "help" ] || [ -z "$1" ]; then
echo "Usage: $0 <path-to-gif> <output-path> <optional: --and-flip-h>"
exit 0
fi
REQUIREMENTS=("ffmpeg" "jq" "ffprobe" "bc" "mktemp")
for req in "${REQUIREMENTS[@]}"; do
if ! command -v "$req" &> /dev/null; then
echo "$req could not be found and is required to run this script."
exit 1
fi
done
if !command -v ffmpeg &> /dev/null; then
echo "FFmpeg could not be found and is required to run this script."
exit 1
fi
GIF_PATH=$1
OUTPUT_PATH=$2
if [ ! -f "$GIF_PATH" ]; then
echo "Please provide a path to a valid GIF file."
exit 1
fi
TEMP_DIR=$(mktemp -d)
if [ ! -d "$TEMP_DIR" ]; then
echo "Failed to create temporary directory."
exit 1
fi
ffmpeg -i "$GIF_PATH" "$TEMP_DIR/frame_%d.png"
if [ $? -ne 0 ]; then
echo "Failed to create frames."
exit 1
fi
TOTAL_FRAMES=$(ls "$TEMP_DIR"/*.png | wc -l | tr -d ' ')
SIZE=$(echo "sqrt($TOTAL_FRAMES) + 1" | bc)
IMAGE_INFO=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of json=compact=1 "$TEMP_DIR/frame_1.png")
IMAGE_WIDTH=$(echo "$IMAGE_INFO" | jq -r '.streams[0].width')
IMAGE_HEIGHT=$(echo "$IMAGE_INFO" | jq -r '.streams[0].height')
if [[ $* == *--and-flip-h* ]]; then
for file in "$TEMP_DIR"/*.png; do
base_name=$(basename "$file" .png)
number=$(echo "$base_name" | grep -oE '[0-9]+')
number=$((number + $TOTAL_FRAMES))
ffmpeg -i "$file" -vf "hflip" "$TEMP_DIR/frame_${number}.png" -y
done
TOTAL_FRAMES=$(ls "$TEMP_DIR"/*.png | wc -l | tr -d ' ')
SIZE=$(echo "sqrt($TOTAL_FRAMES) + 1" | bc)
fi
ffmpeg -i "$TEMP_DIR/frame_%d.png" -vf "tile=$SIZE\x$SIZE" "$OUTPUT_PATH"
rm -rf "$TEMP_DIR"
echo "$ART"
echo "Spritesheet Path: $OUTPUT_PATH"
echo "Frame Count: $TOTAL_FRAMES"
echo "Image Dimensions: $IMAGE_WIDTH x $IMAGE_HEIGHT"
echo "Grid Size (rows x columns): $SIZE x $SIZE"
echo "Offset (x, y): 0, 0"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment