allsorts icon indicating copy to clipboard operation
allsorts copied to clipboard

Produce standalone fonts when subsetting

Open wezm opened this issue 4 years ago • 12 comments

2022 Update:

cmap generation when subsetting, which the original text of this issue focussed around landed in Allsorts 0.9. However, this does not get us all the way to generating standalone fonts. This issue will act as a tracking issue for things that are required to achieve that.

  • [ ] https://github.com/yeslogic/allsorts/issues/59
  • [ ] https://github.com/yeslogic/allsorts/issues/60
  • [ ] https://github.com/yeslogic/allsorts/issues/61
  • [ ] https://github.com/yeslogic/allsorts/issues/62
  • [ ] https://github.com/yeslogic/allsorts/issues/63
  • [ ] https://github.com/yeslogic/allsorts/issues/64

Original text:

The subsetting feature is currently tailored for the needs of subsetting fonts for embedding in PDFs, since that was our primary use case when developing Allsorts. The issue is that we don't include a cmap table in the subset font, which makes it invalid for use outside PDF. When a subset font is embedded in a PDF the cmap info is contained in the PDF directly, so we don't need to include it in the font.

In order to support more general subsetting it would be convenient to have an entry point that takes a list of chars and produces a font with glyphs for just those chars. This would be an incremental improvement on what we have so far and would still have some limitations: with chars as input there wouldn't be a way to include ligature glyphs. Doing so would require subsetting gpos, and gsub tables as well, which is a problem for another day.

The subsetting code lives in subset.rs. The new function signature could be along these lines:

/// Subset this font so that it only contains the glyphs for the supplied `chars`.
pub fn subset_chars(
    provider: &impl FontTableProvider,
    chars: &[char],
) -> Result<Vec<u8>, ReadWriteError>

The implementation would need to map chars to glyph ids using a technique similar to this. The subset font would need to include a new cmap table (probably using the Unicode platformID). There's a bunch of formats to chose from to encode the data. An initial implementation might just choose one of the simpler ones at the cost of size of the resulting font. A more sophisticated implementation could examine the data to determine the best option.

wezm avatar Jun 03 '20 06:06 wezm

The issue is that we don't include a cmap table in the subset font, which makes it invalid for use outside PDF.

Some PDF readers also won't work without a valid cmap, https://crbug.com/1071958 guess is needed for their text selection to work properly.

ebraminio avatar Jun 03 '20 06:06 ebraminio

Looking forward to this feature.

yisibl avatar Aug 21 '20 19:08 yisibl

I've just released 0.9, which implements building of a proper cmap table for subset fonts.

wezm avatar Mar 29 '22 05:03 wezm

@wezm Can you upgrade the dependency version in allsorts-tools?

Looks like it can be solved: https://github.com/yeslogic/allsorts-tools/issues/16

yisibl avatar Mar 29 '22 06:03 yisibl

Yes I'm working on that next. I have a draft PR open for it https://github.com/yeslogic/allsorts-tools/pull/18

wezm avatar Mar 29 '22 07:03 wezm

Reopening as we strip the OS/2 table which is required in OpenType fonts.

wezm avatar Mar 30 '22 01:03 wezm

@wezm I tried to submit a PR to fix it, PTAL. https://github.com/yeslogic/allsorts/pull/58

yisibl avatar Mar 30 '22 04:03 yisibl

Happy New Year! Any progress here?

yisibl avatar Jan 03 '23 11:01 yisibl

No, sorry it's a pretty big piece of work that has not been scheduled yet.

wezm avatar Jan 03 '23 23:01 wezm

Hey! I am also trying to use subsetting for embedded fonts in PDF documents. Since I want to avoid getting too deep into the low level PDF structure, I am just using the genpdf -> printpdf -> lopdf stack. The plan was to embed the full subsetted font into the PDF files without touching the PDF internal mappings /Differences.

I got it to work on all tested PDF readers and printers with the current implementation of subset even though the OS/2 table is missing, but only if Unicode Encoding Records are used (mappings with CharExistence::BasicMultilingualPlane, CharExistence::AstralPlane). If CharExistence::MacRoman or CharExistence::DivinePlane is used, it doesn't work.

Would it be a sensible thing to allow forcing the default mode to be Unicode or are there any problems with this?

One workaround that I think I'll be using for now is to manually add a '€' character to the glyph_ids subset so that it can't be encoded with MacRoman, but this is not the nicest solution and will be a problem if a font doesn't actually have '€'

dnlmlr avatar Mar 02 '23 19:03 dnlmlr

Would it be a sensible thing to allow forcing the default mode to be Unicode or are there any problems with this?

I don't think that would make sense as a default as it would unnecessarily inflate the font. There is already an internal CmapStrategy enum used to drive some of the cmap generation behaviour. A new variant could be added to that and then some way to select that strategy could be added.

wezm avatar Mar 06 '23 00:03 wezm

Yeah I agree that it shouldn't be default, since this is kind of an edge case. What I meant was a way to externally change the encoding mode, for example as a parameter to the subset function. Basically any mechanism that would allow to optionally prevent encoding with MacRoman.

dnlmlr avatar Mar 06 '23 11:03 dnlmlr