Skip to content

Instantly share code, notes, and snippets.

@ernstki
Last active August 31, 2024 11:58
Show Gist options
  • Save ernstki/74aba058622a9cea43bebc4028aba5cd to your computer and use it in GitHub Desktop.
Save ernstki/74aba058622a9cea43bebc4028aba5cd to your computer and use it in GitHub Desktop.
Use ImageMagick to trim extra pixels from an image and replace with a uniform border (default 10 pixels); good for screenshots
#!/usr/bin/env bash
##
## Trim extra pixels from around an image, e.g., a screenshot, and replace
## with a border of uniform width, of a color sampled from the four image
## corners, using ImageMagick 6.x (or above?)
##
## Author: Kevin Ernst <ernstki -at- mail.uc.edu>
## Date: 29 August 2024
## License: WTFPL or ISC at your option
## Homepage: https://gist.github.com/ernstki/74aba058622a9cea43bebc4028aba5cd
## Usage: See the output of `reborder --help` or HELP below
##
## References:
## 1. https://imagemagick.org/Usage/crop/#border
## 2. https://stackoverflow.com/a/48685590/785213
##
if (( DEBUG )); then
set -eExo pipefail
trap 'echo "Trapped at line #$LINENO${FUNCNAME:+ in $FUNCNAME}."' ERR
fi
set -u
ME=${BASH_SOURCE[0]##*/}
HELP="
$ME - trim extra pixels from an image, then add a border of the same color
usage:
$ $ME [-h|--help]
$ $ME [-f|--force] [-n|--dry-run] [BORDERSIZE] IMAGE [IMAGE…]
where:
IMAGE is any image ImageMagick can handle
BORDERSIZE is a valid ImageMagick '-bordersize' (default: 10x10)
-f, --force forces overwriting of existing rebordered image(s)
-n, --dry-run simulates what would happen; does not modify any images
-q, --quiet suppresses \"Wrote 'newimage.ext'.\" messages
homepage:
https://gist.github.com/ernstki/74aba058622a9cea43bebc4028aba5cd
"
plurality() {
# read hex triplet color values and print the one that appears most often
# or return an error if there's no plurality
awk '
{ colorcounts[$1]++ }
END {
for (c in colorcounts) {
if (colorcounts[c] > max) {
it = c
max = colorcounts[c]
}
}
if (max <= NR/2) exit 1
else print it
}'
}
images=()
borderwidth=10
force=
# could make an option for this later
fuzz='1%'
suffix='+rebordered'
dryrun=${DRYRUN:-}
quiet=
endofopts=
while (( $# )); do
if (( endofopts )); then images+=("$1"); shift; continue; fi
case $1 in
--)
endofopts=1
;;
-h|--help)
echo "$HELP"
exit
;;
1|1x1|[0-9]*[0-9]|[0-9]*[0-9]x[0-9]*[0-9])
borderwidth=$1
;;
-f|--force|--force-overwrite)
force=1
;;
-n|--dryrun|--dry-run)
dryrun=1
;;
-q|--quiet|--silent)
quiet=1
;;
*)
images+=("$1")
;;
esac
shift
done
if [[ -z ${images[*]} ]]; then
echo "No images specified to operate on. Try '--help'." >&2;
exit 1
fi
tl='%[hex:u.p{0,0}]'
tr='%[hex:u.p{w-1,0}]'
bl='%[hex:u.p{0,h-1}]'
br='%[hex:u.p{w-1,h-1}]'
processed=0
for i in "${images[@]}"; do
if [[ ! -r $i ]]; then
echo "Unreadable or non-existent file '$i'. Skipping." >&2;
continue
fi
newi="${i%%.*}$suffix.${i##*.}"
cornerpixels=$(convert "$i" -format "$tl\n$tr\n$bl\n$br\n" info:)
if (( $? )); then
echo "Problem running ImageMagick 'convert'; try DEBUG=1" >&2
exit 1
fi
if color=$(echo "$cornerpixels" | plurality); then
if [[ -s $newi ]] && (( !force && ! dryrun)); then
read -rp "Image '$newi' already exists. Overwrite it? [y/N] "
if [[ -z $REPLY || $REPLY =~ ^[nN] ]]; then
if (( !quiet )); then
echo "Not overwriting existing '$newi'." >&2
fi
continue
fi
fi
${dryrun:+echo [DRY RUN] }convert "$i" -trim -fuzz "$fuzz" +repage \
"$newi"
${dryrun:+echo [DRY RUN] }mogrify -bordercolor "#$color" -border \
"$borderwidth" "$newi"
if (( !dryrun && !quiet )); then echo "Wrote '$newi'." >&2; fi
processed=$(( processed + 1 ))
else
echo "Corner pixels of '$i' are too different, can't add a border." \
"Skipping." >&2
fi
done
if (( !processed )); then
echo "No images were processed." >&2;
exit 1
fi
@ernstki
Copy link
Author

ernstki commented Aug 29, 2024

Installation

Make sure ~/bin is in your search path. These days, it usually is. Then:

GIST=https://gist.github.com/ernstki/74aba058622a9cea43bebc4028aba5cd
SCRIPT=$GIST/raw/reborder
(curl -sL $SCRIPT || wget -qO- $SCRIPT) > ~/bin/reborder
chmod a+x ~/bin/reborder

# test it
which reborder
reborder --help

Example

Running reborder with default settings turns this:

A screenshot showing the output of a command-line program in a terminal, with an irregular amount of negative space around the outer margins

into this:

The result of running 'reborder' on the above image, with a uniform 10-pixel border around the image, matching the background detected from the source image by inspecting color values at the four corners

License

WTFPL or ISC, at your option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment