dotfiles/bin/screenshot_wayland.sh
Akemi Izuko f6881cea7a
Init again
The dotfiles are back
2022-09-06 23:34:19 -06:00

242 lines
6.5 KiB
Bash
Executable file

#!/usr/bin/env bash
# Take and resize screenshots on wayland
#
# Input sources: Full, selection, dimensions, latest taken screenshot
# Filters: Resize, drop-shadow
# Output sources: File, clipboard
#
# Screenshot default: .png
# Resize default: .avif
#
# Each screenshot has 1 or more input sources and 1 or more output sources. The
# image extention is determined by the output file, --extension option, or
# defaults. Regardless of extension, every screenshot is first saved as a
# lossless PNG then converted to other formats. All intermediate files are
# saved in a temporary directory set by the --tmp-dir option
#
# Setting the --tmp-dir alongside the --resize option will modify the latest
# image in that directory
print_help() {
cat <<HELP
Take and resize screenshots on wayland
USAGE: $(basename "$1") [FLAGS] <ARG> [FILE]
FLAGS:
-c, --clipboard Save the screenshot to your clipboard
-h, --help Print this help message and exit
OPTIONS:
-d, --drop-shadow <size> Save the screenshot with a drop-shadow on a white background
-e, --extension <ext> Change image extention saved
-r, --resize <size> Resize the latest screenshot instead of taking a new one
-s, --size <dimensions> Screenshot exact dimensions
-t, --tmp-dir <dir> Set the temporary save and resize source directory
ARGS:
area Takes a screenshot of an area selected by the mouse. Like cmd+shift+4
full Screenshots the full screen
markup Edit latest image in swappy. Incompatible with most options
EXAMPLES:
$(basename "$1") full ~/Pictures/elaina_bubble_tea.png
$(basename "$1") -c area ~/Pictures/elaina_bubble_tea.png
$(basename "$1") -c -d 10 -s '20,400 200x180' ~/Pictures/elaina_bubble_tea.png
$(basename "$1") --resize 80% ~/Pictures/elaina_bubble_tea.webp
Saves full original copy under /tmp/screenshots_tmp/. The latest resize is
available at [FILE] or in the clipboard.
Make sure to specify --clipboard or a file path. There is no default!
HELP
}
declare CROP SHADOW IS_CLIPBOARD IS_SWAPPY OUTPUT_PATH RESIZE EXT TMP_DIR TMP_PATH
declare -r SLURP_REGEX="^[0-9]+,[0-9]+[[:space:]][0-9]+x[0-9]+$"
# Not possible to call script without 2 args
parse_args() {
if [[ $# -eq 0 ]]; then
print_help "$0"
return 1
fi
while [[ $# -gt 0 ]]; do
case "$1" in
-c | --clipboard)
IS_CLIPBOARD=true
shift
;;
-d | --drop-shadow)
shift
if [[ "$1" =~ ^[0-9]+x[0-9]+$ ]]; then
SHADOW="$1"
elif [[ "$1" =~ ^[0-9]+$ ]]; then
SHADOW="${1}x${1}"
else
printf 'No size argument found for --drop-shadow option\n'
return 2
fi
shift
;;
-e | --extension)
shift
if [[ "$1" =~ ^\.[a-z0-9]+$ ]]; then
EXT="${1:1}"
elif [[ "$1" =~ ^[a-z0-9]+$ ]]; then
EXT="$1"
fi
shift
;;
-r | --resize)
shift
if [[ "$1" =~ [0-9]+%$ ]]; then
RESIZE="$1"
elif [[ "$1" =~ [0-9]+$ ]]; then
RESIZE="$1%"
else
printf 'Resize amount not specified. Ex: 100%% or 20\n'
return 2
fi
shift
;;
-s | --size)
shift
if [[ "$1" =~ $SLURP_REGEX ]]; then
CROP="$1"
else
printf 'No dimension argument found for --tmp-dir option\n'
return 2
fi
shift
;;
-t | --tmp-dir)
shift
if [[ -z "$1" ]]; then
printf 'No directory argument found for --tmp-dir option\n'
return 2
fi
TMP_DIR="$1"
shift
;;
-h | --help)
print_help "$0"
return 1
;;
area)
CROP="area"
shift
;;
full)
CROP="fullscreen"
shift
;;
markup)
IS_SWAPPY=true
shift
;;
*)
if [[ -z "$OUTPUT_PATH" ]]; then
OUTPUT_PATH="$1"
else
printf 'Multiple output paths specified when only one was expected\n'
return 2
fi
shift
;;
esac
done
# Assert valid number of inputs and outputs
if [[ -z "$CROP" && -z "$RESIZE" && -z "$IS_SWAPPY" ]]; then
printf 'No inputs specified!\n'
print_help "$0"
return 1
fi
}
# Set defaults
set_global_defaults() {
if [[ -z "$EXT" && -n "$OUTPUT_PATH" ]]; then
EXT="${OUTPUT_PATH##*.}"
elif [[ -z "$EXT" && -n "$RESIZE" ]]; then
EXT='avif'
elif [[ -z "$EXT" ]]; then
EXT='png'
fi
if [[ -z "$TMP_DIR" ]]; then
TMP_DIR="$HOME/Desktop/screenshots_tmp"
fi
mkdir -p "$TMP_DIR"
TMP_PATH="${TMP_DIR}/$(date +%s).png"
if ! [[ -w "$TMP_DIR" ]]; then
printf 'Temporary path %s is not writable. Check permissions\n' "$TMP_PATH"
return 2
fi
}
# Save screenshot into tmp
get_screenshot() {
if [[ "$CROP" == "area" ]]; then
grim -g "$(slurp)" "$TMP_PATH"
elif [[ "$CROP" == "fullscreen" ]]; then
grim "$TMP_PATH"
elif [[ "$CROP" =~ $SLURP_REGEX ]]; then
grim -g "$CROP" "$TMP_PATH"
fi
}
apply_drop_shadow() {
magick convert "$TMP_PATH" \
\( +clone -background black -shadow "${SHADOW}+0+0" \) \
+swap -background white -layers merge +repage \
"$TMP_PATH"
}
# Resize latest screenshot
resize_latest_screenshot() {
if [[ -n "$IS_SWAPPY" ]] || [[ -n "$RESIZE" && "$RESIZE" == '100%' && "$EXT" == 'png' ]]; then
TMP_PATH="$(fd -e 'png' -E '*_*' . "$TMP_DIR" | sort | tail -1)"
elif [[ -n "$RESIZE" ]]; then
local latest_screenshot="$(fd -e 'png' -E '*_*' . "$TMP_DIR" | sort | tail -1)"
TMP_PATH="${latest_screenshot%.*}_${RESIZE}.${EXT}"
if [[ -z "$latest_screenshot" ]]; then
printf 'No screenshots found to resize\n'
return 1
fi
magick convert "$latest_screenshot" -resize "$RESIZE" "${EXT^^}:$TMP_PATH"
elif [[ "$EXT" != png ]]; then
local source_path="$TMP_PATH"
TMP_PATH="${source_path%.*}.${EXT}"
magick convert "$source_path" "${EXT^^}:$TMP_PATH"
fi
}
# Copy screenshot to destination
copy_to_destination() {
if [[ "$IS_CLIPBOARD" == true ]]; then
wl-copy < "$TMP_PATH"
elif [[ "$IS_SWAPPY" == true ]]; then
swappy -f "$TMP_PATH" -o "${TMP_PATH%.*}_swappy.png"
fi
if [[ -n "$OUTPUT_PATH" ]]; then
cp "$TMP_PATH" "$OUTPUT_PATH"
fi
}
if ! parse_args "$@"; then
exit $?
fi
set_global_defaults || exit $?
get_screenshot
[[ -z "$SHADOW" ]] || apply_drop_shadow
resize_latest_screenshot || exit $?
copy_to_destination || exit $?
# wl-copy https://www.reddit.com/r/swaywm/comments/bb4dam/take_screenshot_to_clipboard/