Search code examples
flying-saucer

Using custom font with flying saucer gives corrupt PDF


I have a working PDF generated with Flying Saucer. When I now however want to add custom fonts, the generated PDF becomes corrupt. Instead of downloading the file, the browser shows all kind of weird symbols.

The custom font was added by adding the ttf font files on the classpath and calling addFont:

            renderer.getFontResolver().addFont("/fonts/Montserrat-Regular.ttf", BaseFont.IDENTITY_H, true);
            renderer.getFontResolver().addFont("/fonts/Montserrat-Italic.ttf", BaseFont.IDENTITY_H, true);
            renderer.getFontResolver().addFont("/fonts/Montserrat-Bold.ttf", BaseFont.IDENTITY_H, true);
            renderer.getFontResolver().addFont("/fonts/Montserrat-BoldItalic.ttf", BaseFont.IDENTITY_H, true);

And specifying the font in CSS:

html {
  font-family: 'Montserrat', sans-serif;
  font-size: 14px;
}

Solution

  • The problem was due to the response header being set after the PDF was generated into the outputstream of the response.

    My controller was something like this:

        @GetMapping("/{id}/download-pdf")
        @Secured(Roles.ADMIN)
        public void downloadPDFResource(@PathVariable("id") EntityId entityId,
                                        HttpServletRequest request, HttpServletResponse response,
                                        Locale locale) throws IOException {
            byte[] pdf = pdfService.generatePdf("details-pdf", context);
            response.getOutputStream().write(pdf);
            response.setContentType("application/pdf");
            response.addHeader("Content-Disposition",
                               "attachment; filename=" + "document.pdf");
    
            response.getOutputStream().flush();
        }
    

    The fix was to move the setting of the content type and header to the top of the method:

        @GetMapping("/{id}/download-pdf")
        @Secured(Roles.ADMIN)
        public void downloadPDFResource(@PathVariable("id") EntityId entityId,
                                        HttpServletRequest request, HttpServletResponse response,
                                        Locale locale) throws IOException {
            response.setContentType("application/pdf");
            response.addHeader("Content-Disposition",
                               "attachment; filename=" + "document.pdf");
    
            byte[] pdf = pdfService.generatePdf("details-pdf", context);
            response.getOutputStream().write(pdf);
    
            response.getOutputStream().flush();
        }