Search code examples
javaunicodeitextjfreechartcyrillic

Howto write Cyrillic characters in jFreeChart with iText


I'm using itextpdf (5.1.3) and jFree chart (1.0.19) to draw a bar chart inside a pdf document.

To write some text inside my pdf document and also as title and legend in my bar chart i'm using some unicode characters (cyrillic text).

Therefor i'm using FreeSans.ttf as font.

According to the answer from Paulo Soares and the example on http://downloads.sourceforge.net/jfreechart/jfreechart2pdf-v2.pdf i changed my testcode to:

package com.mytest.business.report;

import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.OutputStream;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.DefaultCategoryDataset;


import java.io.BufferedOutputStream;

import java.io.FileOutputStream;
import java.io.IOException;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.DefaultFontMapper;
import com.itextpdf.text.pdf.FontMapper;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;


/**
 * A simple demonstration showing how to write a chart to PDF format using
 * JFreeChart and iText.
 * <P>
 * You can download iText from http://www.lowagie.com/iText.
 */
public class ChartToPDFDemo1 {

    final static String CP1251_TEST_TEXT = "TEST123 - \u042f \u043b\u044e\u0431\u043b\u044e \u0442\u0435\u0431\u044f - ENDE";
    /**
     * Saves a chart to a PDF file.
     *
     * @param file
     *            The file.
     * @param chart
     *            The chart.
     * @param width
     *            The chart width.
     * @param height
     *            The chart height.
     */
    public static void saveChartAsPDF(File file, JFreeChart chart, int width, int height, FontMapper mapper)
            throws IOException {
        OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
        writeChartAsPDF(out, chart, width, height, mapper);
        out.close();
    }

    /**
     * Writes a chart to an output stream in PDF format.
     *
     * @param out
     *            The output stream.
     * @param chart
     *            The chart.
     * @param width
     *            The chart width.
     * @param height
     *            The chart height.
     */
    public static void writeChartAsPDF(OutputStream out, JFreeChart chart, int width, int height, FontMapper mapper)
            throws IOException {

        Document document = new Document(PageSize.A6, 50, 50, 50, 50);;
        try {
            PdfWriter writer = PdfWriter.getInstance(document, out);
            document.addAuthor("JFreeChart");
            document.addSubject("Demonstration");
            document.open();
            document.add( new Paragraph(CP1251_TEST_TEXT, getFont(8, 0)));
            PdfContentByte cb = writer.getDirectContent();
            PdfTemplate tp = cb.createTemplate(width, height);
            Graphics2D g2 = tp.createGraphics(width, height, mapper);
            Rectangle2D r2D = new Rectangle2D.Double(0, 0, width, height);
            chart.draw(g2, r2D, null);
            g2.dispose();
            cb.addTemplate(tp, 0, 0);
        } catch (DocumentException de) {
            System.err.println(de.getMessage());
        }
        document.close();
    }

    public static com.itextpdf.text.Font getFont(final float size, final int style) {

        final String FONT = MyTest.class.getResource("fonts/FreeSans.ttf").getFile();
        return FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, size, style);
    }

    public static DefaultFontMapper mapper() {
        DefaultFontMapper mapper = new DefaultFontMapper();
        final String FONT = MyTest.class.getResource("fonts").getFile();
        mapper.insertDirectory(FONT);
        DefaultFontMapper.BaseFontParameters pp = mapper.getBaseFontParameters("FreeSans");
        if (pp != null) {
            pp.encoding = BaseFont.IDENTITY_H;
        }

        return mapper;
    }

    /**
     * Starting point for the demonstration application.
     */
    public static void main(String[] args) {
        try {

            JFreeChart chart = ChartFactory.createStackedBarChart(CP1251_TEST_TEXT, "", "", new DefaultCategoryDataset(),
                    PlotOrientation.VERTICAL, true, false, false);

            final Font newtitleFont = new Font("FreeSans", Font.PLAIN, 10);
            chart.getTitle().setFont(newtitleFont);

            Font font = new Font("FreeSans", Font.PLAIN, 8);
            TextTitle subtitle = new TextTitle(CP1251_TEST_TEXT, font);
            chart.addSubtitle(subtitle);


            // write the chart to a PDF file...
            File fileName = new File("target/test3.pdf");
            saveChartAsPDF(fileName, chart, 400, 300, mapper());
            System.out.println("pdf crated...");
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }
}

This creates the example pdf file:

enter image description here

My Problem was, i created the .pdf in my JBoss application. This application server is not able to read a file with "class.getResource()". To resolve this Problem i read from stream and copy the font in a temporary file. Here is the code:

        final byte[] bytes = IOUtils.toByteArray(MyFontFactory.class.getResourceAsStream("fonts/FreeSans.ttf"));

        // Font (mapper) for JFreeChart...
        // Because the mapper can't handle streams we need to copy file to local tmp folder...
        final File tempFile = File.createTempFile("FreeSans", ".ttf", null);
        final FileOutputStream fos = new FileOutputStream(tempFile);
        fos.write(bytes);
        fos.close();

        mapper = new DefaultFontMapper();
        mapper.insertFile(tempFile);
        final DefaultFontMapper.BaseFontParameters pp = mapper.getBaseFontParameters("FreeSans");
        if (pp != null) {
            pp.encoding = BaseFont.IDENTITY_H;
        }

Solution

  • Have a look at http://downloads.sourceforge.net/jfreechart/jfreechart2pdf-v2.pdf. You'll have to create a font mapper between the awt font and the iText font. Something like this:

    DefaultFontMapper mapper = new DefaultFontMapper();
    mapper.insertDirectory("c:/windows/fonts");
    DefaultFontMapper.BaseFontParameters pp = mapper.getBaseFontParameters("Arial Unicode MS");
    if (pp!=null) {
        pp.encoding = BaseFont.IDENTITY_H;
    }