On Mon, Apr 30, 2012, Denis M. Wilson wrote:
>
> On Wed, 25 Apr 2012 13:30:38 -0400
> Peter Schaffter <[email protected]> wrote:
>
> > This works for me:
> >
> > - use fontforge to convert the .otf to .t42 and .pfa (which
> > generates an .afm)
> > - use the .afm, with afmtodit, to generate a groff font
> > - move the .t42 and groff font to your groff font dir (I use
> > site-font/devps so my fonts survive across groff installations)
> > - add the font to your 'download' file
> >
>
> Peter, thanks for that. It works fine, although laborious.
Attached is a bash script, install-font, that automates the process.
I'll eventually be making it available on the mom website, so please
test.
> There are still problems, such as the smallcaps names are a.sc etc,
> and ligatures are given unicode names so afmtodit does not recognise
> them.
Of the various freely-available font conversion utilities, fontforge
seems the least error prone; however, it does occasionally entail
the problems you mention. Does anyone know of a utility that
circumvents them?
> By doing the translation I may be violating the license.
Not much one can do about that, except rely on the honour system.
--
Peter Schaffter
Author of The Binbrook Caucus
http://www.schaffter.ca
#!/bin/bash
set -e
ROOT_UID=0
OPTERR=1
loc_or_sysdir=/usr/local/share/groff # make this default
version=`groff -v | tail -1 | sed -e 's/[[:print:]]* \([0-9.]*\)$/\1/'`
trap interrupt SIGINT
shopt -s expand_aliases
alias cp='cp -f' # -p flag for interactive
alias ln='ln -f'
alias mv='mv -f'
show_usage()
{
printf \
"Usage: install-font [-lscpdD] \
[-C \033[4mdir\033[0m] \
[-F \033[4mfamily\033[0m] \
[-f \033[4mgroff fontname\033[0m] | +\033[4mSTYLE\033[0m] file ...\n\
Longer help: install-font -H (pipe through 'less' or 'more')\n"
}
long_help()
{
printf <<EOF \
"USAGE:
install-font [-hHlscp] [-C \033[4mdir\033[0m] [-F \033[4mfamily\033[0m]] \
[-f \033[4mgroff fontname\033[0m]] file1 file2 ...
DESCRIPTION:
A utility to make TrueType (.ttf), OpenType (.otf), and
PostScript Type1 (.pfa, .pfb) fonts available for use with
groff.
With no options, for every file named on the command line,
\033[4minstall-font\033[0m prompts for
- a family name
- a groff fontname
- whether to make the font available to gropdf
- whether to copy the input file(s) to a system-wide location
\033[4minstall-font\033[0m calls fontforge to convert TrueType and OpenType
fonts to PostScript Type42 (.t42) and Type1 (.pfa), from which
a groff font is generated. The .t42 and groff fonts are moved
to site-font/devps/ and registered in the 'download' file. If
the font is to be available to gropdf, the .pfa is moved to
font/devpdf/ and registered in the 'download' file. A symlink
is made to the groff font in site-font/devps.
PostScript fonts are converted to .pfa, even those with a .pfa
extension. The generated .pfa has a filename derived from the
font's PostScript name. This is helpful in the case of fonts with
cryptic names like 'bchri8a.pfa', which becomes 'CharterBT-Italic.pfa'.
In all cases, the original file is preserved with its original
name in the directory from which the font is being installed.
The .pfa and groff fonts are moved to site-font/devps/ and
registered in the 'download' file. If the font is to be
available to gropdf, symlinks are made in font/devpdf/ to both
the .pfa and the groff font. The .pfa is registered in the
'download' file.
OPTIONS
Options not requiring an argument may be grouped.
-h Short help.
-H Long help.
-l Assume prefix /usr/local/ for all directories. (default)
-s Assume prefix /usr/ for all directories.
-c Copy file(s) named on the command line to a system-accessible
location. If neither -s nor -C is given, copy to the family
directory (see -F) under /usr/local/share/fonts/<fonttype>/,
where <fonttype> is one of 'truetype', 'type1', or 'opentype'.
If -s is given, copy to the family directory located under
/usr/share/fonts/<fonttype>/.
If neither -c nor -C is given, a prompt asks whether to copy
the file(s) named on the command line.
-d Make font available to gropdf.
-D Do not make font available to gropdf.
-p Ask before overwriting or linking files. Default is to
overwrite without asking.
-C \033[4mdir\033[0m
Copy file(s) named on the command line to the family directory
(see -F) in \033[4mdir\033[0m.
-F \033[4mfamily\033[0m
Family to which the font belongs. Creates a family for the
groff font, which can then be accessed by calls to .fam or
.FAMILY (mom macros). Also creates a family directory for
fonts being made available system-wide (see -c and -C).
-F is useful for batch processing fonts that belong to the
same family. Use with care, since all files named on the
command line will be assigned to \033[4mfamily\033[0m.
If -F is not given, a prompt asks for the family name.
-f \033[4mname\033[0m or +\033[4mSTYLE\033[0m
Name by which to access the font with calls to .ft or
.FT (mom macros). \033[4mname\033[0m may be arbitrary, or a '+' sign
prefixed to an uppercase fontstyle recognized by groff,
e.g. +R, +I, +B, +BDI, which respectively stand for regular,
italic, bold, and bold italic. The mom macros provide
additional styles, which may also be used.
+\033[4mSTYLE\033[0m is affixed to the family name to arrive at the
groff fontname.
install-font -F Garamond -f +R <file>
creates font GaramondR, which can be accessed by
.fam Garamond
.ft R
or
.ft GaramondR
-f is not compatible with batch processing. \033[4minstall-font\033[0m
will abort if the -f option is given and multiple files are
named on the command line.
If -f is not given, a prompt asks for the font name.
"
EOF
}
case $1 in
-h | "")
show_usage
exit 0
;;
-H)
long_help
exit 0
;;
esac
# need write access to /usr/ and /usr/local/
if [ "$UID" -ne "$ROOT_UID" ] ; then
scriptname=`basename $0`
printf \
"Superuser priviledges required.\nRerun as \
'\033[33msudo ${scriptname} \033[4margs\033[0m' \
or \
'\033[33msu root -c \"${scriptname} \033[4margs\033[0m\033[33m\"\033[0m'\n"
exit 126
fi
# if fontforge not installed, no point going any further
type fontforge > /dev/null 2>&1 || {
printf "fontforge not installed. Aborting.\n" >&2
exit 1
}
tmp_dir=/tmp/install-font
[ -d ${tmp_dir} ] || mkdir ${tmp_dir}
clean_tmp()
{
for i in ${tmp_dir}/*[!pe] ; do rm -f "$i" ; done
}
interrupt()
{
clean_tmp
printf "\nAborting.\n"
exit 130
}
error()
{
case "$1" in
no_filename)
printf \
"[install-font]: Missing filename. \
Aborting.\n" >&2
exit 1
;;
no_file)
printf \
"[install-font]: File \"${file}\" not found. \
Aborting.\n" >&2
exit 1
;;
no_arg)
printf \
"[install-font]: Option \"-${option}\" requires an argument. \
Aborting.\n" >&2
show_usage
exit 1
;;
filename_arg)
printf \
"[install-font]: Option \"-${option}\" requires a non-filename argument. \
Aborting.\n" >&2
show_usage
exit 1
;;
no_dir)
printf \
"[install-font]: Directory \"${copy_dir}\" not found. \
Aborting.\n" >&2
exit 1
;;
incompatible)
printf \
"[install-font]: Incompatible file type. Must have extension ttf|pfa|pfb. \
Aborting.\n" >&2
exit 1
;;
arg_to_f)
printf \
"[install-font]: Option -${option} incompatible with multiple filenames. \
Aborting.\n" >&2
exit 1
esac
}
generate_t42()
{
cat <<EOF > ${tmp_dir}/generate-t42.pe
# generate-t42.pe
Open(\$1);
Generate(\$fontname + ".pfa");
Generate(\$fontname + ".t42");
EOF
}
generate_pfa()
{
cat <<EOF > ${tmp_dir}/generate-pfa.pe
# generate-pfa.pe
Open(\$1);
Generate(\$fontname + ".pfa");
EOF
}
convert_font()
{
printf "Running fontforge...\n"
fontforge -script ${script} ${file}
printf "Done.\n"
}
make_font()
{
printf "Creating \033[33m${groff_font}\033[0m...\n"
afmtodit ${font}.afm textmap ${groff_font}
rm ${font}.afm
printf "Done.\n"
}
install_to_devps()
{
printf "Installing \033[33m${groff_font}\033[0m in ${site_font}/... "
mv ${font}.${ext} ${site_font}/
mv ${groff_font} ${site_font}/
# update the download file in site-font/devps
[ -e ${site_font}/download ] || {
touch ${site_font}/download
}
[ $argc -eq 1 ] && {
cp ${site_font}/download ${site_font}/download.bak
}
printf "${font}\t${font}.${ext}\n" >> ${site_font}/download
printf "Done.\n"
}
install_to_devpdf()
{
if [ ${install_in_devpdf} ] ; then
gropdf=yes
else
printf \
"Make \033[33m${groff_font}\033[0m available to gropdf? (y/n; default = y) "
read gropdf
fi
case $gropdf in
Y | y | YES | Yes | yes | "")
printf "Checking for gropdf executable and devpdf directory... "
have_gropdf=`type gropdf`
if [ "$have_gropdf" ] ; then
printf \
"gropdf found.\nInstalling \033[33m${groff_font}\033[0m in ${devpdf}/... "
if [ -d ${devpdf} ] ; then
case ${ext} in
t42)
mv ${font}.pfa ${devpdf}/
;;
pfa)
ln -s ${site_font}/${font}.pfa ${devpdf}/${font}.pfa
;;
esac
ln -s ${site_font}/${groff_font} ${devpdf}/${groff_font}
[ -e ${devpdf}/download.orig ] || {
cp ${devpdf}/download ${devpdf}/download.orig
}
[ $argc -eq 1 ] && {
cp -f ${devpdf}/download ${devpdf}/download.bak
}
printf "\t${font}\t${font}.pfa\n" >> ${devpdf}/download
printf "Done.\n"
else
printf \
"You do not have a ${devpdf} directory.\nNo fonts will be install in devpdf.\n"
fi
else
printf \
"gropdf is not present on the system. No fonts will be installed in devpdf.\n"
fi ;;
esac
}
get_fontname()
{
printf \
"Enter +STYLE (eg +R, +I, +BD, +BDI), or a unique groff name for \
\033[36m${font}\033[0m.\n"
printf \
"Leave blank to set name to '\033[36m${font}\033[0m': "
}
convert_install()
{
cd ${tmp_dir}
convert_font # generate t42/pfa and afm files
# get postscript family and font name from afm
family_name=`grep "^FamilyName" *afm | \
sed -e 's/^FamilyName *\([[:graph:]]\{1,\}\) *[[:print:]]*$/\1/'`
font=`grep "^FontName" ${font}*afm | \
sed -e 's/^FontName *\([[:graph:]]\{1,\}\) *[[:print:]]*$/\1/'`
if [ ! ${family} ] ; then # get user's name for family
printf "Family name (default = ${family_name}): "
read family
[ ${family} ] || family=${family_name}
fi
printf \
" =>\033[36m${font}\033[0m (${file}) assigned to family \
'\033[33m${family}\033[0m'.\n"
if [ ! ${groff_font} ] ; then # get groff fontname
if [ ! ${append_style} ] ; then
get_fontname
read groff_font
[ ${groff_font} ] || groff_font=${font}
append_style=${groff_font:0:1}
[ "$append_style" = "+" ] && {
append_style=${groff_font##*+}
groff_font=${family}${append_style}
}
else
groff_font=${family}${append_style}
fi
fi
printf \
" =>\033[36m${font}\033[0m assigned groff fontname \
'\033[33m${groff_font}\033[0m'.\n"
if [ ! -e textmap ] ; then
[ -e ${devps}/generate/textmap ] && ln -s ${devps}/generate/textmap . || {
printf "'textmap' not found. Aborting.\n" >&2 ; exit 1
}
fi
make_font
install_to_devps
[ ${skip_devpdf} ] || install_to_devpdf
rm -f ${font}*
cd - &>/dev/null
}
copy_file()
{
[ -d ${copy_dir} ] || {
echo "${copy_dir} not found; creating."
mkdir ${copy_dir} ;
}
[ -d ${copy_dir}/${family} ] || {
mkdir ${copy_dir}/${family}
}
printf "Installing ${file} in ${copy_dir}/${family}/... "
cp ${file} ${copy_dir}/${family}/
printf "Done.\n"
}
print_sep()
{
printf \
"======================================================================\n"
}
# getopts doesn't check if OPTARG is a flag, or a filename when some
# other value is expected
check_optarg()
{
[ "${OPTARG:0:1}" = "-" ] && error no_arg
eval "has_ext=`echo ${OPTARG} | sed -e 's/^[[:graph:]]*\.[[:graph:]]*$/./'`"
[ "${has_ext}" = "." ] && error filename_arg
:
}
while getopts ":C:cdDF:f:hHlps" opt
do
case "$opt" in
c)
copy_orig=yes
;;
C)
option=C
check_optarg
copy_orig=yes
copy_dir=${OPTARG}
[ -d ${copy_dir} ] || error no_dir
;;
d)
install_in_devpdf=yes
;;
D)
skip_devpdf=yes
;;
F)
option=F
check_optarg
family=${OPTARG}
;;
f)
option=f
opt_f=true
check_optarg
append_style=${OPTARG:0:1}
case ${append_style} in
"+")
append_style=${OPTARG##*+}
;;
*)
groff_font=${OPTARG}
;;
esac
;;
h)
show_usage
exit 0
;;
H)
long_help
exit 0
;;
l)
loc_or_sysdir=/usr/local/share/groff
;;
p)
alias mv='mv -i'
alias ln='ln -i'
alias cp='cp -i'
;;
s)
loc_or_sysdir=/usr/share/groff
;;
\?)
printf "Option \"-${OPTARG}\" not valid. Aborting.\n" >&2
show_usage
exit 1
;;
:)
printf "Option \"-${OPTARG}\" requires an argument. Aborting.\n" >&2
show_usage
exit 1
;;
esac
done
shift $((OPTIND-1))
[ "$#" -eq 0 ] && error no_filename
[ $# -gt 1 -a "${opt_f}" ] && {
error arg_to_f
exit 1
}
devps=${loc_or_sysdir}/${version}/font/devps
devpdf=${loc_or_sysdir}/${version}/font/devpdf
site_font=${loc_or_sysdir}/site-font/devps
# create site-font and site-font/devps if not present
[ -d ${loc_or_sysdir}/site-font ] || {
printf "${loc_or_sysdir}/site-font not found; creating.\n"
mkdir ${loc_or_sysdir}/site-font
}
[ -d ${site_font} ] || {
printf "${site_font} not found; creating.\n"
mkdir ${site_font}
}
# process files
for i in "$@" ; do
file="$i"
argc=$((argc+1))
[ -f ${file} ] || error no_file
case ${file##*.} in
TTF | ttf | PFB | pfb | PFA | pfa | OTF | otf)
font_type=${file##*.}
;;
*)
error incompatible
;;
esac
ln -s $PWD/${file} ${tmp_dir}/${file} # make a link in tmp dir to file
[ $argc -gt 1 ] && print_sep
printf "Processing \033[36m$file\033[0m...\n"
case ${font_type} in
TTF | ttf | OTF | otf)
script=generate-t42.pe
ext=t42
[ -e /tmp/$script ] || generate_t42 # create if it doesn't exist
convert_install
if [ "${font_type}" = "TTF" -o "${font_type}" = "ttf" ] ; then
[ ${copy_dir} ] || copy_dir=/usr/local/share/fonts/truetype
else
[ ${copy_dir} ] || copy_dir=/usr/local/share/fonts/opentype
fi
;;
PFB | pfb | PFA | pfa)
script=generate-pfa.pe
ext=pfa
[ -e /tmp/$script ] || generate_pfa # create if it doesn't exist
convert_install
[ ${copy_dir} ] || copy_dir=/usr/local/share/fonts/type1
;;
esac
# copy input file to a system or named directory
if [ ! "$copy_orig" ] ; then
printf \
"Copy \033[36m${file}\033[0m to ${copy_dir}/${family}/?\n (y/n; default = n) "
read copy_file
case "$copy_file" in
Y | y | YES | Yes | yes)
copy_file
;;
* )
printf \
"Install \033[36m${file}\033[0m manually to make it available system-wide.\n"
;;
esac
else
copy_file
fi
unset append_style
unset ext
unset font
unset groff_font
done
clean_tmp
exit 0