Page 1 of 1

Embedding Font IBM Plex Sans with Styles (Bold/Italic) fails

PostPosted: Fri Dec 04, 2020 12:50 am
by peter
Embedding Font IBM Plex Sans with Styles (Bold/Italic) fails

Hello everyone,

I want to embed the font IBM Plex Sans (can get it here https://fonts.google.com/specimen/IBM+Plex+Sans) in my document. Target output is DOCX and PDF. Everything works fine as long as I use the 'Normal' style. PDF and DOCX looks great on all devices. When I start to use font styles like Bold or Italic then things are beginning to escalate.

First approach: I tried to use IBM Plex Sans and added the Bold marker to my example document (is attached below, but be aware that font is not embedded because of 2 MB restriction in this board). When I try to read the docx file and to render it, then I get the following exception.

Code: Select all
Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: Exception writing Document to OutputStream: Failed to read font file file:C:/Users/peter.schrader/.docx4all/temporary%20embedded%20fonts/1607000027719-IBM%20Plex%20Sans-bold.ttf
   at org.docx4j.utils.XmlSerializerUtil.serialize(XmlSerializerUtil.java:56)
   at org.docx4j.utils.XmlSerializerUtil.serialize(XmlSerializerUtil.java:18)
   at org.docx4j.convert.out.fo.renderers.FORendererApacheFOP.render(FORendererApacheFOP.java:247)
   at org.docx4j.convert.out.fo.renderers.FORendererApacheFOP.render(FORendererApacheFOP.java:181)
   at org.docx4j.convert.out.fo.AbstractFOExporter.postprocess(AbstractFOExporter.java:168)
   at org.docx4j.convert.out.fo.AbstractFOExporter.postprocess(AbstractFOExporter.java:47)
   at org.docx4j.convert.out.common.AbstractExporter.export(AbstractExporter.java:81)
   ... 57 common frames omitted
Caused by: java.lang.RuntimeException: Failed to read font file file:C:/Users/peter.schrader/.docx4all/temporary%20embedded%20fonts/1607000027719-IBM%20Plex%20Sans-bold.ttf
   at org.apache.fop.fonts.LazyFont.load(LazyFont.java:132)
   at org.apache.fop.fonts.LazyFont.hasChar(LazyFont.java:179)
   at org.apache.fop.fonts.Font.hasChar(Font.java:278)
   at org.apache.fop.fonts.FontSelector.selectFontForCharacter(FontSelector.java:47)
   at org.apache.fop.fonts.FontSelector.selectFontForCharacterInText(FontSelector.java:85)
   at org.apache.fop.layoutmgr.inline.TextLayoutManager.initialize(TextLayoutManager.java:162)
   at org.apache.fop.layoutmgr.AbstractLayoutManager.getChildLM(AbstractLayoutManager.java:118)
   at org.apache.fop.layoutmgr.BreakOpportunityHelper.getBreakBefore(BreakOpportunityHelper.java:45)
   at org.apache.fop.layoutmgr.inline.InlineStackingLayoutManager.getBreakBefore(InlineStackingLayoutManager.java:392)
   at org.apache.fop.layoutmgr.BreakOpportunityHelper.getBreakBefore(BreakOpportunityHelper.java:49)
   at org.apache.fop.layoutmgr.inline.InlineStackingLayoutManager.getBreakBefore(InlineStackingLayoutManager.java:392)
   at org.apache.fop.layoutmgr.BreakOpportunityHelper.getBreakBefore(BreakOpportunityHelper.java:49)
   at org.apache.fop.layoutmgr.inline.InlineStackingLayoutManager.getBreakBefore(InlineStackingLayoutManager.java:392)
   at org.apache.fop.layoutmgr.BreakOpportunityHelper.getBreakBefore(BreakOpportunityHelper.java:49)
   at org.apache.fop.layoutmgr.BlockStackingLayoutManager.getBreakBefore(BlockStackingLayoutManager.java:1071)
   at org.apache.fop.layoutmgr.BlockStackingLayoutManager.addKnuthElementsForBreakBefore(BlockStackingLayoutManager.java:1049)
   at org.apache.fop.layoutmgr.BlockStackingLayoutManager.breakBeforeServed(BlockStackingLayoutManager.java:447)
   at org.apache.fop.layoutmgr.BlockStackingLayoutManager.getNextKnuthElements(BlockStackingLayoutManager.java:257)
   at org.apache.fop.layoutmgr.BlockLayoutManager.getNextKnuthElements(BlockLayoutManager.java:113)
   at org.apache.fop.layoutmgr.BlockLayoutManager.getNextKnuthElements(BlockLayoutManager.java:105)
   at org.apache.fop.layoutmgr.FlowLayoutManager.getNextChildElements(FlowLayoutManager.java:223)
   at org.apache.fop.layoutmgr.FlowLayoutManager.addChildElements(FlowLayoutManager.java:148)
   at org.apache.fop.layoutmgr.FlowLayoutManager.getNextKnuthElements(FlowLayoutManager.java:116)
   at org.apache.fop.layoutmgr.FlowLayoutManager.getNextKnuthElements(FlowLayoutManager.java:69)
   at org.apache.fop.layoutmgr.PageBreaker.getNextKnuthElements(PageBreaker.java:251)
   at org.apache.fop.layoutmgr.AbstractBreaker.getNextBlockList(AbstractBreaker.java:675)
   at org.apache.fop.layoutmgr.PageBreaker.getNextBlockList(PageBreaker.java:178)
   at org.apache.fop.layoutmgr.PageBreaker.getNextBlockList(PageBreaker.java:158)
   at org.apache.fop.layoutmgr.AbstractBreaker.doLayout(AbstractBreaker.java:385)
   at org.apache.fop.layoutmgr.PageBreaker.doLayout(PageBreaker.java:112)
   at org.apache.fop.layoutmgr.PageSequenceLayoutManager.activateLayout(PageSequenceLayoutManager.java:143)
   at org.apache.fop.area.AreaTreeHandler.endPageSequence(AreaTreeHandler.java:267)
   at org.apache.fop.fo.pagination.PageSequence.endOfNode(PageSequence.java:139)
   at org.apache.fop.fo.FOTreeBuilder$MainFOHandler.endElement(FOTreeBuilder.java:362)
   at org.apache.fop.fo.FOTreeBuilder.endElement(FOTreeBuilder.java:190)
   at org.docx4j.org.apache.xalan.transformer.TransformerIdentityImpl.endElement(TransformerIdentityImpl.java:1148)
   at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:610)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1718)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2883)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
   at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:534)
   at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
   at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
   at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
   at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1216)
   at org.docx4j.org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:518)
   at org.docx4j.utils.XmlSerializerUtil.serialize(XmlSerializerUtil.java:51)
   ... 63 common frames omitted
