Skip to content

Instantly share code, notes, and snippets.

@felipealfonsog
Created March 19, 2026 21:24
Show Gist options
  • Select an option

  • Save felipealfonsog/e04354a0fc5348504ee8a45b99cf321c to your computer and use it in GitHub Desktop.

Select an option

Save felipealfonsog/e04354a0fc5348504ee8a45b99cf321c to your computer and use it in GitHub Desktop.
IMG -> SVG CLI (Portable) - on macOS and Linux
#!/usr/bin/env bash
set -u
trap 'echo; echo "[EXIT] Interrupted."; exit 0' SIGINT
color() {
case "$1" in
red) printf '\033[0;31m%s\033[0m\n' "$2" ;;
green) printf '\033[0;32m%s\033[0m\n' "$2" ;;
yellow) printf '\033[1;33m%s\033[0m\n' "$2" ;;
cyan) printf '\033[0;36m%s\033[0m\n' "$2" ;;
bold) printf '\033[1m%s\033[0m\n' "$2" ;;
*) printf '%s\n' "$2" ;;
esac
}
line() {
echo "------------------------------------------------------------"
}
handle_exit() {
local input="$1"
local normalized
normalized=$(printf '%s' "$input" | tr '[:upper:]' '[:lower:]')
case "$normalized" in
q|quit|exit)
echo
color cyan "[EXIT] Bye."
exit 0
;;
esac
}
prompt() {
local message="$1"
local var_name="$2"
local value
read -r -p "$message" value
handle_exit "$value"
eval "$var_name=\"\$value\""
}
is_installed() {
command -v "$1" >/dev/null 2>&1
}
install_tool() {
local tool="$1"
if is_installed "$tool"; then
color green "[OK] $tool already installed."
return
fi
color yellow "[..] $tool not found."
if is_installed brew; then
color yellow "[..] Installing with brew..."
brew install "$tool"
elif is_installed apt; then
sudo apt update && sudo apt install -y "$tool"
elif is_installed pacman; then
sudo pacman -Sy --noconfirm "$tool"
else
color red "[ERROR] No supported package manager found."
exit 1
fi
}
show_header() {
clear 2>/dev/null || true
color cyan "============================================================"
color cyan " IMG -> SVG CLI (Portable) "
color cyan "============================================================"
echo
echo "Works on macOS and Linux"
echo
color yellow "Type q / quit / exit at any prompt"
echo
}
show_menu() {
line
color bold "Conversion modes"
echo " 1) Inkscape (experimental CLI)"
echo " 2) Color vector (vtracer)"
echo " 3) B/W vector (potrace)"
echo " 4) Wrap image (no vector)"
echo " 5) Exit"
line
echo
prompt "Choose [1-5]: " MODE
}
ask_input() {
prompt "Input file: " INPUT
[[ -f "$INPUT" ]] || { color red "File not found"; ask_input; }
}
ask_output() {
local default="${INPUT%.*}.svg"
prompt "Output [$default]: " OUTPUT
OUTPUT=${OUTPUT:-$default}
}
run_inkscape() {
install_tool inkscape
local actions="select-all;object-to-path;export-plain-svg;export-do"
echo
color cyan "[INKSCAPE CLI]"
echo "inkscape \"$INPUT\" --actions=\"$actions\" --export-filename=\"$OUTPUT\""
inkscape "$INPUT" --actions="$actions" --export-filename="$OUTPUT" || return 1
}
run_vtracer() {
install_tool vtracer
echo
color cyan "[VTRACER]"
vtracer --input "$INPUT" --output "$OUTPUT" --colormode color || return 1
}
run_potrace() {
install_tool potrace
install_tool imagemagick
TMP=$(mktemp /tmp/img2svg.XXXX.pbm)
echo
color cyan "[POTRACE]"
magick "$INPUT" -colorspace gray -threshold 55% "$TMP" || return 1
potrace "$TMP" -s -o "$OUTPUT" || return 1
rm -f "$TMP"
}
run_wrap() {
install_tool inkscape
inkscape "$INPUT" --export-type=svg --export-filename="$OUTPUT"
}
show_result() {
echo
line
color bold "Result"
ls -lh "$OUTPUT" 2>/dev/null || color red "No output"
line
}
post_menu() {
echo
echo "1) Open"
echo "2) Again"
echo "3) Exit"
prompt "> " NEXT
case "$NEXT" in
1) is_installed inkscape && inkscape "$OUTPUT" & ;;
2) main ;;
*) exit 0 ;;
esac
}
main() {
show_header
show_menu
case "$MODE" in
1|2|3|4) ;;
*) exit 0 ;;
esac
ask_input
ask_output
case "$MODE" in
1) run_inkscape ;;
2) run_vtracer ;;
3) run_potrace ;;
4) run_wrap ;;
esac
show_result
post_menu
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment