#!/bin/bash # omarchy:summary=Transcode an image into ASCII/Unicode art text # omarchy:group=transcode # omarchy:name=ascii # omarchy:args= [--width ] [--height ] [--mode ] [--threshold ] [--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 [options] Transcodes an image into ASCII/Unicode art text. Options: -w, --width Maximum output width in terminal columns (default: 80) -H, --height Maximum output height in terminal rows (default: 26) -m, --mode Output style (default: braille) -t, --threshold 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 if [[ -z $1 ]]; then echo "Missing value for --width" >&2 exit 1 fi width="$1" ;; --width=*) width="${1#*=}" ;; -H | --height) shift if [[ -z $1 ]]; then echo "Missing value for --height" >&2 exit 1 fi height="$1" ;; --height=*) height="${1#*=}" ;; -m | --mode) shift if [[ -z $1 ]]; then echo "Missing value for --mode" >&2 exit 1 fi mode="$1" ;; --mode=*) mode="${1#*=}" ;; --block | --blocks) mode=block ;; --braille) mode=braille ;; -t | --threshold) shift if [[ -z $1 ]]; then echo "Missing value for --threshold" >&2 exit 1 fi threshold="$1" ;; --threshold=*) threshold="${1#*=}" ;; --invert) invert=true ;; --no-trim) trim=false ;; --) shift break ;; -*) 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 (($# > 0)); then while (($# > 0)); do 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 shift done fi if [[ -z $image_path || -z $output_path ]]; then usage >&2 exit 1 fi if ! [[ $width =~ ^[0-9]+$ ]] || (( width < 1 )); then echo "Invalid width: $width" >&2 exit 1 fi if ! [[ $height =~ ^[0-9]+$ ]] || (( height < 1 )); then echo "Invalid height: $height" >&2 exit 1 fi if [[ $mode != "braille" && $mode != "block" ]]; then echo "Invalid mode: $mode (expected braille or block)" >&2 exit 1 fi if ! [[ $threshold =~ ^[0-9]+$ ]] || (( threshold < 0 || threshold > 100 )); then echo "Invalid threshold: $threshold (expected 0-100)" >&2 exit 1 fi if [[ ! -f $image_path ]]; then echo "Logo file not found: $image_path" >&2 exit 1 fi if omarchy-cmd-missing magick; then echo "ImageMagick is required to convert logo images" >&2 exit 1 fi case "$mode" in braille) pixel_width=$((width * 2)) pixel_height=$((height * 4)) ;; block) pixel_width=$width pixel_height=$((height * 2)) ;; esac alpha_min=$(magick -background none "$image_path" -alpha extract -format '%[fx:minima]' info: 2>/dev/null) || { echo "Unable to read logo image: $image_path" >&2 exit 1 } alpha_max=$(magick -background none "$image_path" -alpha extract -format '%[fx:maxima]' info: 2>/dev/null) || { echo "Unable to read logo image: $image_path" >&2 exit 1 } 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 [[ $mode == "braille" ]]; then if ! magick "${magick_args[@]}" | awk ' 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 } { 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 for (y = 0; y < height; y += 4) { line = "" 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) } } 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 else if ! magick "${magick_args[@]}" | awk ' BEGIN { 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 for (y = 0; y < height; y += 2) { line = "" 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 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"