Monday, December 20, 2010

Embedding fonts into PDF generated by JasperReports

Today I was creating a report that needed to be exported to PDF. I used the de facto Java standard for when you need a good report: JasperReports (http://jasperforge.org/projects/jasperreports). To make things easier for me, I used the iReport report designer (http://jasperforge.org/projects/ireport), which is a WYSIWYG tool to create JasperReports reports.

I used different fonts, some bold, some regular. The output looked really good in the iReport preview. Then I ran my application and created the PDF. All the fonts and font styles (bold, italic) were gone and had been replaced by one plain font. After googling a bit, I found the cause of the problem: the fonts I used were not embedded in the generated PDF, so they could not be shown correctly.

I will now explain how you can embed fonts in your PDF. The methods described here work on JasperReports 3.7 and greater, so make sure you have a recent version.

There are two methods to embed the fonts in your PDF. Both methods yield the same result, but one method requires the use of iReport. I will first explain the method without iReport, then the method with iReport. If you use iReport, I strongly suggest using the method with iReport, since it is much easier.

1. No iReport (the hard way)


We will use a JasperReports extension, called the simple font extension. This extension registers the necessary fonts with JasperReports so it can embed them in a PDF when needed. The first thing you need to do is to create a file called jasperreports_extension.properties. This file should have the following content (I broke up the lines so they fit the screen, don't do this yourself):


net.sf.jasperreports.extension.registry.factory.fonts=
net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.myfamily=
fonts/myfamily.xml


Then you'll need a file called myfamily.xml in a fonts folder. This is how the content should look like:

<?xml version="1.0" encoding="UTF-8"?>
<fontFamilies>

<fontFamily name="Arial">
<normal><![CDATA[fonts/arial.ttf]]></normal>
<bold><![CDATA[fonts/arialbd.ttf]]></bold>
<italic><![CDATA[fonts/ariali.ttf]]></italic>
<boldItalic><![CDATA[fonts/arialbi.ttf]]></boldItalic>
<pdfEmbedded><![CDATA[true]]></pdfEmbedded>
</fontFamily>


<fontFamily name="Tahoma">
<normal><![CDATA[fonts/tahoma.ttf]]></normal>
<bold><![CDATA[fonts/tahomabd.ttf]]></bold>
<pdfEmbedded><![CDATA[true]]></pdfEmbedded>
</fontFamily>


</fontFamilies>

As you can see, I embedded two fonts here: Arial and Tahoma. Arial has a regular, bold and italic variant, while Tahoma lacks the italic variant. I set both pdfEmbedded to true, to make sure they get embedded into pdfs. You will of course also have to put the ttf files in the fonts directory you created earlier. You will have to locate the ttf files on your harddisk. For windows, they are located in \windows\fonts.

Now all you need to do is add all the files we created and copied to the classpath of your application. To sum it up, you'll have the following files on your classpath:
  • jasperreports_extension.properties: This file needs to go in the root of your classpath (so not in a package). It will be automatically picked up by JasperReports.
  • fonts/myfamily.xml: The xml file defining the fonts. It should be named as you declared it in the .properties file.
  • fonts/*.ttf: All the ttf files you reference in your xml file

 

2. Using iReport (the easy way)


Everything we did in the first method can be automated using iReport. The first thing you need to do is make sure the all the fonts you used in your report have been defined in iReport. You can do this by starting iReport and going to Tools -> Options -> iReport -> Fonts. You'll see the following window:



If the fonts you used are not yet installed (they probably aren't), you'll need to install them. Click the "Install Font" button. A wizard will pop up, asking you the font name and the location of the ttf files. Just direct the application to the location of the ttf files (for windows systems this is generally in the windows\fonts folder). Make sure to check the "Embed this font in PDF" checkbox on the second page! All other settings can be left at their defaults. Once all the fonts are installed, you select all the fonts you used in your report (hold <code>ctrl</code> to select multiple entries from the list). Then you click the "Export as extension" button. This will create a jar file. All you need to do is add the created jar file to the classpath of your application and you're done!

54 comments:

  1. Good article. I think font extensions are not understood or used as well as they should be, so it's nice to see things like this.
    By the way, there is no "s" in iReport.

    ReplyDelete
  2. Thanks, that article saved my day! I was searching arround for days and did not find a suitable solution to this Problem. I could not beleive that a Report tool like Jasper cannot handle bold fonts.

    ReplyDelete
  3. Hi Christoph,

    As you can see Jasper Reports can handle bold fonts, you just have to know how to configure it :-). That's the main problem with Jasper Reports: the documentation. There is the ultimate guide that's very good, but unfortunately it's not free. If you don't use Jasper Reports commercially you're on your own.

    ReplyDelete
  4. Thanks a lot. I finally made it work!

    ReplyDelete
  5. I have tried both methods, but they are only applicable if you are using Java 1.5 while I am using Java 1.4. Do we have other way to resolve this issue?

    ReplyDelete
  6. Hi Andy,

    First of all I would definitely recommend upgrading to a newer java version: 1.4 is starting to get pretty old. I suppose you don't have a choice or you would already have done so.
    Can you tell me exactly which part doesn't work on java 1.4? Is it the font extension, iReport, JasperReport...? You could try mapping the fonts directly in your report xml file, as follows:

    <font fontName="My Font" ispdfembedded="true"
    pdffontname="path/to/myfont.ttf"/>

    I haven't tried this though, so I don't know if it will work...

    ReplyDelete
  7. Hi,

    I have created the fonts jar file and kept in the classpath.
    After this do we need to do any changes in the jrxml file like setting "PDFembedded = true"..please clarify

    Regards,
    Hema

    ReplyDelete
  8. hi,

    my concern is how can we make sure that the jasper report is using the fonts from fonts jar file or from windows/unix environment.

    Please clarify..

    Thanks in advance,
    Hema.

    ReplyDelete
  9. Hi,

    Jasper reports will not pick up the fonts from the windows/unix environment. This is the reason you need the font extension. iReport DOES pick up the fonts from the OS, and that's the reason your report looks ok in iReport but not in JasperReport.

    In the fonts.jar file is a file called jasperreports_extension.properties. Jasper reports will automatically pick up this file and read it out. It will the find your font definition file (the fontfamily.xml file or whatever you called it) and get the fonts from that file. It will all be automatic, all you need to do is add the jar file to your classpath.

    ReplyDelete
  10. Hi,

    You don't have to modify your jrxml file if you use the font extension, that was the old approach. The new approach is to use the font extension. All you have to do is make sure that the font name used in your jrxml file is the same as the one you define in the fontfamily.xml file.

    ReplyDelete
  11. Hi !! i have a question, i generate the archive.jar with fonts that i needed, y my projects i add, but i dont see this changes, and makes a error... only add .jar or i have to do something else?

    ReplyDelete
  12. Hi Pollet,

    What error are you getting? Please make sure you use a real font (Arial, Times New Roman...) and not a Java substitute font (like SansSerif)

    ReplyDelete
  13. GRAVE: java.lang.NoClassDefFoundError: org/springframework/core/io/Resource
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at net.sf.jasperreports.engine.util.JRClassLoader.loadClassForRealName(JRClassLoader.java:157)
    at net.sf.jasperreports.engine.util.JRClassLoader.loadClassForName(JRClassLoader.java:115)
    at net.sf.jasperreports.engine.util.ClassUtils.instantiateClass(ClassUtils.java:53)
    at net.sf.jasperreports.extensions.DefaultExtensionsRegistry.instantiateRegistry(DefaultExtensionsRegistry.java:198)
    at net.sf.jasperreports.extensions.DefaultExtensionsRegistry.loadRegistries(DefaultExtensionsRegistry.java:175)
    at net.sf.jasperreports.extensions.DefaultExtensionsRegistry.loadRegistries(DefaultExtensionsRegistry.java:135)
    at net.sf.jasperreports.extensions.DefaultExtensionsRegistry.getRegistries(DefaultExtensionsRegistry.java:121)
    at net.sf.jasperreports.extensions.DefaultExtensionsRegistry.getExtensions(DefaultExtensionsRegistry.java:98)
    at net.sf.jasperreports.engine.util.JRStyledTextParser.(JRStyledTextParser.java:76)
    at net.sf.jasperreports.engine.fill.JRBaseFiller.(JRBaseFiller.java:174)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.(JRVerticalFiller.java:74)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.(JRVerticalFiller.java:56)
    at net.sf.jasperreports.engine.fill.JRFiller.createFiller(JRFiller.java:143)
    at net.sf.jasperreports.engine.fill.JRFiller.fillReport(JRFiller.java:79)
    at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:624)
    at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:540)

    this is my error, so I question you, if no is necesary to do some extra thing

    ReplyDelete
  14. of course, is arial, and variations of arial
    (bold, italic and bold-italic)

    ReplyDelete
  15. Hi Polet,

    Add the spring-core-x.x.x.jar and spring-beans-x.x.x.jar to your application. These are needed by the font extension.

    ReplyDelete
  16. some thing and no more, I need to see the align (left, right o justify )in the .pdf and no give it format in the ireport, i need give it format from java-jasperreport, because I receive a text in html and should respect all formats in the pdf. some idea???

    ReplyDelete
  17. Hi Polet,

    If you want to pass html, just add a textfield to your report and set the "markup" property of the textfield to "html" using iReport.

    ReplyDelete
  18. Excelent!!!!
    I'm using windows to compile reports than will be generated dinamicaly on linux JVM, this is better solution than install ms-core-font.
    Thank you.

    ReplyDelete
  19. thxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    ReplyDelete
  20. [net.sf.jasperreports.extensions.DefaultExtensionsRegistry] Error instantiating extensions registry for chart.theme: org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from URL [vfs:/C:/jboss-6.1.0.Final/server/default/deploy/ReqTrace.war/WEB-INF/lib/jasperreports-chart-themes-4.0.1.jar/net/sf/jasperreports/chartthemes/spring/beans/chartThemesBeans.xml]; nested exception is java.lang.IllegalArgumentException: Class [org.apache.cxf.ws.policy.spring.PolicyNamespaceHandler] does not implement the NamespaceHandler interface

    ReplyDelete
    Replies
    1. hey.

      How did you solve this?
      Thank you

      Delete
  21. iReport 4.1.1 says error access denied when trying to install a font.
    And manually, what should be the place to jasperreports_extension.properties? Grail app root?

    ReplyDelete
  22. It works great for me, i only added Arial Unicode MS, set PDF embedded, and now i can export in various languajes. Thank you men!

    You can try printing this for testing purposes:

    Test Arabic characters - ﺀ ﻻ للها لله ﻼ ﷲ گ ﭪﭖ
    Test Chinese characters - 甲 骨 文 章 草 新 隸 體 書
    Test Arabic characters - ﺀ ﻻ للها لله ﻼ ﷲ گ ﭪﭖ
    Test Hindi characters - अ आ इ ई उ ऊ ऋ ऌ ऍ ऎ ए ऐ
    Test Russian characters - И з м е н и т ь з а д а ч и
    Test Farsi characters - ماموریت نگهداری نرخ تبدیل ارز
    Test Hungarian characters - Üzenet szöveg
    Test Turkish characters - Açıklama
    Test Spanish characters - Descripción
    Test English characters - Description

    ReplyDelete
    Replies
    1. Hi ,
      Am trying to load a arabic text but it is loading like this "اÙرجاء إدخا٠اÙعدد اÙبر Ù" any help? i have loaded the fonts and steps mentioned above.

      Thanks

      Delete
  23. add the created jar file to the classpath of your application, where is classpath?

    ReplyDelete
  24. Hi Cuinetes,

    It looks like you're having some problems with the classpath. I've never written a Grails applications, so I'm not sure how it works. You need to add the jar to the classpath. For web applications this is typically in the WEB-INF\lib directory. I'm not sure this is also the case for Grails application. Try locating the other .jar files in your application and place the fonts jar together with the other jar files. Then restart the server.

    ReplyDelete
  25. Hi Cuinetes,

    Please follow the below link to add font extensions to Grails App

    http://stackoverflow.com/questions/6711480/including-liberation-ttf-fonts-in-a-grails-war

    Regards,
    S.S. Khan

    ReplyDelete
  26. great article thank you,

    im using jasper reports in web application pdf exporting
    with above settings i wanted to embed the font
    i use following font tag in jrxml file

    font fontName="Arial" size="10" isItalic="false" isPdfEmbedded ="true" pdfEncoding ="Identity-H"

    ReplyDelete
  27. I am new to iReport. I ve tried to follow ur solution but faced two problems:
    1- When I try to intsall the font, I get a "Access deined on the font file" error , although the file is not protected and i ve even copied it to the iReports font folder.

    2- The "export as extension " button in my iReport is disabled and I dont know why.

    ReplyDelete
  28. ERROR [net.sf.jasperreports.extensions.DefaultExtensionsRegistry] Error instantiating extensions registry for chart.theme from vfszip:My-App.ear/lib/jasperreports-chart-themes-4.7.0.jar/jasperreports_extension.properties
    org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [defaultChartPropertiesBean.xml]
    Offending resource: URL [My-App.ear/lib/jasperreports-chart-themes-4.7.0.jar/net/sf/jasperreports/chartthemes/spring/beans/chartThemesBeans.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [chartConstantsBean.xml]
    Offending resource: URL [My-App.ear/lib/jasperreports-chart-themes-4.7.0.jar/net/sf/jasperreports/chartthemes/spring/beans/defaultChartPropertiesBean.xml]; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from URL [My-App.ear/lib/jasperreports-chart-themes-4.7.0.jar/net/sf/jasperreports/chartthemes/spring/beans/chartConstantsBean.xml]; nested exception is org.springframework.beans.FatalBeanException: Class [org.springframework.beans.factory.xml.UtilNamespaceHandler] for namespace [http://www.springframework.org/schema/util] does not implement the [org.springframework.beans.factory.xml.NamespaceHandler] interface
    at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)

    Anyone can help me please?

    Thanks

    ReplyDelete
    Replies
    1. OK Problem Solved.

      I included jasperreports-chart-themes-4.7.0.jar in my classpath. However, this jar wasn't used anymore. I only used the default themes from jasper.

      Deleting this jar from .ear and everything works fine.

      Thanks anyway

      Delete
  29. net.sf.jasperreports.engine.util.JRFontNotFoundException: Font '’Arial’' is not available to the JVM. See the Javadoc for more details.
    at net.sf.jasperreports.engine.util.JRFontUtil.checkAwtFont(JRFontUtil.java:358)
    at net.sf.jasperreports.engine.util.JRStyledText.getAwtAttributedString(JRStyledText.java:226)
    at net.sf.jasperreports.engine.fill.TextMeasurer.measure(TextMeasurer.java:326)
    at net.sf.jasperreports.engine.fill.JRFillTextElement.chopTextElement(JRFillTextElement.java:511)
    at net.sf.jasperreports.engine.fill.JRFillTextField.prepare(JRFillTextField.java:593)
    at net.sf.jasperreports.engine.fill.JRFillElementContainer.prepareElements(JRFillElementContainer.java:328)
    at net.sf.jasperreports.engine.fill.JRFillBand.fill(JRFillBand.java:388)
    at net.sf.jasperreports.engine.fill.JRFillBand.fill(JRFillBand.java:347)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillTitle(JRVerticalFiller.java:329)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReportStart(JRVerticalFiller.java:263)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport(JRVerticalFiller.java:129)
    at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:903)
    at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:832)
    at net.sf.jasperreports.engine.fill.JRFiller.fillReport(JRFiller.java:84)
    at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:624)
    at net.sf.jasperreports.engine.JasperRunManager.runReportToPdf(JasperRunManager.java:421)
    at org.apache.jsp.jsp.print_005fexecsummary_005fjasper_jsp._jspService(print_005fexecsummary_005fjasper_jsp.java:388)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

    please help.. i followed your steps.. its still not working

    ReplyDelete
  30. Hi Kiran,

    Are you sure you added all the files to the classpath? How are you testing your application?

    ReplyDelete
  31. This comment has been removed by the author.

    ReplyDelete
  32. Permiss denied when install the font... any ideas?

    ReplyDelete
  33. Solved: sudo chmod 777 to /usr/lib/iReport.4..1/ireport/fonts and restart the server.

    ReplyDelete
  34. Hi ,
    Am trying to load a arabic text but it is loading like this "اÙرجاء إدخا٠اÙعدد اÙبر Ù" any help?

    ReplyDelete
  35. Hi sri,

    Make sure you are using a unicode font and that it is embedded in the pdf

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Hi Mathias,
      Can u explain about how to do it i have done this earlier but still it is not working. if possible a step by step explanation would be very helpful.


      Thanks In Advance

      Delete
    3. This comment has been removed by the author.

      Delete
    4. Hi Mathias,

      ResourceBundle bundle = ResourceBundle.getBundle("Arabic-Report", Locale.getDefault(), "Path of that Arabic-Report file");

      In that bundle variable arabic text are read like this "إدخا٠اÙعدد اÙبر Ù".

      Arabic-Report is a .property(saved as UTF-8 format) file which contains key and its corresponding arabic value.

      Any suggestion ?

      Thanks

      Delete
  36. Hi,
    I got the following error when Export as extension button is click.
    "duplicate entry: fonts/Zawgyi-One-20051130.ttf"

    Any idea?
    Thank

    ReplyDelete
    Replies
    1. Sorry, I know why. It's because I also choose that font for bold and italic.

      Delete
  37. pdf is generating in hindi in ireport tool bt when i use java code to generate pdf by passing the same jrxml,it is nt working??? :(

    ReplyDelete
  38. trying to add a √ (check mark) in ireport. It displays in the ireport when run but comes blank when run from application pdf format. So which font to install for this.
    Thanks

    ReplyDelete
  39. I think I have never seen such blogs ever before that has complete things with all details which I want. So kindly update this ever for us.
    user manual

    ReplyDelete
  40. It already works fine in the PDF output of the iReport, but when I used it in my Java application, the texts are not in BOLD. I already successfully made a JAR file and added it to my classpath, but still the texts are not in BOLD. I am using Arial font and would like to see some texts in bold. I am just running a local Java Application in a runnable JAR. I added the JAR via Build Path> Configure Build Path> Add JAR in Libraries Tab. Any input would help. Thanks!

    ReplyDelete
  41. rap beats for saleI conclude I have selected the smart and inconceivable website along with interesting stuff.

    ReplyDelete