Search code examples
grailsflying-saucerpdfrenderer

Error Generating PDF: ITextFontResolver: java.lang.RuntimeException: Font 'Courier-BoldOblique' with 'Cp1252' is not recognized


Recently needed to make some library changes so that could use Apache POI for docx suppot. This included changing Itext versions from 2.1.0 to 4.2.1.

Also using Grails Renderer Plugin with Flying Saucer. From build.gradle:

compile 'org.xhtmlrenderer:flying-saucer-core:9.1.12'
compile 'org.xhtmlrenderer:flying-saucer-pdf:9.1.12'
compile 'org.xhtmlrenderer:flying-saucer-log4j:9.1.12'

compile ('org.grails.plugins:rendering:2.0.3') {
    exclude group: 'org.xhtmlrenderer', module: 'core-renderer'
}

compile("com.lowagie:itext:4.2.1")

When generating a PDF I get the following Exception:

java.lang.RuntimeException: Font 'Courier-BoldOblique' with 'Cp1252' is not recognized.
    at org.xhtmlrenderer.pdf.ITextFontResolver.createInitialFontMap(ITextFontResolver.java:470) ~[flying-saucer-pdf-9.1.12.jar:na]
    at org.xhtmlrenderer.pdf.ITextFontResolver.<init>(ITextFontResolver.java:40) ~[flying-saucer-pdf-9.1.12.jar:na]
    at org.xhtmlrenderer.pdf.ITextRenderer.<init>(ITextRenderer.java:124) ~[flying-saucer-pdf-9.1.12.jar:na]
    at org.xhtmlrenderer.pdf.ITextRenderer.<init>(ITextRenderer.java:110) ~[flying-saucer-pdf-9.1.12.jar:na]
    at org.xhtmlrenderer.pdf.ITextRenderer.<init>(ITextRenderer.java:106) ~[flying-saucer-pdf-9.1.12.jar:na]
    at org.xhtmlrenderer.pdf.ITextRenderer.<init>(ITextRenderer.java:102) ~[flying-saucer-pdf-9.1.12.jar:na]
Caused by: com.lowagie.text.DocumentException: Font 'Courier-BoldOblique' with 'Cp1252' is not recognized.
    at com.lowagie.text.pdf.BaseFont.createFont(BaseFont.java:696) ~[itext-4.2.1.jar:na]
    at com.lowagie.text.pdf.BaseFont.createFont(BaseFont.java:603) ~[itext-4.2.1.jar:na]
    at com.lowagie.text.pdf.BaseFont.createFont(BaseFont.java:438) ~[itext-4.2.1.jar:na]
    at org.xhtmlrenderer.pdf.ITextFontResolver.createFont(ITextFontResolver.java:483) ~[flying-saucer-pdf-9.1.12.jar:na]
    at org.xhtmlrenderer.pdf.ITextFontResolver.createFont(ITextFontResolver.java:479) ~[flying-saucer-pdf-9.1.12.jar:na]
    at org.xhtmlrenderer.pdf.ITextFontResolver.addCourier(ITextFontResolver.java:491) ~[flying-saucer-pdf-9.1.12.jar:na]
    at org.xhtmlrenderer.pdf.ITextFontResolver.createInitialFontMap(ITextFontResolver.java:459) ~[flying-saucer-pdf-9.1.12.jar:na]

In looking at the code, the above exception happens from my code from

  ITextRenderer theRenderer = new ITextRenderer()

My code is running in a war deployed on Tomcat. I can see the font files (like Courier-BoldOblique.afm, but they are in the jar itext-4.2.1.jar in /com/lowagie/text/pdf/fonts.

How do I get the code to find the fonts correctly, so that the creation of ITextRenderer succeeeds?


Solution

  • Found the problem:

    • The fonts are initialized in com.lowagie.text.pdf.BaseFont in a static initializer into local variable BuiltinFonts14
    • However in fr.opensagres.xdocreport.itext.extension.font.AbstractFontRegistry in inner-class ExtendedBaseFont there is a method clearBuiltinFonts that is clearing the initialized BuiltinFonts14

    Therefore the (ugly) solution is as follows:

    Create a class:

    public abstract class FixBaseFont extends BaseFont {
    
        public static void fixBuiltinFonts() {
    
            if (BuiltinFonts14.size() != 14) {
                BuiltinFonts14.clear();
    
                BuiltinFonts14.put(COURIER, PdfName.COURIER);
                BuiltinFonts14.put(COURIER_BOLD, PdfName.COURIER_BOLD);
                BuiltinFonts14.put(COURIER_BOLDOBLIQUE, PdfName.COURIER_BOLDOBLIQUE);
                BuiltinFonts14.put(COURIER_OBLIQUE, PdfName.COURIER_OBLIQUE);
                BuiltinFonts14.put(HELVETICA, PdfName.HELVETICA);
                BuiltinFonts14.put(HELVETICA_BOLD, PdfName.HELVETICA_BOLD);
                BuiltinFonts14.put(HELVETICA_BOLDOBLIQUE, PdfName.HELVETICA_BOLDOBLIQUE);
                BuiltinFonts14.put(HELVETICA_OBLIQUE, PdfName.HELVETICA_OBLIQUE);
                BuiltinFonts14.put(SYMBOL, PdfName.SYMBOL);
                BuiltinFonts14.put(TIMES_ROMAN, PdfName.TIMES_ROMAN);
                BuiltinFonts14.put(TIMES_BOLD, PdfName.TIMES_BOLD);
                BuiltinFonts14.put(TIMES_BOLDITALIC, PdfName.TIMES_BOLDITALIC);
                BuiltinFonts14.put(TIMES_ITALIC, PdfName.TIMES_ITALIC);
                BuiltinFonts14.put(ZAPFDINGBATS, PdfName.ZAPFDINGBATS);
            }
        }
    }
    

    And then every time add a call to this class before initializing ITextRenderer

    FixBaseFont.fixBuiltinFonts()
    ITextRenderer renderer = new ITextRenderer()