I am developing a microservice in springboot to generate pdf by using freeMarker and openHtmlToPdf libraries. I want to introduce custom font(tamil language). But in only getting #### as output. Not sure where I am going wrong.
Method converting html to pdf
private fun convertToPdf(htmlContent: String): ByteArrayResource {
val jsoupDocument = Jsoup.parse(htmlContent)
jsoupDocument.outputSettings().syntax(Document.OutputSettings.Syntax.html)
val xmlDocument = W3CDom().fromJsoup(jsoupDocument)
val FONT_FILE = File("resources/fonts/NotoSansTamil.ttf")
val byteArrayOutputStream = ByteArrayOutputStream()
val baseUrl = javaClass
.protectionDomain
.codeSource
.location
.toString()
PdfRendererBuilder()
.withW3cDocument(xmlDocument, baseUrl)
.useFont(FONT_FILE, "Nota Sans")
.toStream(byteArrayOutputStream)
.run()
return ByteArrayResource(byteArrayOutputStream.toByteArray())
}
Freemarker template
<html>
<head>
<#-- <meta charset="UTF-16">-->
<title>FreeMarker</title>
<style>
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url(./fonts/NotoSansTamil.ttf);
}
</style>
</head>
<body>
<h1> Welcome to FreeMarker ${name} </h1>
</body>
</html>
There are multiple different problems that code.
font-familymismatchYou defined font as
but in the hmtl frament using
Just for the record this font called Noto instead of Nota.
Solution: Always use the same font family name in html fragment as defined in Kotlin code.
Wrong
FilepathAs you defined the font is totally wrong. I assume your project layout is like Maven / Gradle suggest. In this case the
resourcesfolder should be[project_root]/src/main/resourcesIf I'm right then the font should be at
[project_root]/src/main/resources/fonts/NotoSansTamil.ttfbut yourFONT_FILEwill point to[project_root]/resources/fonts/NotoSansTamil.ttf.Messy Base URL
You build and pass
baseUrltoPdfRenderedBuilderto resolve resources.If your layout is Maven / Gradle like, then it points to
[project_root]/target/classes/. It will never work on the other machine and it won't work when you pakcage your code into an artifact.Loading font as file not a resource
This snippet specify a file on the file system, but you need a resource which is usually shipped with that artifact.
Solution
Mixing font resolution concepts
You added a font both renderer
.useFont(...)and html / css sidesrc: url(...);It's a bad idea and won't work properly.Solution: Choose only one way. Use either
builder.useFontor a@font-facerule, not both. I suggest usebuilder.useFont. In this case@font-facedefinition and messybaseUrlare no longer required.Putting all together
Fixing all previously mentioned problems the following code will work.
NOTE: I have never written Kotlin code before, probably it could be made better, optimized, etc.