Converting Proportional to Fixed-Width

ClintGoss
ClintGoss Posts: 66
edited August 2019 in Font Technology
I'm programmatically converting (in perl with Font::TTF) a proportional font to "fixed-width" and wrestling with nested composite glyphs. Straightforward approach seems horrendously complex, and I'm wondering if there is a simpler approach that I am missing ...
Adjusting of simple glyphs is straightforward: reset AdvanceWidth and, if needed, shift glyph points in the X axis. However ...
If a simple glyph is a component in another composite glyph, the attachment points are now incorrect since the component may be X-shifted. The attachment points have to be adjusted to account for the X-shift.
Furthermore, composite glyphs can be arbitrarily nested, so some kind of iterative strategy seems to be needed. No composite glyph can be processed until all it's components have been processed ... i.e. starting with all simple glyphs then composite glyphs that only have simple glyphs as components, then working your way up the dependency tree of composite glyphs. At each stage, a structure is needed to remember how much each component has been re-positioned.
Things get (much) more thorny if I want to scale some wider glyphs in the X direction to fit the fixed-width bounding box, such as is done by the Python-based monospacifier tool (https://github.com/cpitclaudel/monospacifier ... which I can't actually run)
Is there a simpler strategy to what I'm trying to do?
I could (groan) flatten composites into simple glyphs, but that seems heavy-handed.
FYI, I can't just set the OS2.isFixedPitch and let (hope) the rendering engine forces everything to monospace, since the font does use 3 widths: 1× wide (eg. Latin), 2× wide for most Asian 'fullwidth', and 0 wide for appopriate code points, so not strictly monospaced.
Any thoughts / ideas appreciated!
Tagged:

Comments

  • Kent Lew
    Kent Lew Posts: 944
    Would it help simplify things to first run a routine that would un-nest any nested composites? If a glyph contains a component reference to a glyph that is in turn a composite, then recalculate the reference and change it to direct references to the outline components.
    Then you can run a first adjustment on glyphs that are outline only and build a dictionary storing those outline adjustment amounts for each as you go.
    Then a second routine adjusts all the glyphs that contain components and gets a value from the dictionary to compensate any component reference shift accordingly.
    Off the top of my head, and without thinking it through carefully, it seems to me that might handle everything adequately (setting aside the question of any scaling).
  • Yes. That helps ... 
    And, BTW, scaling is a nightmare, because component glyphs need to scale differently depending on the total size of the parent composite, which implies duplicating component simple glyphs to serve different parent composite glyphs. Sigh.
  • Just out of curiousity why would you need/want to do this?
  • I am expanding several fixed-width OFL fonts with scripts that I am pulling from other glyph-compatible** open-source fonts. The result will be fonts that are "duowidth" (a term I derived from discussions of "duospaced" fonts on this forum). The added scripts come from proportional fonts that could (hopefully) reasonably be auto-converted to fixed width.

    I'm doing this in a hybrid Perl / Python / Excel / OtherBitsAndPieces pipeline, so all this FixedWidth-ifier needs to be programmatic ...

    ** "glyph-compatible" is my term ... I have not seen a better one in use. I say that a license, A, is “glyph-compatible” with license B if both licenses allow code and data (typically glyph data) to be extracted from a font released under A and incorporated into a font released under B.
  • John Savard
    John Savard Posts: 1,135
    edited August 2019
    I'll have to admit that the same question came to my mind. And I'm still puzzled. I understand that your intent is to create a composite font that has greater language coverage. However, making a proportional typeface monospaced, and still having it look tolerable, is a difficult thing even for a human type designer to do. Attempting to have a computer do it... it appears that under any conceivable scenario, you would be better off using an existing font with wide language coverage, even if its quality were only mediocre.
    I mean, no doubt you could accomplish a reasonable result, if you had the entire resources of a firm like Monotype - or, better yet, Google (Alphabet) - under your command. If you are trying to program this yourself, I would strenuously warn you against an almost certain waste of time and effort. And the other thing, of course, is why the typefaces have to be made monospaced in order to be combined in a single font?
  • Thank you for your considered advice, John.
  • John Savard
    John Savard Posts: 1,135
    edited August 2019
    ClintGoss said:
    Thank you for your considered advice, John.
    I'm sorry to be so negative, and maybe from the efforts you've already made, you have some reason to find that I'm mistaken. I felt qualified to comment partly because I have more experience with computers and their programming than I have with type.
    As I see it, the first basic capability you would have to achieve in order to do this would be to convert a font from Bezier outlines to strokes of varying widths - as in the Metafont format. Then you could scale a letter's width without making its strokes thinner (if that didn't make them too crowded). A TrueType to Metafont converter, though, is already something beyond the current state of the art to my knowledge.
  • No question that simple horizontal scaling to get to the correct widths would produce a huge mess, that anyone who designs typefaces would consider unacceptable. John Savard correctly implies the problem: you want to maintain the thickness of vertical and diagonal “strokes” while scaling.

    I disagree that converting to an actual stroke-based format is the necessary/only route to do this.

    That said, in any case, the interest in automating such a process has been around for decades, and experienced programmers who also know fonts have not yet done it. There have been ways it could have been done... for example, the folks who made FontChameleon could easily have extended it to do this. But understand that said system required a human to manually turn a font into a "Chameleon" font descriptor, prior to doing any such thing. I am just saying that given the tech as it existed, they could have added an instant-monospace feature in a day, and it would have worked with all their existing font descriptors.

    But not with a bunch of arbitrary, existing open source fonts. That capability we do not have, and can’t be reasonably programmed in a day, a week, or a month. Nor probably even a year.

    You could write a program to take a variable font with a width axis and spit out a monospaced font, though. That would be cool, and totally plausible. Somebody should do that.  :)  But it wouldn’t work with non–variable-font sources.
  • John Savard
    John Savard Posts: 1,135
    I disagree that converting to an actual stroke-based format is the necessary/only route to do this.

    Oh, that's true. I didn't really make that claim, although I was (in effect) making the weaker claim that if you could do this kind of scaling, the same basic tech could also be used to convert to a stroke based format as well, which might potentially be more useful to more people.
  • Craig Eliason
    Craig Eliason Posts: 1,440
    You could write a program to take a variable font with a width axis and spit out a monospaced font, though. That would be cool, and totally plausible. Somebody should do that.  :)  But it wouldn’t work with non–variable-font sources.
    Even then, it’s not like the /i at the expanded end of the axis is likely to have a similar advance width to the /W at the condensed end. 
  • Thomas Phinney
    Thomas Phinney Posts: 2,896
    edited August 2019
    You could write a program to take a variable font with a width axis and spit out a monospaced font, though. That would be cool, and totally plausible. Somebody should do that.  :)  But it wouldn’t work with non–variable-font sources.
    Even then, it’s not like the /i at the expanded end of the axis is likely to have a similar advance width to the /W at the condensed end. 
    Agreed! For each glyph, the program would adjust the width axis as much as possible to get to the right width, and then make up any difference by adjusting the sidebearings.

    That would be fine for cases where the glyph doesn't get wide enough. What you want the app to do when the glyph doesn't get narrow enough (let's say, cap M for example) is more... interesting. Sidebearings can only do so much. So in that case, you probably say that you can't get rid of more than half of each sidebearing.

    Then what? Either:
    1. the remainder is done by squishing the glyph horizontally. Which sounds awful, but when I look at the M in a typical monospace, there is some of that going on.

    2. or you flag the glyph to a list, for later human intervention.

    At the end of the day, would still benefit from human intervention, but automation could get you most of the way there. IF you already have a weight axis, which is... not entirely trivial.