#!/usr/bin/env bash set -o pipefail # tmux requires unrecognized OSC sequences to be wrapped with DCS tmux; # ST, and for all ESCs in to be replaced with ESC ESC. It # only accepts ESC backslash for ST. We use TERM instead of TMUX because TERM # gets passed through ssh. function print_osc() { if [[ $TERM == screen* || $TERM == tmux* ]]; then printf "\033Ptmux;\033\033]" else printf "\033]" fi } # More of the tmux workaround described above. function print_st() { if [[ $TERM == screen* || $TERM == tmux* ]]; then printf "\a\033\\" else printf "\a" fi } function load_version() { if [ -z ${IMGCAT_BASE64_VERSION+x} ]; then IMGCAT_BASE64_VERSION=$(base64 --version 2>&1) export IMGCAT_BASE64_VERSION fi } function b64_encode() { load_version if [[ $IMGCAT_BASE64_VERSION =~ GNU ]]; then # Disable line wrap base64 -w0 else base64 fi } function b64_decode() { load_version if [[ $IMGCAT_BASE64_VERSION =~ fourmilab ]]; then BASE64ARG=-d elif [[ $IMGCAT_BASE64_VERSION =~ GNU ]]; then BASE64ARG=-di else BASE64ARG=-D fi base64 $BASE64ARG } # print_image filename inline base64contents print_filename width height preserve_aspect_ratio # filename: Filename to convey to client # inline: 0 or 1, if set to 1, the file will be displayed inline, otherwise, it will be downloaded # base64contents: Base64-encoded contents # print_filename: 0 or 1, if set to 1, print the filename after outputting the image # width: set output width of the image in character cells, pixels or percent # height: set output height of the image in character cells, pixels or percent # preserve_aspect_ratio: 0 or 1, if set to 1, fill the specified width and height as much as possible without stretching the image # file: Empty string or file type like "application/json" or ".js". function print_image() { print_osc printf "1337;File=inline=%s" "$2" printf ";size=%d" $(printf "%s" "$3" | b64_decode | wc -c) [ -n "$1" ] && printf ";name=%s" "$(printf "%s" "$1" | b64_encode)" [ -n "$5" ] && printf ";width=%s" "$5" [ -n "$6" ] && printf ";height=%s" "$6" [ -n "$7" ] && printf ";preserveAspectRatio=%s" "$7" [ -n "$8" ] && printf ";type=%s" "$8" printf ":%s" "$3" print_st printf '\n' [ "$4" == "1" ] && echo "$1" has_image_displayed=t } function error() { errcho "ERROR: $*" } function errcho() { echo "$@" >&2 } function show_help() { errcho errcho "Usage: imgcat [-p] [-n] [-W width] [-H height] [-r] [-s] [-u] [-t file-type] [-f] filename ..." errcho " cat filename | imgcat [-W width] [-H height] [-r] [-s]" errcho errcho "Display images inline in the iTerm2 using Inline Images Protocol" errcho errcho "Options:" errcho errcho " -h, --help Display help message" errcho " -p, --print Enable printing of filename or URL after each image" errcho " -n, --no-print Disable printing of filename or URL after each image" errcho " -u, --url Interpret following filename arguments as remote URLs" errcho " -f, --file Interpret following filename arguments as regular Files" errcho " -t, --type file-type Provides a type hint" errcho " -r, --preserve-aspect-ratio When scaling image preserve its original aspect ratio" errcho " -s, --stretch Stretch image to specified width and height (this option is opposite to -r)" errcho " -W, --width N Set image width to N character cells, pixels or percent (see below)" errcho " -H, --height N Set image height to N character cells, pixels or percent (see below)" errcho errcho " If you don't specify width or height an appropriate value will be chosen automatically." errcho " The width and height are given as word 'auto' or number N followed by a unit:" errcho " N character cells" errcho " Npx pixels" errcho " N% percent of the session's width or height" errcho " auto the image's inherent size will be used to determine an appropriate dimension" errcho errcho " If a type is provided, it is used as a hint to disambiguate." errcho " The file type can be a mime type like text/markdown, a language name like Java, or a file extension like .c" errcho " The file type can usually be inferred from the extension or its contents. -t is most useful when" errcho " a filename is not available, such as whe input comes from a pipe." errcho errcho "Examples:" errcho errcho " $ imgcat -W 250px -H 250px -s avatar.png" errcho " $ cat graph.png | imgcat -W 100%" errcho " $ imgcat -p -W 500px -u http://host.tld/path/to/image.jpg -W 80 -f image.png" errcho " $ cat url_list.txt | xargs imgcat -p -W 40 -u" errcho " $ imgcat -t application/json config.json" errcho } function check_dependency() { if ! (builtin command -V "$1" >/dev/null 2>&1); then error "missing dependency: can't find $1" exit 1 fi } # verify that value is in the image sizing unit format: N / Npx / N% / auto function validate_size_unit() { if [[ ! "$1" =~ ^(:?[0-9]+(:?px|%)?|auto)$ ]]; then error "Invalid image sizing unit - '$1'" show_help exit 1 fi } ## Main if [ -t 0 ]; then has_stdin=f else has_stdin=t fi # Show help if no arguments and no stdin. if [ $has_stdin = f ] && [ $# -eq 0 ]; then show_help exit fi check_dependency base64 check_dependency wc file_type="" # Look for command line flags. while [ $# -gt 0 ]; do case "$1" in -h | --h | --help) show_help exit ;; -p | --p | --print) print_filename=1 ;; -n | --n | --no-print) print_filename=0 ;; -W | --W | --width) validate_size_unit "$2" width="$2" shift ;; -H | --H | --height) validate_size_unit "$2" height="$2" shift ;; -r | --r | --preserve-aspect-ratio) preserve_aspect_ratio=1 ;; -s | --s | --stretch) preserve_aspect_ratio=0 ;; -f | --f | --file) has_stdin=f is_url=f ;; -u | --u | --url) check_dependency curl has_stdin=f is_url=t ;; -t | --t | --type) file_type="$2" shift ;; -*) error "Unknown option flag: $1" show_help exit 1 ;; *) if [ "$is_url" == "t" ]; then encoded_image=$(curl -fs "$1" | b64_encode) || { error "Could not retrieve image from URL $1, error_code: $?" exit 2 } elif [ -r "$1" ]; then encoded_image=$(cat "$1" | b64_encode) else error "imgcat: $1: No such file or directory" exit 2 fi has_stdin=f print_image "$1" 1 "$encoded_image" "$print_filename" "$width" "$height" "$preserve_aspect_ratio" "$file_type" ;; esac shift done # Read and print stdin if [ $has_stdin = t ]; then print_image "" 1 "$(cat | b64_encode)" 0 "$width" "$height" "$preserve_aspect_ratio" "$file_type" fi if [ "$has_image_displayed" != "t" ]; then error "No image provided. Check command line options." show_help exit 1 fi exit 0