1#!/usr/local/bin/bash
2#
3# Siddharth Dushantha 2020
4#
5# Dependencies: sxiv, imagemagick, xdotool, fzf
6
7VERSION=1.0.6
8
9# Default values
10SEARCH_PROMPT="❯ "
11SIZE=532x365
12POSITION="+0+0"
13FONT_SIZE=38
14BG_COLOR="#ffffff"
15FG_COLOR="#000000"
16PREVIEW_TEXT="ABCDEFGHIJKLM\nNOPQRSTUVWXYZ\nabcdefghijklm\nnopqrstuvwxyz\n1234567890\n!@$\%(){}[]"
17
18show_help() {
19printf "%s" "\
20usage: fontpreview [-h] [--size \"px\"] [--position \"+x+y\"] [--search-prompt SEARCH_PROMPT]
21                   [--font-size \"FONT_SIZE\"] [--bg-color \"BG_COLOR\"] [--fg-color \"FG_COLOR\"]
22                   [--preview-text \"PREVIEW_TEXT\"] [-i font.otf] [-o preview.png] [--version]
23
24┌─┐┌─┐┌┐┌┌┬┐┌─┐┬─┐┌─┐┬  ┬┬┌─┐┬ ┬
25├┤ │ ││││ │ ├─┘├┬┘├┤ └┐┌┘│├┤ │││
26└  └─┘┘└┘ ┴ ┴  ┴└─└─┘ └┘ ┴└─┘└┴┘
27Very customizable and minimal font previewer written in bash
28
29optional arguments:
30   -h, --help            show this help message and exit
31   -i, --input           filename of the input font (.otf, .ttf, .woff are supported)
32   -o, --output          filename of the output preview image (input.png if not set)
33   --size                size of the font preview window
34   --position            the position where the font preview window should be displayed
35   --search-prompt       input prompt of fuzzy searcher
36   --font-size           font size
37   --bg-color            background color of the font preview window
38   --fg-color            foreground color of the font preview window
39   --preview-text        preview text that should be displayed in the font preview window
40   --version             show the version of fontpreview you are using
41"
42}
43
44pre_exit() {
45    # Get the proccess ID of this script and kill it.
46    # We are dumping the output of kill to /dev/null
47    # because if the user quits sxiv before they
48    # exit this script, an error will be shown
49    # from kill and we dont want that
50    kill -9 "$(cat "$PIDFILE" 2>/dev/null)" &> /dev/null
51
52    # Delete tempfiles, so we don't leave useless files behind.
53    rm -rf "$FONTPREVIEW_DIR"
54}
55
56generate_preview(){
57    # Credits: https://bit.ly/2UvLVhM
58    convert -size $SIZE xc:"$BG_COLOR" \
59        -gravity center \
60        -pointsize $FONT_SIZE \
61        -font "$1" \
62        -fill "$FG_COLOR" \
63        -annotate +0+0 "$PREVIEW_TEXT" \
64        -flatten "$2"
65}
66
67main(){
68    # Checkig if needed dependencies are installed
69    dependencies=(xdotool sxiv convert fzf)
70    for dependency in "${dependencies[@]}"; do
71        type -p "$dependency" &>/dev/null || {
72            echo "error: Could not find '${dependency}', is it installed?" >&2
73            exit 1
74        }
75    done
76
77    # Checking for enviornment variables which the user might have set.
78    # This config file for fontpreview is pretty much the bashrc, zshrc, etc
79    # Majority of the variables in fontpreview can changed using the enviornment variables
80    # and this makes fontpreview very customizable
81    [[ $FONTPREVIEW_SEARCH_PROMPT != "" ]] && SEARCH_PROMPT=$FONTPREVIEW_SEARCH_PROMPT
82    [[ $FONTPREVIEW_SIZE != "" ]] && SIZE=$FONTPREVIEW_SIZE
83    [[ $FONTPREVIEW_POSITION != "" ]] && POSITION=$FONTPREVIEW_POSITION
84    [[ $FONTPREVIEW_FONT_SIZE != "" ]] && FONT_SIZE=$FONTPREVIEW_FONT_SIZE
85    [[ $FONTPREVIEW_BG_COLOR != "" ]] && BG_COLOR=$FONTPREVIEW_BG_COLOR
86    [[ $FONTPREVIEW_FG_COLOR != "" ]] && FG_COLOR=$FONTPREVIEW_FG_COLOR
87    [[ $FONTPREVIEW_PREVIEW_TEXT != "" ]] && PREVIEW_TEXT=$FONTPREVIEW_PREVIEW_TEXT
88
89    # Save the window ID of the terminal window fontpreview is executed in.
90    # This is so that when we open up sxiv, we can change the focus back to
91    # the terminal window, so that the user can search for the fonts without
92    # having to manualy change the focus back to the terminal.
93    xdotool getactivewindow > "$TERMWIN_IDFILE"
94
95    # Flag to run some commands only once in the loop
96    FIRST_RUN=true
97
98    while true; do
99        # List out all the fonts which imagemagick is able to find, extract
100        # the font names and then pass them to fzf
101        font=$(convert -list font | awk -F: '/^[ ]*Font: /{print substr($NF,2)}' | fzf --prompt="$SEARCH_PROMPT")
102
103        # Exit if nothing is returned by fzf, which also means that the user
104        # has pressed [ESCAPE]
105        [[ -z $font ]] && return
106
107        generate_preview "$font" "$FONT_PREVIEW"
108
109        if [[ $FIRST_RUN == true ]]; then
110            FIRST_RUN=false
111
112            # Display the font preview using sxiv
113            #sxiv -g "$SIZE$POSITION" "$FONT_PREVIEW" -N "fontpreview" -b &
114            sxiv -N "fontpreview" -b -g "$SIZE$POSITION" "$FONT_PREVIEW" &
115
116            # Change focus from sxiv, back to the terminal window
117            # so that user can continue to search for fonts without
118            # having to manually change focus back to the terminal window
119            xdotool windowfocus "$(cat "$TERMWIN_IDFILE")"
120
121            # Save the process ID so that we can kill
122            # sxiv when the user exits the script
123            echo $! >"$PIDFILE"
124
125	# Check for crashes of sxiv
126	elif [[ -f $PIDFILE ]] ; then
127	    if ! pgrep -F "$PIDFILE" >/dev/null 2>&1; then
128		echo "Restart sxiv - You maybe using a obsolete version. " >&2
129		# Display the font preview using sxiv
130		sxiv -g "$SIZE$POSITION" -N "fontpreview" -b "$FONT_PREVIEW" &
131
132		# Change focus from sxiv, back to the terminal window
133		# so that user can continue to search for fonts without
134		# having to manually change focus back to the terminal window
135		xdotool windowfocus "$(cat "$TERMWIN_IDFILE")"
136
137		# Save the process ID so that we can kill
138		# sxiv when the user exits the script
139		echo $! >"$PIDFILE"
140	    fi
141
142	fi
143    done
144}
145
146# Disable CTRL-Z because if we allowed this key press,
147# then the script would exit but, sxiv would still be
148# running
149trap "" SIGTSTP
150
151trap pre_exit EXIT
152
153# Use mktemp to create a temporary directory that won't
154# collide with temporary files of other application.
155FONTPREVIEW_DIR="$(mktemp -d "${TMPDIR:-/tmp}/fontpreview_dir.XXXXXXXX")" || exit
156PIDFILE="$FONTPREVIEW_DIR/fontpreview.pid"
157touch "$PIDFILE" || exit
158FONT_PREVIEW="$FONTPREVIEW_DIR/fontpreview.png"
159touch "$FONT_PREVIEW" || exit
160TERMWIN_IDFILE="$FONTPREVIEW_DIR/fontpreview.termpid"
161touch "$TERMWIN_IDFILE" || exit
162
163font=$1
164
165
166# Parse the arguments
167options=$(/usr/local/bin/getopt -o hi:o: --long position:,size:,version,search-prompt:,font-size:,bg-color:,fg-color:,preview-text:,input:,output:,help -- "$@")
168eval set -- "$options"
169
170while true; do
171    case "$1" in
172        --size)
173            shift
174            FONTPREVIEW_SIZE=$2
175            ;;
176        --position)
177            shift
178            FONTPREVIEW_POSITION=$2
179            ;;
180        -h|--help)
181            show_help
182            exit
183            ;;
184        --version)
185            echo $VERSION
186            exit
187            ;;
188        -i|--input)
189            input_file="$2"
190            ;;
191        -o|--output)
192            output_file="$2"
193            ;;
194        --search-prompt)
195            FONTPREVIEW_SEARCH_PROMPT=$2
196            ;;
197        --font-size)
198            FONTPREVIEW_FONT_SIZE=$2
199            ;;
200        --bg-color)
201            FONTPREVIEW_BG_COLOR=$2
202            ;;
203        --fg-color)
204            FONTPREVIEW_FG_COLOR=$2
205            ;;
206        --preview-text)
207            FONTPREVIEW_PREVIEW_TEXT=$2
208            ;;
209        --)
210            shift
211            break
212            ;;
213    esac
214    shift
215done
216
217
218# Point a font file to fontpreview and it will preview it.
219# Example:
220#   $ fontpreview /path/to/fontFile.ttf
221#
222# This is useful because people can preview fonts which they have not
223# installed onto their system. So if they want to preview a font file that
224# is in their Downloads directory, then they can easily preview it.
225if [ -f "$font" ]; then
226    generate_preview "$font" "$FONT_PREVIEW"
227
228    # Display the font preview using sxiv
229    sxiv -g "$SIZE$POSITION" -N "fontpreview" -b "$FONT_PREVIEW" &
230
231    # For some strange reason, sxiv just doesnt have time to read the file
232    sleep 0.1
233    exit
234fi
235
236# Check if the user gave an input file if they did, then create a preview
237# and then save the preview to the current working directory
238if [ "$input_file" != "" ] ; then
239    [ -z "$output_file" ] && output_file="${input_file}.png"
240    generate_preview "$input_file" "$output_file"
241    exit
242fi
243
244main
245