Last active
October 2, 2019 21:16
-
-
Save porglezomp/215fc503ef14b09b93d9b736daeafa60 to your computer and use it in GitHub Desktop.
A tool to chop GIFs into 25 discord emoji.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
input=$1 | |
output=$2 | |
prefix=$3 | |
if [ -z "$input" -o -z "$output" ]; then | |
echo "Usage: $0 <input> <output> [prefix]" | |
exit 1 | |
fi | |
function red () { printf "\e[31m$1\e[0m\n" ${@:2}; } | |
function green () { printf "\e[32m$1\e[0m\n" ${@:2}; } | |
function yellow () { printf "\e[33m$1\e[0m\n" ${@:2}; } | |
if ! which convert >/dev/null 2>&1; then | |
red "ERROR: The ImageMagick convert command isn't installed." | |
exit 1 | |
elif ! convert --version | grep -q 'ImageMagick'; then | |
red "ERROR: The convert command doesn't seem to be ImageMagick." | |
exit 1 | |
fi | |
mkdir -p "$output" | |
temp=$(mktemp).gif | |
# Get GIF dimensions | |
parts=$(file "$input" | sed 's/.* \(.*\) x \(.*\)/\1 \2/') | |
let w=$(echo $parts | cut -d' ' -f1) | |
let h=$(echo $parts | cut -d' ' -f2) | |
# Ensure that the GIF dimensions are a multiple of 5 | |
let w2=$w/5*5 | |
let h2=$h/5*5 | |
if [ $w -ne $w2 -o $h -ne $h2 ]; then | |
convert "$input" -coalesce -resize "$w"x"$h" "$temp" | |
else | |
# We always ensure it ends up in "$temp" | |
cp "$input" "$temp" | |
fi | |
# Discord requires emoji to be <= 256K, so we have these to check. | |
function size () { printf "%d" $(wc -c < "$1"); } | |
function size_ok () { [ $(size "$1") -lt 262144 ]; } | |
# This will run a gifsicle optimization command and report its progress. | |
function opt () { | |
local temp; local name; temp=$1; name=$2; shift 2 | |
gifsicle "$name" $@ -o "$temp" | |
if size_ok "$temp"; then | |
mv "$temp" "$name" | |
green "passed" | |
return 0 | |
else | |
yellow "failed (%d)" $(size "$temp") | |
return 1 | |
fi | |
} | |
# Try increasingly agressive optimizations with gifsicle until it's an OK size. | |
function optimize () { | |
local name; local temp; local level; name=$1 | |
temp=$(mktemp).gif | |
for level in $(seq 3); do | |
printf "Optimize level $level... " | |
opt "$temp" "$name" -O"$level" && return 0 | |
done | |
printf "Optimize lossy=100... " | |
opt "$temp" "$name" -O3 --lossy=100 --dither && return 0 | |
printf "Optimize lossy=250... " | |
opt "$temp" "$name" -O3 --lossy=250 --dither && return 0 | |
printf "Optimize lossy=250, colors=128... " | |
opt "$temp" "$name" -O3 --lossy=250 --colors=128 --dither && return 0 | |
printf "Optimize lossy=500... " | |
opt "$temp" "$name" -O3 --lossy=500 --dither && return 0 | |
printf "Optimize lossy=500, colors=128... " | |
opt "$temp" "$name" -O3 --lossy=500 --colors=128 --dither && return 0 | |
printf "Optimize lossy=1000... " | |
opt "$temp" "$name" -O3 --lossy=1000 --dither && return 0 | |
printf "Optimize lossy=1000, colors=128... " | |
opt "$temp" "$name" -O3 --lossy=1000 --colors=128 --dither && return 0 | |
printf "Optimize lossy=1000, colors=64... " | |
opt "$temp" "$name" -O3 --lossy=1000 --colors=64 --dither && return 0 | |
mv "$temp" "$name" | |
return 1 | |
} | |
# Loop over each image | |
let w=$w2/5 | |
let h=$h2/5 | |
let i=0 | |
trap "exit 130" INT; trap "exit 131" QUIT | |
for y in $(seq 0 4); do | |
for x in $(seq 0 4); do | |
let i++ | |
let x0=$x*$w | |
let y0=$y*$h | |
printf "Cropping #%02d... " $i | |
name=$(printf "%s/%s%02d.gif" "$output" "$prefix" "$i") | |
convert "$temp" \ | |
-coalesce -repage 0x0 -crop "$w"x"$h"+"$x0"+"$y0" +repage \ | |
-layers Optimize "$name" | |
green "done" | |
if ! size_ok "$name"; then | |
bytes=$(size "$name") | |
yellow "$name is oversize ($bytes bytes), trying to compress it..." | |
if ! which gifsicle >/dev/null 2>&1; then | |
red "WARNING: Optimizing GIFs requires gifsicle. Skipping." | |
continue | |
fi | |
if optimize "$name"; then | |
bytes=$(size "$name") | |
green "Successfully reduced to %d bytes." $bytes | |
else | |
bytes=$(size "$name") | |
red "Compression failed, size is %d bytes." $bytes | |
fi | |
fi | |
done | |
done | |
rm "$temp" | |
echo; echo | |
prefix=$(echo "$prefix" | sed 's/[ -]//g') | |
for i in $(seq 25); do | |
printf ":%s%02d:" "$prefix" "$i" | |
let step=$i%5; if [ $step -eq 0 ]; then echo; fi | |
done | |
echo; echo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment