#!/bin/sh
# paint-pink-left-center.sh
# Overwrites each input image by painting a 10×10 square centered vertically
# on the left edge (x=0) in hot pink.
#
# Accepts any number of FILE or GLOB arguments (quoted or unquoted).
# Dependency: ImageMagick (mogrify, or magick, or convert) + identify (or magick identify).
set -u
if [ $# -lt 1 ]; then
echo "usage: ${0##*/} FILE|GLOB [FILE|GLOB ...]" >&2
exit 64
fi
log() { printf '%s\n' "$*" >&2; }
SQUARE=10
# Select an ImageMagick frontend for writing.
MODE=
if command -v mogrify >/dev/null 2>&1; then
MODE=mogrify
log "info: using ImageMagick frontend: mogrify"
elif command -v magick >/dev/null 2>&1; then
MODE=magick
log "info: using ImageMagick frontend: magick (mogrify subcommand)"
elif command -v convert >/dev/null 2>&1; then
MODE=convert
log "info: using ImageMagick frontend: convert (temp-file in-place emulation)"
else
log "error: ImageMagick not found (expected: mogrify, magick, or convert)."
exit 69
fi
# Select an ImageMagick frontend for reading dimensions.
IDENT=
if command -v identify >/dev/null 2>&1; then
IDENT="identify"
elif command -v magick >/dev/null 2>&1; then
IDENT="magick identify"
else
log "error: ImageMagick identify not found (expected: identify or magick identify)."
exit 69
fi
log "info: using dimension probe: $IDENT"
get_dims() {
# Prints: "<width> <height>"
# Returns non-zero on failure.
f=$1
$IDENT -format '%w %h' -- "$f" 2>/dev/null
}
compute_rect() {
# Prints: "<x0> <y0> <x1> <y1>" (inclusive pixel coordinates)
# Centers a SQUARE×SQUARE region vertically at the left edge.
w=$1
h=$2
# Left edge anchoring.
x0=0
x1=$((SQUARE - 1))
maxx=$((w - 1))
if [ "$maxx" -lt 0 ]; then
maxx=0
fi
if [ "$x1" -gt "$maxx" ]; then
x1=$maxx
fi
# Vertical centering.
y0=$(((h - SQUARE) / 2))
if [ "$y0" -lt 0 ]; then
y0=0
fi
y1=$((y0 + SQUARE - 1))
maxy=$((h - 1))
if [ "$maxy" -lt 0 ]; then
maxy=0
fi
if [ "$y1" -gt "$maxy" ]; then
y1=$maxy
fi
if [ "$y0" -gt "$y1" ]; then
y0=0
fi
printf '%s %s %s %s\n' "$x0" "$y0" "$x1" "$y1"
}
draw_corner() {
# $1: path
f=$1
dims=$(get_dims "$f") || return 1
w=${dims%% *}
h=${dims##* }
rect=$(compute_rect "$w" "$h")
x0=${rect%% *}; rest=${rect#* }
y0=${rest%% *}; rest=${rest#* }
x1=${rest%% *}; y1=${rest##* }
log "info: image dimensions: ${w}×${h}"
log "info: painting rectangle (inclusive pixels): x=${x0}..${x1}, y=${y0}..${y1}"
draw="rectangle ${x0},${y0} ${x1},${y1}"
case "$MODE" in
mogrify)
mogrify -fill hotpink -stroke none -draw "$draw" -- "$f"
;;
magick)
magick mogrify -fill hotpink -stroke none -draw "$draw" -- "$f"
;;
convert)
# Emulate in-place edit using a temporary file, then atomic replace.
case "$f" in
*.*)
ext=${f##*.}
base=${f%.*}
tmp=$(mktemp "${base}.pinkpatch.XXXXXX.${ext}") || return 1
;;
*)
tmp=$(mktemp "${f}.pinkpatch.XXXXXX") || return 1
;;
esac
if convert -- "$f" -fill hotpink -stroke none -draw "$draw" "$tmp"; then
mv -f -- "$tmp" "$f"
else
rm -f -- "$tmp"
return 1
fi
;;
esac
}
# Preserve spaces in quoted arguments during the "$arg" → glob expansion stage.
oldIFS=$IFS
IFS='
'
trap 'IFS=$oldIFS' EXIT HUP INT TERM
rc=0
matched_any=0
for arg in "$@"; do
log "info: expanding argument: $arg"
expanded=0
for f in $arg; do
expanded=1
matched_any=1
if [ ! -f "$f" ]; then
log "warn: skipping (not a regular file): $f"
rc=1
continue
fi
log "info: processing file: $f"
if draw_corner "$f"; then
log "info: done: $f"
else
log "error: failed: $f"
rc=1
fi
done
if [ "$expanded" -eq 0 ]; then
log "warn: no items produced by expansion for: $arg"
rc=1
fi
done
if [ "$matched_any" -eq 0 ]; then
log "error: no files matched any argument."
exit 66
fi
exit "$rc"