Skip to content

Instantly share code, notes, and snippets.

@hackerb9
Created July 23, 2019 10:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hackerb9/fe209e749a01efeddbc9d0e638bac3e1 to your computer and use it in GitHub Desktop.
Save hackerb9/fe209e749a01efeddbc9d0e638bac3e1 to your computer and use it in GitHub Desktop.
#!/bin/bash
# XXX showanddelete hacked to show best view by default and to
# change the image every five seconds if no key pressed.
# Maximum number of seconds to wait for a response from the terminal
# after a an escape sequence query. Usually, terminals respond much
# faster than 0.1 seconds, but may need to be increased for slow links
# (e.g., RS232C, ssh).
TIMEOUT=0.1
# Default sixel geometry if terminal does not respond to queries.
DEFAULT_WIDTH=800; DEFAULT_HEIGHT=480
cleanup() {
# If the user hits ^C, we don't want them stuck in SIXEL mode
echo -n $'\e[?80h' # Reenable sixel scrolling
echo -n $'\e\\' # Escape sequence to stop SIXEL
tput el
exit 0
}
trap cleanup SIGINT SIGHUP SIGABRT
getwindowsize() {
# Send control sequences to find how large of a sixel image can be shown.
# Prints geometry as width then height.
local -i x y # for reading width and height integers
local d # dummy variable
# Before querying the terminal, wait for it to be ready.
waitforterminal
# Send control sequence to query the sixel graphics geometry.
IFS=";" read -s -t ${TIMEOUT} -d "S" -p $'\e[?2;1;0S' d d x y d >&2
if [[ $? -ne 0 ]]; then
# Fall back to dtterm WindowOps to approximate sixel geometry.
IFS=";" read -s -t ${TIMEOUT} -d "t" -p $'\e[14t' d x y d >&2
fi
# Return the results (or the default if querying didn't work)
[[ x -gt 0 ]] || x=${DEFAULT_WIDTH}
[[ y -gt 0 ]] || y=${DEFAULT_HEIGHT}
echo $x $y
return
}
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.
# This is important if sixcat is run multiple times in a row,
# or if we want to run resetnumcolors at the end of the program.
# WARNING. While this should work with any terminal, but if it fails
# it'll end up waiting for approximately *forever* (i.e., 60 seconds).
read -s -t ${1:-60} -d "c" -p $'\e[c'
}
flushstdin() {
# flush stdin in case a key was hit twice by accident
while read -s -n1 -t .001; do :; done
}
e() {
# Clear current line and print text on it without a formfeed
echo -en "\r"
tput el
echo -en "$*"
}
E() {
# Clear current line and print text on it with a formfeed
echo -en "\r"
tput el
echo -e "$*"
}
rename() {
# Maybe rename an image file.
local file="$1"
local ext=${f##*.}
local base=$(basename "$file" ".$ext")
e "New name for $base? "
read newname
if [ "$newname" ]; then
newname="$(dirname "$file")/$newname"
newname="${newname#./}" # Remove dotslash from "./foo.jpg"
if [[ "$newname" != *$ext ]]; then
newname="$newname.$ext"
fi
e "Rename $file to $newname (y/N)? "
read -s -n 1
case $REPLY in
y|Y)
mv -i "$file" "$newname" &&
E "Renamed $file to $newname" &&
# If rename successful, write to outerscope variable "f"!!!
f="$newname"
;;
*)
E "Rename cancelled."
;;
esac
else
E "Rename cancelled."
fi
}
editcomment() {
# Retrieve the current image comment/caption and let the user edit it.
local file="$1"
comment=$(rdjpgcom "$1")
read -e -i "$comment" -p "New comment? " newcomment
if [ "$newcomment" == "$comment" ]; then
E "Comment editing cancelled."
return
fi
mv "$file" "$file.old"
wrjpgcom -replace -comment "$newcomment" "$file.old" > "$file"
gio trash "$file.old"
}
doit () {
# For every file, show it and ask what is to be done.
for f; do
waitforterminal # Wait for the terminal to be ready.
if [[ -d "$f" ]]; then
echo "recursing on $f";
doit "$f"/*
continue
fi
[[ -f "$f" ]] || continue;
# If the current file isn't an image, just skip it.
if ! identify "$f" 2>/dev/null 1>&2; then
continue
fi
# Show a quick preview
E "$f"
e "preparing best fit view\r"
convert -rotate '-90>' -rotate '+90' -gravity center \
-geometry ">${WIDTH}x>${HEIGHT}" "$f" sixel:-
# Read a key loop
while true; do
e "Press space to keep, 'd' to delete, 'v' to view, 'h' for help, 'q' to quit.\r";
flushstdin
if read -s -n1 -t 5 </dev/tty; then
tput el
case $REPLY in
s|" ") continue 2 # Nothing to do, just skip the image.
;;
d|t) gio trash "$f" && echo "trashed $f"
sleep 0.25; flushstdin # Slow down deletes
continue 2
;;
D) rm "$f" && echo "deleted $f"
sleep 0.25; flushstdin # Slow down deletes
continue 2
;;
v) e "preparing high quality view\r" # About 1 second
convert -geometry ">${WIDTH}x>${HEIGHT}" "$f" sixel:-
;;
b) # Rotate to fit screen. Double rotate for square images.
e "preparing best fit view\r"
convert -rotate '-90>' -rotate '+90' -gravity center \
-geometry ">${WIDTH}x>${HEIGHT}" "$f" sixel:-
;;
c|i) identify "$f"
rdjpgcom "$f" 2>/dev/null
;;
r) rename "$f"
;;
C) editcomment "$f"
;;
w) e "preparing wide view\r"
convert -geometry ">${WIDTH}x" \
-crop ${WIDTH}x${HEIGHT} \
"$f" sixel:-
;;
e) e "preparing enhanced view\r"
convert -geometry ">${WIDTH}x>${HEIGHT}" "$f" \
-channel rgb -auto-level -gamma 1.5 sixel:-
;;
p) e "Paused. Hit any key.\r"
read -n1
;;
h|'?') E "$(basename $0): Rapidly browse and delete image files"
cat <<- "EOF"
For each image in a directory, a low quality preview will be shown.
You can then hit one of these keys:
space (or s): skip to next image.
d: trash image (also try 'gio list trash:' and 'gio trash --empty')
D: delete image immediately (no confirmation!)
v: view image in higher quality (can take a second).
b: best fit view (same as v, but image rotated to landscape).
w: wide view, show image full width
e: enhanced view (auto-level + gamma 1.5)
c: display comments and image size.
r: rename image.
C: edit image comment.
h: help (looks like you found it).
q: quit
EOF
;;
q) exit;;
esac;
else
continue 2
fi;
done
done
e
}
### MAIN
# # Set global variables to hold the window size.
declare -i -g WIDTH HEIGHT
read WIDTH HEIGHT < <(getwindowsize)
HEIGHT=HEIGHT-32 # Trim some space for a line of text.
if [[ $# -gt 0 ]]; then
doit "$@"
else
doit *
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment