Skip to content

Instantly share code, notes, and snippets.

@porglezomp porglezomp/chopper.sh
Last active Oct 2, 2019

Embed
What would you like to do?
A tool to chop GIFs into 25 discord emoji.
#!/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
You can’t perform that action at this time.