425 lines
9.6 KiB
Bash
Executable File
425 lines
9.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# This file is part of pnglatex <https://github.com/mneri/pnglatex>.
|
|
# Copyright Massimo Neri <hello@mneri.me> and all the contributors.
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
BACKGROUND=
|
|
BORDER=
|
|
DPI=
|
|
ENVIRONMENT=
|
|
FOREGROUND=
|
|
FORMULA=
|
|
HEADER=
|
|
HELP=0
|
|
LOGFILE=
|
|
MARGIN=
|
|
OPTIMIZE=0
|
|
PACKAGES=
|
|
PADDING=
|
|
PNGFILE=
|
|
SHOWVERSION=0
|
|
SILENT=0
|
|
SIZE=
|
|
TEXFILE=
|
|
declare -r VERSION=0.13
|
|
|
|
# Add margin, border and padding to the image.
|
|
function box {
|
|
if [ "$PADDING" ]; then
|
|
convert $PNGFILE -bordercolor $BACKGROUND -border $(scale $PADDING) $PNGFILE
|
|
fi
|
|
|
|
if [ "$BORDER" ]; then
|
|
convert $PNGFILE -bordercolor $BORDER -border $(scale 1) $PNGFILE
|
|
fi
|
|
|
|
if [ "$MARGIN" ]; then
|
|
convert $PNGFILE -bordercolor $BACKGROUND -border $(scale $MARGIN) $PNGFILE
|
|
fi
|
|
}
|
|
|
|
# Remove temporary files.
|
|
function clean {
|
|
rm -rf $TMPDIR
|
|
}
|
|
|
|
# Get screen's dpi.
|
|
#
|
|
# @return the dpi resolution of the screen.
|
|
function dpi {
|
|
local VALUE
|
|
|
|
if exists xdpyinfo; then
|
|
VALUE=$(xdpyinfo 2> /dev/null | grep resolution | sed -r 's/^[^0-9]+([0-9]+)x.*$/\1/')
|
|
fi
|
|
|
|
if [ ! "$VALUE" ]; then
|
|
VALUE=96
|
|
fi
|
|
|
|
echo $VALUE
|
|
}
|
|
|
|
# Check if the specified command is installed on the system.
|
|
#
|
|
# @param $1 the command to test.
|
|
# @return true if the command is installed on the system, false otherwise.
|
|
function exists {
|
|
local COMMAND=$1
|
|
return $(command -v $COMMAND &> /dev/null)
|
|
}
|
|
|
|
# Generate the png image.
|
|
function generate {
|
|
local BEGINENV
|
|
local ENDENV
|
|
local PREFIX
|
|
local TMPDIR
|
|
local SUFFIX
|
|
|
|
TMPDIR="$(mktemp -d)"
|
|
TEXFILE="$(mktemp -p $TMPDIR tXXX.tex)"
|
|
|
|
if [ "$ENVIRONMENT" = '$' ] || [ "$ENVIRONMENT" = '$$' ]; then
|
|
BEGINENV=$ENVIRONMENT
|
|
ENDENV=$ENVIRONMENT
|
|
else
|
|
BEGINENV=$(echo $ENVIRONMENT | sed -e 's/\([^\[\{]*\)/\\begin\{\1\}/')
|
|
ENDENV=$(echo $ENVIRONMENT | sed -e 's/\([^\[\{]*\).*/\\end\{\1\}/')
|
|
fi
|
|
|
|
echo "\documentclass[${SIZE}pt]{article}\pagestyle{empty}" > $TEXFILE
|
|
|
|
{
|
|
IFS=":"
|
|
|
|
for P in $PACKAGES; do
|
|
echo $P | sed -e 's/\([^\[\{]*\)/\\usepackage\{\1\}/' >> $TEXFILE
|
|
done
|
|
}
|
|
|
|
if [ ! -z "$HEADER" ]; then
|
|
cat $HEADER >> $TEXFILE
|
|
fi
|
|
|
|
echo "\begin{document}$BEGINENV" >> $TEXFILE
|
|
|
|
if [ ! "$FORMULA" ]; then
|
|
cat - >> $TEXFILE
|
|
else
|
|
echo $FORMULA >> $TEXFILE
|
|
fi
|
|
|
|
echo "$ENDENV\end{document}" >> $TEXFILE
|
|
|
|
if [ "$LOGFILE" ]; then
|
|
cat $TEXFILE > $LOGFILE
|
|
fi
|
|
|
|
latex -halt-on-error -interaction=nonstopmode -output-directory=$TMPDIR $TEXFILE \
|
|
| tee -a $LOGFILE \
|
|
| sed -n '/^!/,/^ /p' >&2
|
|
|
|
if [ ${PIPESTATUS[0]} -ne 0 ]; then
|
|
clean
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! "$PNGFILE" ]; then
|
|
PNGFILE="$(mktemp -p $PWD fXXX.png)"
|
|
fi
|
|
|
|
dvipng -bg $BACKGROUND -D $DPI -fg $FOREGROUND -o $PNGFILE -q --strict -T tight ${TEXFILE%.tex}.dvi \
|
|
| tee -a $LOGFILE \
|
|
> /dev/null
|
|
|
|
if [ "$PADDING" ] || [ "$BORDER" ] || [ "$MARGIN" ]; then
|
|
box
|
|
fi
|
|
|
|
if [ $OPTIMIZE -eq 1 ]; then
|
|
optimize
|
|
fi
|
|
|
|
if [ $SILENT -eq 0 ]; then
|
|
readlink -f $PNGFILE
|
|
fi
|
|
|
|
clean
|
|
}
|
|
|
|
# Entry point of the script.
|
|
function main {
|
|
if ! exists latex || ! exists dvipng; then
|
|
echo "pnglatex requires latex and dvipng packages." >&2
|
|
exit 1
|
|
fi
|
|
|
|
properties
|
|
parse "$@"
|
|
|
|
if [ $HELP -eq 1 ]; then
|
|
usage
|
|
exit 0
|
|
fi
|
|
|
|
if [ $SHOWVERSION -eq 1 ]; then
|
|
version
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$PADDING" ] || [ "$BORDER" ] || [ "$MARGIN" ]; then
|
|
if ! exists convert; then
|
|
echo "Paddings, borders and margins require imagemagick package." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ $OPTIMIZE -eq 1 ]; then
|
|
if ! exists optipng; then
|
|
echo "Optimization requires optipng package." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ ! -z "$HEADER" ] && [ ! -f "$HEADER" ]; then
|
|
echo "File does not exist: $HEADER" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$BACKGROUND" ]; then
|
|
BACKGROUND=White
|
|
fi
|
|
|
|
if [ -z "$DPI" ]; then
|
|
DPI=$(dpi)
|
|
else
|
|
if ! match "$DPI" '^[1-9][0-9]*$'; then
|
|
echo "Invalid dpi." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$ENVIRONMENT" ]; then
|
|
ENVIRONMENT=\$
|
|
fi
|
|
|
|
if [ -z "$FOREGROUND" ]; then
|
|
FOREGROUND=Black
|
|
fi
|
|
|
|
if [ ! -z "$MARGIN" ] && ! match "$MARGIN" '^[0-9]+(x[0-9]+)?$'; then
|
|
echo "Invalid margin." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -z "$PADDING" ] && ! match "$PADDING" '^[0-9]+(x[0-9]+)?$'; then
|
|
echo "Invalid padding." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$SIZE" ]; then
|
|
SIZE=11
|
|
else
|
|
SIZE=$(echo $SIZE | sed 's/pt//')
|
|
|
|
if ! match "$SIZE" '^[1-9][0-9]*$'; then
|
|
echo "Invalid font size." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
generate
|
|
}
|
|
|
|
# Return true if the specified string matches the specified regular expression
|
|
#
|
|
# @param $1 The string to test.
|
|
# @param $2 The pattern to match.
|
|
# @return true if the string matches the pattern, false otherwise.
|
|
function match {
|
|
local PATTERN=$2
|
|
local TEXT=$1
|
|
|
|
return $(echo $TEXT | egrep $PATTERN &> /dev/null);
|
|
}
|
|
|
|
# Use optipng to optimize the image.
|
|
#
|
|
# @return echoes optipng output.
|
|
function optimize {
|
|
optipng -f0-5 -quiet -zc1-9 -zm1-9 -zs0-3 $PNGFILE
|
|
}
|
|
|
|
# Parse command line arguments.
|
|
function parse {
|
|
while getopts b:B:d:e:f:F:hH:l:m:Mo:Op:P:r:s:Sv ARG; do
|
|
case $ARG in
|
|
b)
|
|
BACKGROUND=$OPTARG
|
|
;;
|
|
B)
|
|
BORDER=$OPTARG
|
|
;;
|
|
d)
|
|
DPI=$OPTARG
|
|
;;
|
|
e)
|
|
ENVIRONMENT=$OPTARG
|
|
;;
|
|
f)
|
|
FORMULA=$OPTARG
|
|
;;
|
|
F)
|
|
FOREGROUND=$OPTARG
|
|
;;
|
|
h)
|
|
HELP=1
|
|
;;
|
|
H)
|
|
HEADER=$OPTARG
|
|
;;
|
|
l)
|
|
LOGFILE=$OPTARG
|
|
;;
|
|
m)
|
|
MARGIN=$OPTARG
|
|
;;
|
|
o)
|
|
PNGFILE=$OPTARG
|
|
;;
|
|
O)
|
|
OPTIMIZE=1
|
|
;;
|
|
p)
|
|
PACKAGES=$OPTARG
|
|
;;
|
|
P)
|
|
PADDING=$OPTARG
|
|
;;
|
|
s)
|
|
SIZE=$OPTARG
|
|
;;
|
|
S)
|
|
SILENT=1
|
|
;;
|
|
v)
|
|
SHOWVERSION=1
|
|
;;
|
|
?)
|
|
exit 1
|
|
esac
|
|
done
|
|
}
|
|
|
|
function properties {
|
|
local PROPERTIES=~/.pnglatex
|
|
|
|
if [ -f $PROPERTIES ]; then
|
|
while IFS="=" read -r KEY VALUE; do
|
|
case $KEY in
|
|
BACKGROUND)
|
|
BACKGROUND=$VALUE
|
|
;;
|
|
BORDER)
|
|
BORDER=$VALUE
|
|
;;
|
|
DPI)
|
|
DPI=$VALUE
|
|
;;
|
|
ENVIRONMENT)
|
|
ENVIRONMENT=$VALUE
|
|
;;
|
|
FOREGROUND)
|
|
FOREGROUND=$VALUE
|
|
;;
|
|
HEADER)
|
|
HEADER=$VALUE
|
|
;;
|
|
MARGIN)
|
|
MARGIN=$VALUE
|
|
;;
|
|
OPTIMIZE)
|
|
OPTIMIZE=$VALUE
|
|
;;
|
|
PACKAGES)
|
|
PACKAGES=$VALUE
|
|
;;
|
|
PADDING)
|
|
PADDING=$VALUE
|
|
;;
|
|
SIZE)
|
|
SIZE=$(echo $VALUE | sed 's/pt//')
|
|
;;
|
|
esac
|
|
done < $PROPERTIES
|
|
fi
|
|
}
|
|
|
|
# Scales the specified dimensions to the wanted dpi.
|
|
#
|
|
# @param $1 the dimension string, in the form of 'mxn', where m and n are integers.
|
|
# @return echoes the scaled dimension string.
|
|
function scale {
|
|
local BASEDPI=$(dpi)
|
|
local WIDTH=$(($(echo $1 | sed -r 's/x.*//') * $DPI / $BASEDPI))
|
|
local HEIGHT=$(($(echo $1 | sed -r 's/.*x//') * $DPI / $BASEDPI))
|
|
|
|
echo ${WIDTH}x${HEIGHT}
|
|
}
|
|
|
|
# Print usage message.
|
|
#
|
|
# @return echoes the usage message.
|
|
function usage {
|
|
echo "pnglatex $VERSION - Write LaTeX formulas into PNG files."
|
|
echo "Copyright Massimo Neri <hello@mneri.me> and all the contributors."
|
|
echo
|
|
echo "List of options:"
|
|
echo " -b <color> Set the background color."
|
|
echo " -B <color> Set the border color."
|
|
echo " -d <dpi> Set the output resolution to the specified dpi."
|
|
echo " -e <environment> Set the environment with [options] and {arguments}."
|
|
echo " -f <formula> The LaTeX formula."
|
|
echo " -F <color> Set the foreground color."
|
|
echo " -h Print this help message."
|
|
echo " -H <file> Insert the content of the specified file in the preamble."
|
|
echo " -l <file> Log file."
|
|
echo " -m <margin> Set the margin."
|
|
echo " -o <file> Specify the output file name."
|
|
echo " -O Optimize the image."
|
|
echo " -p <packages> A colon separated list of LaTeX package names."
|
|
echo " -P <padding> Set the padding."
|
|
echo " -s <size> Set the font size."
|
|
echo " -S Silent mode: don't print image file name."
|
|
echo " -v Show version."
|
|
echo
|
|
echo "Examples:"
|
|
echo " pnglatex -f \"E=mc^2\""
|
|
echo " pnglatex -e displaymath -f \"\sum_{i=0}^n i=\frac{n(n+1)}{2}\""
|
|
echo " pnglatex -b Transparent -p amssymb:amsmath -P 5x5 -s 12 -f \"A\triangleq B\""
|
|
}
|
|
|
|
# Print pnglatex version.
|
|
#
|
|
# @return echoes the version.
|
|
function version {
|
|
echo $VERSION
|
|
}
|
|
|
|
trap "clean" SIGINT SIGTERM
|
|
main "$@"
|