[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Real numbers in AFM kerning information?



To Thomas Wu:

Here is, as I wrote yesterday, a modified AFM to MTX conversion part of
fontinst.dtx that can handle real numbers. The easiest way to use it is to
replace its to replace its normal counterpart in fontinst.dtx with this and
run fontinst.ins. You'd better see to that non-modified and modified
versions get different names so that you know what is what (besides, it is
considered good style).

To Ulrik Vieth:

Here I go again, rewriting a part of fontinst. The main new feature is of
course that it can now handle reals in AFMs. To be on the safe side, all
numbers except character codes are read as reals (and all reals except the
italic angle, which is handled as before, are rounded to integers by a new
macro \afm_length). Perhaps this is overkill but AFM to MTX conversion
hardly takes any time anyway.

Apart from that, I corrected a typo in the definition of CharWidth (it said
\charxwidth, but should be \char_x_width) and made the computation of
italic correction customizable (new feature, see the description of
\italcorr_expression below).


Lars Hellström

The code:

% \subsection{Converting an \texttt{AFM} file to an \texttt{MTX} file}
%
% \DescribeMacro{\afmtomtx}
% The macro:
% \begin{quote}
%    |\afmtomtx{AFMFILE}{MTXFILE}|
% \end{quote}
% reads |AFMFILE.afm|, and writes the same information out to |MTXFILE.mtx|.
%
% \begin{macro}{\afmtomtx}
%    \begin{macrocode}
\def\afmtomtx#1#2{{
   \open_out{\temp_prefix#2.mtx}
   \def\raw_font_name{#2}
   \font_italic=0
   \let\italcorr_expression=\uprightitalcorr
   \setint{minimumkern}{0}
   \minimum_kern=\int{minimumkern}
   \out_line{\percent_char~Filename:~#2.mtx}
   \out_line{\percent_char~Created~by:~tex~\jobname}
   \out_line{\percent_char~Created~using:~\string\afmtomtx{#1}{#2}}
   \out_line{}
   \out_line{\percent_char~This~file~contains~the
      information~of~#1.afm~in~a~form}
   \out_line{\percent_char~more~easily~read~by~TeX.~
      It~is~used~by~the~fontinst~package.}
   \out_line{}
   \out_line{\percent_char~THIS~FILE~CAN~BE~DELETED.}
   \out_line{}
   \out_line{\string\relax}
   \out_line{\string\metrics}
   \out_line{}
   \out_line{\string\needsfontinstversion{\fontinstversion}}
   \out_line{}
   \catcode`\^^M=12
   \catcode`\ =10
   \expandafter\afm_line\primitiveinput #1.afm\relax
   \out_line{}
   \out_line{\string\endmetrics}
   \close_out{Metrics}
}}
%    \end{macrocode}
% \end{macro}
%
% Kerns below this value are ignored.
%
%    \begin{macrocode}
\newcount\minimum_kern
%    \end{macrocode}
%
%
% \begin{macro}{\afm_length}
% \begin{macro}{\afm_unit_dimen}
%   LH 1998/12/28: The call |\afm_length|\meta{count}\marg{real}
%   interprets the \meta{real} as a real number, rounds it to the
%   nearest integer, and sets the \meta{count} (a |\count| register)
%   to that integer. In this process, |\a_dimen| is used as a temporary
%   storage.
%    \begin{macrocode}
\def\afm_length#1#2{
   \a_dimen=#2\afm_unit_dimen
   #1=\a_dimen
   \divide #1 by \afm_unit_dimen
   \advance \a_dimen by -#1\afm_unit_dimen
   \ifdim \a_dimen>0.5\afm_unit_dimen
      \advance #1 by 1
   \else \ifdim \a_dimen<-0.5\afm_unit_dimen
      \advance #1 by -1
   \fi\fi
   \relax
}
%    \end{macrocode}
%   The dimen |\afm_unit_dimen| is used to keep track of how long an AFM
%   unit is interpreted as being in this routine. Lowering its value
%   makes |\afm_length| capable of handling greater lengths but looses
%   some very slight precision in the rounding, increasing the value
%   has the opposite effects. The current value of 1000\thinspace sp
%   means it reads lengths with three decimals accuracy (not very much
%   use for them though as the number is rounded to zero decimals
%   accuracy anyway, but it does make a difference when deciding how
%   a \meta{real} like |0.502| should be rounded) and can handle lengths
%   of an absolute value of a good million AFM units. This should be
%   adequate in most cases. It is, by the way, probably wisest to keep
%   it a power of ten scaled points in all cases, as this should reduce
%   the rounding errors caused by various base conversions.
%    \begin{macrocode}
\newdimen\afm_unit_dimen
\afm_unit_dimen=1000sp
%    \end{macrocode}
% \end{macro}\end{macro}
%
%
% The command |\afm_line| reads to the end of the line, calls
% |\afm_command| on that line, then calls |\afm_line| again.
%
%    \begin{macrocode}
{\catcode`\^^M=12 \gdef\afm_line#1
{\afm_command#1~\end_of_line\afm_line}}
%    \end{macrocode}
%
% The command |\afm_command| reads the first word |FOO|, and calls
% |afm-FOO|.  If this does not exist, then |\gobble_one_line| will
% eat up the rest of the line.
%
%    \begin{macrocode}
\def\afm_command#1~{\csname~afm-#1\endcsname\gobble_one_line}
\def\gobble_one_line#1\end_of_line{}
%    \end{macrocode}
%
% This all stops when we reach the command |EndFontMetrics|.
%
%    \begin{macrocode}
\x_cs\def{afm-EndFontMetrics}#1\afm_line{\endinput}
%    \end{macrocode}
%
% \begin{macro}{\afm_def}
%   To define an AFM command, you say |\afm_def{|\meta{command}|}(|^^A
%   \meta{pattern}|){|\meta{result}|}|
%   \begin{macrocode}
\def\afm_def#1(#2)#3{\x_cs\def{afm-#1}
   \gobble_one_line#2\end_of_line{#3}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\afm_let}
%   Saying |\afm_let|\marg{dest-command}\marg{source-command} copies
%   the definition of one AFM command to another.
%    \begin{macrocode}
\def\afm_let#1#2{
   \expandafter\let \csname afm-#1\expandafter\endcsname
      \csname afm-#2\endcsname
}
%    \end{macrocode}
% \end{macro}
%
% For example, we can define the following AFM commands:
% (Fixed by Thierry Bouche |<Thierry.Bouche@ujf-grenoble.fr>|
% 1997/02/07, to get fontdimens comparable to EC fonts.)
%
%    \begin{macrocode}
\afm_def{CharWidth}(#1){\afm_length\char_x_width{#1}}
\afm_def{ItalicAngle}(#1){\calculate_it_slant{#1}}
\afm_def{XHeight}(#1){
   \afm_length\a_count{#1}
   \out_line{\string\setint{xheight}{\the\a_count}}}
\afm_def{CapHeight}(#1){
   \afm_length\a_count{#1}
   \out_line{\string\setint{capheight}{\the\a_count}}}
\afm_def{Ascender}(#1){
   \afm_length\a_count{#1}
   \out_line{\string\setint{ascender}{\the\a_count}}}
\afm_def{Descender}(#1){
   \afm_length\a_count{#1}
   \out_line{\string\setint{descender_neg}{\the\a_count}}}
\afm_def{UnderlineThickness}(#1){
   \afm_length\a_count{#1}
   \out_line{\string\setint{underlinethickness}{\the\a_count}}}
\afm_def{FontBBox}(#1~#2~#3~#4){
   \afm_length\a_count{#4}
   \out_line{\string\setint{maxheight}{\the\a_count}}
   \afm_length\a_count{#2}
   \out_line{\string\setint{maxdepth_neg}{\the\a_count}}}
\afm_def{IsFixedPitch}(#1){
   \if\first_char#1=f
   \else\out_line{\string\setint{monowidth}{1}}
   \fi
}
%    \end{macrocode}
%
% Processing kern pairs.  If one of the glyph name starts with
% a dot as in |.notdef| or |.null| the kern pair is ignored.
%
%    \begin{macrocode}
\afm_def{KP}(#1~#2~#3~#4){
   \if\first_char#1=.\else
   \if\first_char#2=.\else
      \afm_length\a_count{#3}
      \ifnum \a_count>\minimum_kern
         \out_line{\string\setkern{#1}{#2}{\the\a_count}}
      \else\ifnum \a_count<-\minimum_kern
         \out_line{\string\setkern{#1}{#2}{\the\a_count}}
      \fi\fi
   \fi\fi
}
\afm_let{KPX}{KP}
%    \end{macrocode}
%
% Processing char metrics.
%
%    \begin{macrocode}
\afm_def{C}(#1~;#2){\init_afm{#1}\do_list[#2]\afm_char}
\afm_let{CH}{C}
%    \end{macrocode}
%
% Processing composite chars.
%
%    \begin{macrocode}
\afm_def{CC}(#1~#2~;#3){\init_cc{#1}\do_list[#3]\cc_char}
%    \end{macrocode}
%
% When parsing a character, we set the values of the following
% variables:
%
%    \begin{macrocode}
\newcount\char_slot
\newcount\char_x_width
\newcount\x_width
\newcount\bbox_llx
\newcount\bbox_lly
\newcount\bbox_urx
\newcount\bbox_ury
\newcount\font_italic
\let\char_name=\empty_command
%    \end{macrocode}
%
% |\init_afm| initializes the variables the AFM character list writes to.
%
%    \begin{macrocode}
\def\init_afm#1{
   \char_slot=#1\relax
   \x_width=\char_x_width
   \bbox_llx=0
   \bbox_lly=0
   \bbox_urx=0
   \bbox_ury=0
   \let\char_name=\empty_command
}
%    \end{macrocode}
%
% |\afm_char| writes the values of these variables to the |.mtx| file,
%  and saves them in a macro |\g-GLYPHNAME|, in the form:
% \begin{quote}
%    |{WIDTH}{HEIGHT}{DEPTH}{ITALIC}|
% \end{quote}
%
% These are needed, because the (grumble grumble) syntax of |CC| commands
% doesn't include the glyph measurements, so we have to remember them.
%
%    \begin{macrocode}
\def\afm_char{
   \a_count=-\bbox_lly
   \eval_expr{\italcorr_expression\x_width\bbox_llx\bbox_urx
      \bbox_lly\bbox_ury\font_italic}
   \out_line{
      \ifnum -1<\char_slot
         \string\setrawglyph
      \else
         \string\setnotglyph
      \fi
      {\char_name}
      {\raw_font_name}
      {10pt}
      {\the\char_slot}
      {\the\x_width}
      {\the\bbox_ury}
      {\the\a_count}
      {\the\result}
   }
}
%    \end{macrocode}
%
% |\init_cc| and |\cc_char| write out a composite character glyph.
%
%    \begin{macrocode}
\def\init_cc#1{%
   \out_line{\string\setglyph{#1}}
   \def\char_name{#1}
}
\def\cc_char{%
   \out_lline{\string\samesize{\char_name-not}}
   \out_line{\string\endsetglyph}
}
%    \end{macrocode}
%
%
%
% \DescribeMacro{\italcorr_expression}
% LH 1998/12/28: I've changed the way the italic correction is
% computed quite a bit, although the computed values are normally
% still the same. The point is that it is much simpler to modify the
% formula according to which the value is computed using this method
% than using the previous method.
%
% The call
% \begin{quote}
%   |\italcorr_expression|\marg{width}\marg{left}^^A
%   \marg{right}\marg{bottom}\marg{top}\marg{slant},
% \end{quote}
% where the arguments are \TeX\ \meta{number}s, should expand to an
% integer expression. The value of that expression will be taken as the
% italic correction of the current character.
%
% \meta{width} is the width of the character. \meta{left},
% \meta{right}, \meta{bottom}, and \meta{top} are the respective
% coordinates of the sides of the bounding box of the character.
% \meta{slant} is the italic slant of the font as a whole, as computed
% from the |ItalicAngle| of the font; the MTX file written will set
% the integer \texttt{italicslant} to this value.
%
% \begin{macro}{\uprightitalcorr}
% \begin{macro}{\slanteditalcorr}
%   These two commands are what |\italcorr_expression| will get set
%   to---the italic version is used if the italic slant is positive and
%   the upright version is used otherwise. The default definitions
%   compute the same values as in fontinst v1.8, but the definitions
%   can easily be modified using |\resetcommand|.
%    \begin{macrocode}
\def\uprightitalcorr#1#2#3#4#5#6{0}
\def\slanteditalcorr#1#2#3#4#5#6{\max{\sub{#3}{#1}}{0}}
%    \end{macrocode}
% \end{macro}\end{macro}
%
%
% To set the italic angle, we need to calculate the tangent of the
% angle that the |.afm| file contains.  This is done with David
% Carlisle's \texttt{trig} macros.  We need to do a bit of trickery to
% strip off any spaces which may have crept into the end of the angle,
% since the trig macros don't like space at the end of their argument.
%
%    \begin{macrocode}
\def\calculate_it_slant#1{
   \edef\theangle{\strip_spaces#1~\end_strip_spaces}
   \CalculateTan{\theangle}
   \a_dimen=-\one_thousand sp
   \a_dimen=\UseTan{\theangle}\a_dimen
   \font_italic=\a_dimen
   \out_line{\string\setint{italicslant}{\the\font_italic}}
   \ifnum 0<\font_italic
      \let\italcorr_expression=\slanteditalcorr
   \else
      \let\italcorr_expression=\uprightitalcorr
   \fi
}
%    \end{macrocode}
%    \begin{macrocode}
\def\strip_spaces#1~#2\end_strip_spaces{#1}
%    \end{macrocode}
%
% To process a list of commands separated by semi-colons, we call
% |\do_list[LIST]|.  This works in a similar way to |\afm_line|.
%
%    \begin{macrocode}
\def\do_list[~#1~#2;~#3]{
   \csname~list-#1\endcsname\gobble_one_semi#2;
   \ifx\relax#3\relax\expandafter\gobble_one
   \else\expandafter\identity_one\fi
   {\do_list[~#3]}
}
\def\gobble_one_semi#1;{}
%    \end{macrocode}
%
% There is an analagous |\list_def| for defining commands to be used
% inside lists.
%
%    \begin{macrocode}
\def\list_def#1(#2)#3{\x_cs\def{list-#1}\gobble_one_semi#2~;{#3}}
%    \end{macrocode}
%
% For example, these are the commands that are used in giving
% character metrics:
%
%    \begin{macrocode}
\list_def{W}(#1~#2){\afm_length\x_width{#1}}
\list_def{WX}(#1){\afm_length\x_width{#1}}
\list_def{WY}(#1){}
\list_def{N}(#1){\def\char_name{#1}}
\list_def{B}(#1~#2~#3~#4){
   \afm_length\bbox_llx{#1}
   \afm_length\bbox_lly{#2}
   \afm_length\bbox_urx{#3}
   \afm_length\bbox_ury{#4}
}
\list_def{PCC}(#1~#2~#3){
   \afm_length\a_count{#2}
   \afm_length\b_count{#3}
   \out_lline{\string\glyphpcc{#1}{\the\a_count}{\the\b_count}}
}
%    \end{macrocode}
%
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%