Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use embedded Fonts to call the Graphics2D.drawString(...) with iText (DefaultFontMapper?)

Tags:

java

itext

To generate a valid PDF/X document, it's mandatory to have all fonts embedded. Somehow it's not possible for me to use those fonts in an Graphics2D context.

This Unittests shows the problem (commented lines are some tests i made):

import java.awt.Font;
import java.awt.Graphics2D;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Map.Entry;

import org.junit.Test;

import com.itextpdf.awt.DefaultFontMapper;
import com.itextpdf.awt.DefaultFontMapper.BaseFontParameters;
import com.itextpdf.awt.PdfGraphics2D;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfWriter;

public class TestFont
{

    @Test
    public void shouldBeAbleToAddFountsAndDrawOnCanvas() throws FileNotFoundException, DocumentException
    {
        final DefaultFontMapper mapper = new DefaultFontMapper();
        mapper.insertDirectory(".");

        final PrintStream out2 = new PrintStream(System.out);
        for (final Entry<String, BaseFontParameters> entry : mapper.getMapper().entrySet())
        {
            out2.println(String.format("%s: %s", entry.getKey(), entry.getValue().fontName));
        }
        out2.flush();

        final float width = 150;
        final float height = 150;

        final Document document = new Document(new Rectangle(width, height));
        final PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("fonts.pdf"));
        writer.setPDFXConformance(PdfWriter.PDFX32002);

        document.open();
        final Graphics2D g2d = new PdfGraphics2D(writer.getDirectContent(), width, height, mapper);

        g2d.setFont(new Font("Comicate", Font.PLAIN, 12));

        g2d.drawString("Hello world", 5, 24);

        g2d.dispose();

        document.close();
    }

}

It will throw an PdfXConformanceException with message: "All the fonts must be embedded. This one isn't: Helvetica.

I already browsed though the PdfGraphics2D class to check the setFont() implementation and found out, that a FontMapper will be used. I already added this to the Unittest above.

public void setFont(Font f) {
    if (f == null)
        return;
    if (onlyShapes) {
        font = f;
        return;
    }
    if (f == font)
        return;
    font = f;
    fontSize = f.getSize2D();
    baseFont = getCachedBaseFont(f);
}

private BaseFont getCachedBaseFont(Font f) {
    synchronized (baseFonts) {
        BaseFont bf = (BaseFont)baseFonts.get(f.getFontName());
        if (bf == null) {
            bf = fontMapper.awtToPdf(f);
            baseFonts.put(f.getFontName(), bf);
        }
        return bf;
    }
}

The Unittest is based on this example from the iText in Action book. Here are some other examples about the FontMapper.

To run the Unittest you need this dependency:

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.3.2</version>
</dependency>

The Custom Font (located in ".") you find here.

The Console Output shows me this (to identify the fontName):

Comicate: ./COMICATE.TTF
like image 561
d0x Avatar asked Sep 28 '12 14:09

d0x


1 Answers

I am not sure of the exact way to correct the error in your code, but there are easy workarounds:

Workaround 1) Create a BufferedImage to do all your graphics painting to. Then you can use all normal java.awt.Graphics functions like drawString and setColor regardless of iText, and when you are done just draw the image to a PDF. WARNING you do loose quality of text when zooming, but here is an example:

//create doccument and writer    
Rectangle pagesize = new Rectangle(200, 100);
Document document= new Document(pagesize);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("C:\\sample.pdf"));

BufferedImage bf = new BufferedImage(BorderWidth, BorderHeight, BorderWidth);
//Do all graphics code here, draw strings and images etc
    //Some code to set font (java.awt.Font)
    //Some code to draw string
    //Some code to draw image?

//Convert BufferedImage to Image
Image img = (Image)bf;
//draw image to PDF using writer
writer.getDirectContentUnder().addImage(img);

Workaround 2) This uses iText features to draw strings, without needing to create any graphics objects, the font is taken care of by using a BaseFont as follows:

//create doccument and writer    
Rectangle pagesize = new Rectangle(200, 100);
Document document= new Document(pagesize);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("C:\\sample.pdf"));

document.open();
//This sample uses the "GOTHIC.TTF" font file located in the "Template" package
BaseFont bf = BaseFont.createFont(GUI.class.getClass().getResource("/Template/GOTHIC.TTF") + "", BaseFont.WINANSI, BaseFont.EMBEDDED);

//set font type, size and color
Font font = new Font(bf, 13.5f);

PdfContentByte canvas = writer.getDirectContent();

canvas.beginText();
canvas.setFontAndSize(bf, 10);
//Method Usage: showTextAligned(Align, String, x, y, rotation);
canvas.showTextAligned(Element.ALIGN_TOP, "My Text Here", 75, 40, 0);
canvas.endText();

document.close();

I know this does not give the answer you were looking for, however if you are just drawing a small amount of text then workaround 2 works great, I have used something similar to workaround 2 before. If this does not help then I am sure Bruno will have the answer.

like image 58
sorifiend Avatar answered Sep 22 '22 14:09

sorifiend