3

As a sort of follow-up to these two questions, I'm interested in trying to fine-tune the output of transforming characters so they don't look too out-of-alignment. The main use-case of this (at present) is in typesetting documents utilising the dozenal or duodecimal numeral system. Whilst the desired characters are available in Unicode, they're nonexistent in virtually all fonts, so the character transforms are necessary for the time being.

What I'm after is twofold. Firstly, if the correct Unicode glyphs are available in the font, I don't want to perform the transformation/substitution. Secondly, and more importantly, if the transformation is performed, I want to avoid the awkward kerning keming I get with the transformed characters. How could the rendering be improved?

Dozenal text rendering example

Here's a MWE. The initial code to get it working was shamelessly stolen from egreg's answer to the first linked question. The fonts aren't strictly necessary, but they're my preferred fonts in the documents I've been typing up, so improving how they look is quite important.

\documentclass{article}

\usepackage{fontspec}
\usepackage{microtype}

% Special characters for dozenal numerals

% newunicodechar and graphicx are needed to substitute and rotate the characters
\usepackage{newunicodechar}
\usepackage{graphicx}

\newcommand{\DeclareUnicodeCharacter}[2]{%
  \begingroup\lccode`|=\string"#1\relax
    \lowercase{\endgroup\newunicodechar{|}}{#2}%
}

\DeclareUnicodeCharacter{218A}{\turnedtwo}
\DeclareUnicodeCharacter{218B}{\turnedthree}

\makeatletter
\DeclareRobustCommand{\turnedtwo}{\make@turned{2}}
\DeclareRobustCommand{\turnedthree}{\make@turned{3}}
\newcommand{\make@turned}[1]{%
  \raisebox{\depth}{\scalebox{-1}[-1]{#1}}%
}
\makeatother


\setmainfont{Linux Libertine O}[
    Ligatures=TeX,
    Numbers=Uppercase,
]

\setsansfont{Fira Sans}[
    Ligatures=TeX,
    Numbers=Uppercase,
    Scale=MatchLowercase,
    BoldFont={* SemiBold},
]

\setmonofont{Fira Mono}[
    Ligatures=TeX,
    Scale=MatchLowercase,
]

\begin{document}

\Huge 

123456789↊↋0

\textit{123456789↊↋0}

\textbf{123456789↊↋0}

\textbf{\itshape 123456789↊↋0}

\sffamily 123456789↊↋0

\textit{123456789↊↋0}

\textbf{123456789↊↋0}

\textbf{\itshape 123456789↊↋0}

\end{document}
Robbie
  • 2,893

2 Answers2

2

I suggest to add some kerning on either side (canceling each other) when the font is slanted (more precisely, when the glyph has a nonzero italic correction). Also the coding can be simplified. You can try and get better positioning.

\documentclass{article}

\usepackage{fontspec}
\usepackage{microtype}

% Special characters for dozenal numerals

% newunicodechar and graphicx are needed to substitute and rotate the characters
\usepackage{newunicodechar}
\usepackage{graphicx}

\newunicodechar{^^^^218a}{\turnedtwo}
\newunicodechar{^^^^218b}{\turnedthree}

\makeatletter
\newcommand{\turnedtwo}{\make@turned{2}{0.15em}}
\newcommand{\turnedthree}{\make@turned{3}{0.15em}}
\newcommand{\make@turned}[2]{%
  \ifdim\fontcharic\font`#1>0pt\relax
    \kern#2\relax
  \fi
  \raisebox{\depth}{%
    \scalebox{-1}[-1]{%
      #1%
    }%
  }%
  \ifdim\fontcharic\font`#1>0pt\relax
    \kern-#2\relax
  \fi
}
\makeatother


\setmainfont{Linux Libertine O}[
    Ligatures=TeX,
    Numbers=Uppercase,
]

\setsansfont{Fira Sans}[
    Ligatures=TeX,
    Numbers=Uppercase,
    Scale=MatchLowercase,
    BoldFont={* SemiBold},
]

\setmonofont{Fira Mono}[
    Ligatures=TeX,
    Scale=MatchLowercase,
]

\begin{document}

\Huge

123456789↊↋0

\textit{123456789↊↋0}

\textbf{123456789↊↋0}

\textbf{\itshape 123456789↊↋0}

\sffamily 123456789↊↋0

\textit{123456789↊↋0}

\textbf{123456789↊↋0}

\textbf{\itshape 123456789↊↋0}

\end{document}

enter image description here

egreg
  • 1,121,712
1

Changed the argument of your \scalebox from #1 to \itfix-\kern-.4pt#1\/\itfix+\kern.4pt}.

Having earlier determined the font shape and family with \itfixcheck and \famfixcheck, I develop a kern through the macro \itfix{} based on the shape mode and font family. If the shape is not italic, the correction is 0pt. If the shape is italic, then if the family begins with an "F" (Fira), a .3pt correction is applied, otherwise (Linux Libertine) a 2.5pt correction is applied.

\documentclass{article}

\usepackage{fontspec}
\usepackage{microtype}

% Special characters for dozenal numerals

% newunicodechar and graphicx are needed to substitute and rotate the characters
\usepackage{newunicodechar}
\usepackage{graphicx}

\newcommand{\DeclareUnicodeCharacter}[2]{%
  \begingroup\lccode`|=\string"#1\relax
    \lowercase{\endgroup\newunicodechar{|}}{#2}%
}

\DeclareUnicodeCharacter{218A}{\turnedtwo}
\DeclareUnicodeCharacter{218B}{\turnedthree}

\makeatletter
\DeclareRobustCommand{\turnedtwo}{\make@turned{2}}
\DeclareRobustCommand{\turnedthree}{\make@turned{3}}
\newcommand{\make@turned}[1]{%
  \itfixcheck%
  \famfixcheck%
  \raisebox{\depth}{\scalebox{-1}[-1]{\itfix-\kern-.4pt#1\/\itfix+\kern.4pt}}%
}

\newcommand\itfixcheck{\edef\tmp{\f@shape}\expandafter\itfixaux\tmp\relax}

\def\itfixaux#1#2\relax{\ifx i#1\gdef\itfixscale{1}\else\gdef\itfixscale{0}\fi}

\newcommand\famfixcheck{\edef\tmp{\f@family}\expandafter\famfixaux\tmp\relax}

\def\famfixaux#1#2\relax{\ifx F#1\gdef\famfixdim{.3pt}\else\gdef\famfixdim{2.5pt}\fi}

\newcommand\itfix[1]{\kern#1\itfixscale\dimexpr\famfixdim\relax}
\makeatother


\setmainfont{Linux Libertine O}[
    Ligatures=TeX,
    Numbers=Uppercase,
]

\setsansfont{Fira Sans}[
    Ligatures=TeX,
    Numbers=Uppercase,
    Scale=MatchLowercase,
    BoldFont={* SemiBold},
]

\setmonofont{Fira Mono}[
    Ligatures=TeX,
    Scale=MatchLowercase,
]

\begin{document}

\Huge 

123456789↊↋0

\textit{123456789↊↋0}

\textbf{123456789↊↋0}

\textbf{\itshape 123456789↊↋0}

\sffamily 123456789↊↋0

\textit{123456789↊↋0}

\textbf{123456789↊↋0}

\textbf{\itshape 123456789↊↋0}
\end{document}

enter image description here