adding new files
This commit is contained in:
283
sixcat
Executable file
283
sixcat
Executable file
@ -0,0 +1,283 @@
|
||||
#!/bin/bash
|
||||
|
||||
# sixcat: Use sixel graphics to show an image inside a terminal.
|
||||
# sixgif: Use sixel graphics to play an animation inside a terminal.
|
||||
|
||||
# Version 1.0
|
||||
# hackerb9, June 2017
|
||||
|
||||
# Sixel graphics are supported by terminals such as the DEC VT340 and
|
||||
# emulators, such as 'xterm -ti vt340'.
|
||||
|
||||
# ImageMagick is required. (apt-get install imagemagick)
|
||||
|
||||
# The heart of this program is really just one line:
|
||||
#
|
||||
# convert foo.jpg sixel:-
|
||||
#
|
||||
# All the other lines are bells and whistles, mostly to make the image
|
||||
# look better by increasing the number of colors available.
|
||||
|
||||
|
||||
######################################################################
|
||||
# Configuration
|
||||
######################################################################
|
||||
|
||||
# Number of colors in the terminal's sixel palette.
|
||||
# (But also see the -x and -n options).
|
||||
default_numcolors=16 # Genuine vt340's had a 16-color palette.
|
||||
|
||||
# Maximum image size is terminal dependent, so we have to guess.
|
||||
geometry="-geometry 800x480>" # this was the actual vt340 resolution
|
||||
#geometry="-geometry 800x800>" # allows for portrait orientation
|
||||
#geometry="-geometry 1000x1000>" # maximum allowed in xterm322
|
||||
|
||||
# Should ImageMagick dither the image to make it look better?
|
||||
# (Use dither="" to disable.)
|
||||
dither="-dither floyd-steinberg"
|
||||
|
||||
# Maximum number of seconds to wait for a response from the terminal
|
||||
# after a color escape sequence request. Usually, terminals respond
|
||||
# much faster than 0.1 seconds, but I could imagine it needing to be
|
||||
# increased for slow links (e.g., RS232C).
|
||||
timeout=0.1
|
||||
|
||||
|
||||
######################################################################
|
||||
# Helper functions
|
||||
######################################################################
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename $0) [-x|-X|-n INTEGER] <imagefiles...>
|
||||
|
||||
-x: Force the use of xterm escape sequences to detect and
|
||||
change the palette size instead of defaulting to $default_numcolors.
|
||||
If the palette is smaller than 1024, it is set to 1024.
|
||||
|
||||
Note that -x is the default if \$TERM is "xterm".
|
||||
|
||||
-X: Just assume palette size is $default_numcolors.
|
||||
Does not use xterm escape sequences regardless of \$TERM.
|
||||
|
||||
-n INTEGER:
|
||||
Assume pallete size is INTEGER.
|
||||
Does not use xterm escape sequences regardless of \$TERM.
|
||||
|
||||
Note: if this program is called sixgif, it will play GIF animations
|
||||
in the top left instead of scrolling all the frames as multiple images.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
# Some functions to deal with checking and changing the number of
|
||||
# colors the terminal can show. Likely xterm specific, but YMMV.
|
||||
|
||||
getnumcolors() {
|
||||
# Query xterm for the palette size and print it.
|
||||
# (Negative numbers indicate errors.)
|
||||
colors 1 0
|
||||
}
|
||||
|
||||
resetnumcolors() {
|
||||
# Reset xterm back to its default number of colors.
|
||||
# Print the new number of colors (negative if an error occurred.)
|
||||
colors 2 0
|
||||
}
|
||||
|
||||
setnumcolors() {
|
||||
# Request xterm to change the number of colors in its palette.
|
||||
# Print the new number of colors (negative if an error occurred.)
|
||||
colors 3 $1
|
||||
}
|
||||
|
||||
colors() {
|
||||
# Send an xterm escape code request in the form: ^[[?1;3;1024S
|
||||
# Print the response value (or a negative number if an error occurs)
|
||||
csi=$'\e['
|
||||
action=$1 # Action. 1 to get, 2 to reset, 3 to set
|
||||
value=$2 # Number of colors to set
|
||||
returnvalue=-1
|
||||
|
||||
# Raw response is in the same form as request: ^[[?1;0;1024S
|
||||
# Let's parse it to be more manageable.
|
||||
IFS=";" \
|
||||
read -a REPLY -s -t $timeout -d "S" \
|
||||
-p "${csi}?1;${action};${value}S"
|
||||
|
||||
if [[ $? != 0 || ${#REPLY} == 0 ]]; then
|
||||
# No response to VT escape sequence. Maybe you are not an xterm?
|
||||
# Or, perhaps timeout is too short?
|
||||
returnvalue=-2
|
||||
elif [[ "${REPLY[1]}" == "3" ]]; then
|
||||
# Response code 3 means error. Likely too many colors requested.
|
||||
returnvalue=-3
|
||||
elif [[ "${REPLY[1]}" == "0" ]] ; then
|
||||
# 0 means okay. Yay!
|
||||
returnvalue=${REPLY[2]}
|
||||
else
|
||||
# If we get here, response was not in the format we expected.
|
||||
# Perhaps user typed during xterm response? Or cosmic rays?
|
||||
returnvalue=-4
|
||||
fi
|
||||
|
||||
echo $returnvalue
|
||||
}
|
||||
|
||||
waitforterminal() {
|
||||
# Send an escape sequence and wait for a response from the terminal.
|
||||
# This routine will let us know when an image transfer has finished
|
||||
# and it's okay to send escape sequences that request results.
|
||||
# (E.g., if we want to run resetnumcolors at the end of the program.)
|
||||
# WARNING. While this should work with any terminal, if it fails,
|
||||
# it'll end up waiting for approximately *forever* (i.e., 60 seconds).
|
||||
read -s -t 60 -d "c" -p $'\e[c'
|
||||
}
|
||||
|
||||
|
||||
debugeta() {
|
||||
# Given a number of bytes, estimate the amount of time its going
|
||||
# to take to send at the current TTY baud rate.
|
||||
# Mostly for larks as this will be completely bogus on terminal emulators.
|
||||
|
||||
len=$1
|
||||
|
||||
# Static variables to store TTY type and STTY speed.
|
||||
[[ "$TTY" ]] || TTY=$(tty)
|
||||
[[ "$SPEED" ]] || SPEED=$(stty speed) || SPEED=0
|
||||
|
||||
echo "sixel command length is $len bytes"
|
||||
|
||||
if [[ "$SPEED" -gt 0 ]]; then
|
||||
if [[ "$TTY" =~ /pt || "$TTY" =~ ttyp ]]; then
|
||||
echo "pseudoterminal detected (speed estimates only valid for real hardware)"
|
||||
fi
|
||||
echo "terminal speed is $SPEED bps"
|
||||
echo "estimated time to send: $((len*8/SPEED)) seconds"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# If the user hits ^C, we don't want them stuck in SIXEL mode
|
||||
cleanup() {
|
||||
echo -n $'\e[?80h' # Reenable sixel scrolling
|
||||
echo -n $'\e\\' # Escape sequence to stop SIXEL
|
||||
exit 0
|
||||
}
|
||||
trap cleanup SIGINT SIGHUP SIGABRT
|
||||
|
||||
|
||||
######################################################################
|
||||
# MAIN BEGINS HERE
|
||||
######################################################################
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
usage
|
||||
exit 1
|
||||
else
|
||||
case "$1" in
|
||||
-n|--num-colors) shift
|
||||
nflag="$1"
|
||||
shift
|
||||
# Just assume the palette is n colors. Do not bother checking or changing.
|
||||
# (Might be needed for some terminal emulators. I do not know.)
|
||||
if [[ "$nflag" -gt 0 ]]; then
|
||||
default_numcolors=$nflag
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-x|--force-xterm-colors) shift
|
||||
# Force xterm palette manipulation, regardless of $TERM
|
||||
# (Might be needed for some terminal emulators. I do not know.)
|
||||
xflag=yup
|
||||
;;
|
||||
-X|--disable-xterm-colors) shift
|
||||
# Disable xterm palette manipulation, regardless of $TERM
|
||||
# (Might be needed for some terminal emulators. I do not know.)
|
||||
Xflag=yup
|
||||
;;
|
||||
-*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
|
||||
numcolors=$default_numcolors
|
||||
|
||||
# Optionally detect and set the number of palette colors
|
||||
if [[ "$xflag" || -z "$Xflag" && -z "$nflag" && "$TERM" =~ ^xterm ]]; then
|
||||
# Since the VT340 only had a palette of 16 colors, we can vastly
|
||||
# improve the image if we tell xterm to increase it to 1024.
|
||||
# This would fail on a real VT340.
|
||||
palettechanged=yup
|
||||
oldnumcolors=$(getnumcolors)
|
||||
if [[ $oldnumcolors -lt 1024 ]]; then
|
||||
numcolors=$(setnumcolors 1024)
|
||||
if [[ $numcolors -le 0 ]]; then
|
||||
echo -e "\rTerminal did not accept escape sequence to increase color palette. Are you really an xterm?" >&2
|
||||
numcolors=$default_numcolors
|
||||
fi
|
||||
else
|
||||
# At least 1024 colors, so do not change anything
|
||||
numcolors=$oldnumcolors
|
||||
palettechanged=
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# Small optimization (saves half a second)
|
||||
if [[ $numcolors == 1024 ]]; then
|
||||
# Imagemagick already defaults to 1024 colors for sixel
|
||||
colors=""
|
||||
else
|
||||
colors="-colors $numcolors"
|
||||
fi
|
||||
|
||||
|
||||
# Print image filename after showing it? Yes, if multiple files.
|
||||
if [[ $# -gt 1 ]]; then
|
||||
showname=yup
|
||||
else
|
||||
showname=""
|
||||
fi
|
||||
|
||||
|
||||
# PAST IS PROLOGUE... NOW TO THE MEAT.
|
||||
for f; do
|
||||
x=$(convert "$f" $geometry $colors sixel:- 2>/dev/null)
|
||||
[[ ${#x} != 0 ]] || continue # The sixel command length better be >0
|
||||
|
||||
: debugeta ${#x}
|
||||
|
||||
case $0 in
|
||||
*sixgif)
|
||||
# If this program is named "sixgif" play files as animations,
|
||||
# instead of displaying each frame and scrolling down.
|
||||
echo -n $'\e[?80l' # Disable sixel scrolling
|
||||
for t in {1..3}; do
|
||||
echo -n "$x" # sixgif plays repeatedly
|
||||
done
|
||||
echo -n $'\e[?80h' # Reenable sixel scrolling
|
||||
;;
|
||||
|
||||
*)
|
||||
echo -n "$x" # sixcat just shows once
|
||||
[[ "$showname" ]] && echo "$f"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
# TIDY UP
|
||||
waitforterminal
|
||||
if [[ "$palettechanged" ]]; then
|
||||
# Reset color palette
|
||||
numcolors=$(resetnumcolors)
|
||||
: echo Number of colors reset to $numcolors >&2
|
||||
fi
|
Reference in New Issue
Block a user