I'm trying to generate a pdf contains Chinese UTF-8 characters via flying saucer and thymeleaf. But the generated pdf just ignore all the Chinese characters (latin is fine). Here is the Thymeleaf configuration
@Configuration
public class ThymeleafConfig {
@Bean
public ClassLoaderTemplateResolver fileTemplateResolver(){
ClassLoaderTemplateResolver fileTemplateResolver = new ClassLoaderTemplateResolver();
fileTemplateResolver.setPrefix("templates/");
fileTemplateResolver.setTemplateMode("HTML");
fileTemplateResolver.setSuffix(".html");
fileTemplateResolver.setCharacterEncoding("UTF-8");
fileTemplateResolver.setOrder(1);
return fileTemplateResolver;
}
@Bean
public SpringTemplateEngine templateEngine(){
SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.setEnableSpringELCompiler(true);
springTemplateEngine.setTemplateResolver(fileTemplateResolver());
return springTemplateEngine;
}
@Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
}
As you can see, I've set the character encoding to UTF-8 for both template resolver and view resolver.
And the PDF Util for generating pdfs
public class PDFUtil {
@Autowired
private TemplateEngine templateEngine;
public String createPdf(String templatename, String fileName, String modelName, Object model) throws IOException, DocumentException {
String fileNameUrl = "";
Context ctx = new Context();
ctx.setVariable(modelName, model);
String processedHtml = templateEngine.process(templatename, ctx);
FileOutputStream outputStream = null;
try {
final File outputFile = File.createTempFile(fileName, ".pdf");
outputStream = new FileOutputStream(outputFile);
ITextRenderer renderer = new ITextRenderer();
ITextFontResolver resolver = renderer.getFontResolver();
final ClassPathResource fonts = new ClassPathResource("fonts/PingFangSCRegular.ttf");
String test = fonts.getFilename();
resolver.addFont(fonts.getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
renderer.setDocumentFromString(processedHtml);
renderer.layout();
renderer.createPDF(outputStream, false);
renderer.finishPDF();
FileSystemResource resource = new FileSystemResource(outputFile);
fileNameUrl = resource.getURL().toString();
}
finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) { }
}
}
return fileNameUrl;
}
}
Here I've added the Chinese font to the resolver.
And this is the template html head
<head th:fragment="html_head">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Title</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://unpkg.com/jsbarcode@latest/dist/JsBarcode.all.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/fontawesome.min.css" />
<style type="text/css">
@font-face {
font-family: 'PingFang SC Regular';
src: url('/fonts/PingFangSCRegular.ttf');
-fs-pdf-font-embed: embed;
-fs-pdf-font-encoding: Identity-H;
}
</style>
</head>
So I tried to declare that the charset is UTF-8 and the font family is PingFang SC Regular. But no surprise that does not work.
Here is the maven dependency I've added to my springboot project
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.22</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.3</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.13.3</version>
</dependency>
The html body I want to render
<body>
<div th:fragment="header(model)">
<div class="row">
<div class="col-4">
<img id="barcode" alt="111"/>
</div>
<div class="col-4">
<h3>啊啊啊啊啊啊aaa[[${model.title}]]</h3>
<p id="print-time">[[${model.printTime}]]</p>
</div>
</div>
</div>
</body>
Can anyone figure out why the UTF-8 character does not show in the generated pdf? Any idea would be appreciate.
In your template, you declare the font-face, but you don't apply it to the content of the page.
You just have to declare that the font should be used:
body {font-family: 'PingFang SC Regular';}
Also, you don't need to use @font-face
in the template, as you have added the font to the renderer (using resolver.addFont
).
The following HTML should work fine:
<html>
<head>
<style>
body {font-family: 'PingFang SC Regular';}
</style>
</head>
<body>
<h3>啊啊啊啊啊啊</h3>
</body>
</html>