Caused by: java.io.FileNotFoundException: C:\Users\peter.schrader\.docx4all\temporary embedded fonts\1607000027719-IBM Plex Sans-bold.ttf (Das System kann die angegebene Datei nicht finden)
   at java.base/java.io.FileInputStream.open0(Native Method)
   at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
   at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
   at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
   at java.base/sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:86)
   at java.base/sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:184)
   at java.base/java.net.URL.openStream(URL.java:1140)
   at org.apache.fop.apps.io.ResourceResolverFactory$NormalResourceResolver.getResource(ResourceResolverFactory.java:224)
   at org.apache.fop.apps.io.ResourceResolverFactory$TempAwareResourceResolver.getResource(ResourceResolverFactory.java:152)
   at org.apache.fop.apps.io.ResourceResolverFactory$DefaultResourceResolver.getResource(ResourceResolverFactory.java:121)
   at org.apache.fop.apps.io.InternalResourceResolver.getResource(InternalResourceResolver.java:92)
   at org.apache.fop.fonts.truetype.OFFontLoader.read(OFFontLoader.java:111)
   at org.apache.fop.fonts.truetype.OFFontLoader.read(OFFontLoader.java:101)
   at org.apache.fop.fonts.FontLoader.getFont(FontLoader.java:126)
   at org.apache.fop.fonts.FontLoader.loadFont(FontLoader.java:110)
   at org.apache.fop.fonts.LazyFont.load(LazyFont.java:119)
   ... 110 common frames omitted


When I trick the code and recover the deleted fonts immediately then the rendering runs through, but when I open the PDF file in Adobe then I get another error message and only dots are displayed where normal characters should appear (this is also attached):

Cannot find or create the font 'EAAAAA+IBMPlexSans-Bold'. Some characters may not display or print correctly.


Second Approach: Instead of using 'IBM Plex Sans' + Bold Style I use the font 'IBM Plex Sans Bold'. No errors or exceptions appear, but when I open the generated DOCX(!) file on another system (were IBM Plex Sans Bold is not installed) then the font is not used (although the file size of an almost empty DOCX with 4 MB indicates that all IBM Plex Sans Fonts are most likely embedded). The characters are simply rendered in another font. In the PDF file it seems to be displayed correctly. Sadly, I cannot force users to install IBM Plex Sans before they open my generated documents, so using 'IBM Plex Sans Bold' is not a choice.

Conclusion: So... I don't have any other ideas how to solve this now. To avoid Bold/Italic in general is not a really sustainable solution. When I try the same stuff with Calibri+Bold or Calibri Bold everything is fine. There are maybe specifics in IBM Plex Sans that causes that error, but I cannot see them or it would be guessing game for me (for example 'IBM Plex Sans' has spaces inside and 'Calibri' not, but can this really cause such a problem?!).

Please help my, thank you!

Re: Embedding Font IBM Plex Sans with Styles (Bold/Italic) f

PostPosted: Mon Dec 07, 2020 11:57 am
by jason
Hi Peter, I just wrote a long post but lost it when I pressed the preview button. Grrr...

In summary.

If you use 8.2.6 (releasing today), embedded fonts should work for the +Bold case. The Bold font doesn't work, because for some reason it generates an incorrect entry in the fop config.xml. So do +Bold instead. This should be a workable solution for you, right?

Incorrect:

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
        <font
                embed-url="file:/home/jharrop/.docx4all/temporary embedded fonts/1607302268477-IBM Plex Sans-bold.ttf">
                <font-triplet name="IBM Plex Sans" style="normal"
                        weight="bold" />
        </font>
 
Parsed in 0.000 seconds, using GeSHi 1.0.8.4


compared to:

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
                                <font
                                        embed-url="file:/usr/share/fonts/TTF/IBM_Plex_Sans/IBMPlexSans-Bold.ttf">
                                        <font-triplet name="IBM Plex Sans Bold" style="normal"
                                                weight="normal" />
                                </font>
 
Parsed in 0.000 seconds, using GeSHi 1.0.8.4


For completeness, if you were to install the font locally, then in the PDF output, its the actual Bold font which works correctly (generated above config). To get +Bold working (for other people reading this post), you can either use an entry in fop-substitutions.xml:

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
      <substitution>
        <from font-family="IBM Plex Sans" font-weight="700..900"/>
        <to font-family="IBM Plex Sans Bold"/>
      </substitution>
 
Parsed in 0.000 seconds, using GeSHi 1.0.8.4


(remember to enable it in docx4j.properties)

or craft an entry in MicrosoftFonts.xml (not so convenient, since its embedded in docx4j-core.jar)