Skip to content

Instantly share code, notes, and snippets.

@NoTengoBattery
Created August 4, 2021 04:10
Show Gist options
  • Save NoTengoBattery/1f65d47a5ebebc7dd49b51fceb7e21a6 to your computer and use it in GitHub Desktop.
Save NoTengoBattery/1f65d47a5ebebc7dd49b51fceb7e21a6 to your computer and use it in GitHub Desktop.
Convert TGS to APNG for Signal
#!/bin/zsh
# Convert Telegram stickets (TGS) and probably any lottie animation to a highly compressed and compact
# APNG for Signal.
#
# Copyright (C) 2021 Oever González <software@notengobattery.com>
# Open source under the MIT license.
conversor() {
WORKING_DIR=$(mktemp -d)
for file in "$@"; do
BASE_NAME=$(basename "$file")
UNCOMPRESSED="$WORKING_DIR/$BASE_NAME.json"
FRAME_DIR="$WORKING_DIR/$BASE_NAME"
BASE_FILE="$WORKING_DIR/${BASE_NAME}"
BASE_STRIP="$WORKING_DIR/${BASE_NAME}_strip.png"
RES=${RES:-256}
r=$(($RES*2))
gunzip -c "$file" > "$UNCOMPRESSED" || return $?
TGS_INFO=$(tgs2png -i "$UNCOMPRESSED") || return $?
mkdir -p "$FRAME_DIR"
FRAMES=$(print "$TGS_INFO" | awk -F'[ ,=]' '{print $5}')
_FPS=$(print "$TGS_INFO" | awk -F'[ ,=]' '{print $8}')
DURATION=$(print "$TGS_INFO" | awk -F'[ ,=]' '{print $11}')
for ((frame=0; frame<$FRAMES; frame++)); do
f=$(($frame+1))
tgs2png -s $(($r*4))x0 -o $frame -n 1 "$UNCOMPRESSED" > "$FRAME_DIR/$f.png" &
done
wait
ffmpeg -r $_FPS -i "$FRAME_DIR/%d.png" -vcodec apng -vf scale=${r}:-1:flags=neighbor:sws_dither=none \
-r ${FPS:=20} -plays 0 "${BASE_FILE}.apng"
apngdis "${BASE_FILE}.apng" -s &>/dev/null
pngnq-s9 -L -Qn -T15 -n128 -e '.1.png' "$BASE_STRIP"
mv "${BASE_FILE}_strip.1.png" "$BASE_STRIP"
pngquant --nofs --strip --ext '.2.png' "$BASE_STRIP"
ffmpeg -r $_FPS -i "${BASE_FILE}_strip.2.png" -vcodec png -vf scale=${RES}:-1:flags=area:sws_dither=none \
-pix_fmt rgba -y "${BASE_FILE}_strip.png"; rm "${BASE_FILE}_strip.2.png"
pngnq-s9 -L -Qn -T15 -n96 -e '.1.png' "$BASE_STRIP"
mv "${BASE_FILE}_strip.1.png" "$BASE_STRIP"
pngquant --posterize 4 --nofs --strip --ext '.2.png' "$BASE_STRIP"
mv "${BASE_FILE}_strip.2.png" "$BASE_STRIP"
TFRAMES=$(imgp -x 100% -w "$BASE_STRIP" | awk -F'[x ]' '/->.*x/{print $2/$1}')
apngasm "${BASE_FILE}_result.apng" "$BASE_STRIP" 1 $FPS -vs$TFRAMES -z2 -i64
BYTE_SIZE=$(stat -c "%s" "${BASE_FILE}_result.apng")
FILE_SIZE=$(printf '%g' $(($BYTE_SIZE / 1024.0)))
if (($FILE_SIZE>300.0)); then rm -r "$WORKING_DIR"; return 1; fi
mv "${BASE_FILE}_result.apng" "$PWD/${BASE_NAME}.$RES.$FPS.apng" || return $?
echo "${BYTE_SIZE}: $BASE_NAME ($FILE_SIZE k) => { Resolution: $RES ; FPS: $FPS ; }"
done
rm -r "$WORKING_DIR"
}
{{ conversor "$@"; } || \
RES=224 conversor "$@"; } || \
RES=208 conversor "$@";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment