* Use (( )) for the numeric argument test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Drop the quotes on a variable inside [[ ]] Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Use omarchy-pkg-drop instead of raw pacman -Rns omarchy-pkg-drop already filters to installed packages, so the 2>/dev/null || true suppression is no longer needed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Drop defensive checks around default-set commands ttfx, imagemagick, and networkmanager are all in the default package set, so their commands are runtime invariants and should be invoked directly. Removing the nmcli guard also removes the degraded wifi fallthrough that only ran when nmcli was missing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
239 lines
5.6 KiB
Bash
Executable File
239 lines
5.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# omarchy:summary=Transcode an image into ASCII/Unicode art text
|
|
# omarchy:group=transcode
|
|
# omarchy:name=ascii
|
|
# omarchy:args=<input-image.svg|png> <output-path> [--width <columns>] [--height <rows>] [--mode <braille|block>] [--threshold <percent>] [--invert]
|
|
# omarchy:examples=omarchy transcode ascii ~/logo.svg /tmp/logo.txt | omarchy transcode ascii ~/logo.png ~/.config/omarchy/branding/screensaver.txt --width 80
|
|
|
|
set -o pipefail
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: omarchy-transcode-ascii <input-image.svg|png> <output-path> [options]
|
|
|
|
Transcodes an image into ASCII/Unicode art text.
|
|
|
|
Options:
|
|
-w, --width <columns> Maximum output width in terminal columns (default: 80)
|
|
-H, --height <rows> Maximum output height in terminal rows (default: 26)
|
|
-m, --mode <braille|block> Output style (default: braille)
|
|
-t, --threshold <percent> Pixel threshold from 0-100 (default: 50)
|
|
--invert Treat light pixels as the logo instead of dark pixels
|
|
--no-trim Preserve surrounding whitespace/background
|
|
--help Show this help
|
|
EOF
|
|
}
|
|
|
|
width=80
|
|
height=26
|
|
mode=braille
|
|
threshold=50
|
|
invert=false
|
|
trim=true
|
|
image_path=""
|
|
output_path=""
|
|
|
|
while (($# > 0)); do
|
|
case "$1" in
|
|
--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
-w | --width)
|
|
shift
|
|
[[ -n $1 ]] || { echo "Missing value for --width" >&2; exit 1; }
|
|
width="$1"
|
|
;;
|
|
-H | --height)
|
|
shift
|
|
[[ -n $1 ]] || { echo "Missing value for --height" >&2; exit 1; }
|
|
height="$1"
|
|
;;
|
|
-m | --mode)
|
|
shift
|
|
[[ -n $1 ]] || { echo "Missing value for --mode" >&2; exit 1; }
|
|
mode="$1"
|
|
;;
|
|
-t | --threshold)
|
|
shift
|
|
[[ -n $1 ]] || { echo "Missing value for --threshold" >&2; exit 1; }
|
|
threshold="$1"
|
|
;;
|
|
--invert)
|
|
invert=true
|
|
;;
|
|
--no-trim)
|
|
trim=false
|
|
;;
|
|
-*)
|
|
echo "Unknown option: $1" >&2
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
*)
|
|
if [[ -z $image_path ]]; then
|
|
image_path="$1"
|
|
elif [[ -z $output_path ]]; then
|
|
output_path="$1"
|
|
else
|
|
echo "Unexpected argument: $1" >&2
|
|
usage >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [[ -z $image_path || -z $output_path ]]; then
|
|
usage >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ $mode != "braille" && $mode != "block" ]]; then
|
|
echo "Invalid mode: $mode (expected braille or block)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f $image_path ]]; then
|
|
echo "Logo file not found: $image_path" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ $mode == "braille" ]]; then
|
|
pixel_width=$((width * 2))
|
|
pixel_height=$((height * 4))
|
|
else
|
|
pixel_width=$width
|
|
pixel_height=$((height * 2))
|
|
fi
|
|
|
|
alpha_range=$(magick -background none "$image_path" -alpha extract -format '%[fx:minima] %[fx:maxima]' info: 2>/dev/null) || {
|
|
echo "Unable to read logo image: $image_path" >&2
|
|
exit 1
|
|
}
|
|
read -r alpha_min alpha_max <<<"$alpha_range"
|
|
|
|
use_alpha=false
|
|
if awk -v min="$alpha_min" -v max="$alpha_max" 'BEGIN { exit !(min < 0.999 && max > min) }'; then
|
|
use_alpha=true
|
|
fi
|
|
|
|
magick_args=(-background none "$image_path" -auto-orient)
|
|
|
|
if [[ $use_alpha == "true" ]]; then
|
|
magick_args+=(-alpha extract -alpha off)
|
|
if [[ $invert == "true" ]]; then
|
|
magick_args+=(-negate)
|
|
fi
|
|
else
|
|
magick_args+=(-alpha remove -alpha off -colorspace Gray)
|
|
if [[ $invert == "false" ]]; then
|
|
magick_args+=(-negate)
|
|
fi
|
|
fi
|
|
|
|
if [[ $trim == "true" ]]; then
|
|
magick_args+=(-bordercolor black -border 1 -trim +repage)
|
|
fi
|
|
|
|
magick_args+=(-resize "${pixel_width}x${pixel_height}" -threshold "${threshold}%" -negate -compress none pbm:-)
|
|
|
|
tmp_output=$(mktemp)
|
|
trap 'rm -f "$tmp_output"' EXIT
|
|
|
|
if ! magick "${magick_args[@]}" | awk -v mode="$mode" '
|
|
BEGIN {
|
|
braille_base = 10240
|
|
dot[0,0] = 1
|
|
dot[0,1] = 2
|
|
dot[0,2] = 4
|
|
dot[1,0] = 8
|
|
dot[1,1] = 16
|
|
dot[1,2] = 32
|
|
dot[0,3] = 64
|
|
dot[1,3] = 128
|
|
|
|
block["11"] = "█"
|
|
block["10"] = "▀"
|
|
block["01"] = "▄"
|
|
block["00"] = " "
|
|
}
|
|
{
|
|
sub(/#.*/, "")
|
|
for (i = 1; i <= NF; i++) {
|
|
token[++token_count] = $i
|
|
}
|
|
}
|
|
END {
|
|
if (token[1] != "P1") {
|
|
exit 1
|
|
}
|
|
|
|
width = token[2]
|
|
height = token[3]
|
|
pixel_offset = 4
|
|
row_step = (mode == "braille") ? 4 : 2
|
|
|
|
for (y = 0; y < height; y += row_step) {
|
|
line = ""
|
|
if (mode == "braille") {
|
|
for (x = 0; x < width; x += 2) {
|
|
code = 0
|
|
for (dy = 0; dy < 4; dy++) {
|
|
for (dx = 0; dx < 2; dx++) {
|
|
if (y + dy < height && x + dx < width) {
|
|
pixel = token[pixel_offset + ((y + dy) * width) + x + dx]
|
|
if (pixel == 1) {
|
|
code += dot[dx,dy]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (code == 0) {
|
|
line = line " "
|
|
} else {
|
|
line = line sprintf("%c", braille_base + code)
|
|
}
|
|
}
|
|
} else {
|
|
for (x = 0; x < width; x++) {
|
|
top = token[pixel_offset + (y * width) + x]
|
|
bottom = (y + 1 < height) ? token[pixel_offset + ((y + 1) * width) + x] : 0
|
|
line = line block[top bottom]
|
|
}
|
|
}
|
|
sub(/[ ]+$/, "", line)
|
|
lines[++line_count] = line
|
|
}
|
|
|
|
first = 1
|
|
while (first <= line_count && lines[first] ~ /^[ ]*$/) {
|
|
first++
|
|
}
|
|
|
|
last = line_count
|
|
while (last >= first && lines[last] ~ /^[ ]*$/) {
|
|
last--
|
|
}
|
|
|
|
for (i = first; i <= last; i++) {
|
|
print lines[i]
|
|
}
|
|
}
|
|
' >"$tmp_output"; then
|
|
echo "Unable to convert logo image: $image_path" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -s $tmp_output ]]; then
|
|
echo "No logo pixels found in: $image_path" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$output_path")"
|
|
cp "$tmp_output" "$output_path"
|
|
echo "Wrote ASCII art to $output_path"
|