Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iText + HTMLWorker - How to change default font?

I have to create a PDF file from a HTML source. Currently, I'm coping with problem concerning special (polish) characters in the output file, precisely with their lack.

HTML source:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<table width="100%" border="0.5" align="center" cellpadding="0" style="border-collapse:collapse; border:1px solid black; font-family:Arial, Helvetica, sans-serif; font-size:16px">
  <tr>
    <td align="center" ><b>Test: ąęłóćńśŁÓŃĆŻŹąśżźłęó</b></td>
  </tr>
</table>

Java source:

Document document = new Document(PageSize.A4, 38, 38, 50, 38);  
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("iTextExample.pdf"));  
document.open();  
HTMLWorker htmlWorker = new HTMLWorker(document);  
htmlWorker.parse(new StringReader(readFileAsString("index.html")));  
document.close();


public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) {
            throw new IOException("File " + filePath + " too large, was " + len + " bytes.");
        }
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}

My question is: how to change default font (Helvetica) to eg. Arial Bold in whole PDF document?

I've tested many examples connected with StyleSheet and none of them worked. I have to change a default font, because there's no polish characters - that's the solution I hope is going to work.

Edit:

class defaultFontProvider extends FontFactoryImp {

    private String _default;

    public defaultFontProvider(String def) {
        _default = def;
    }

    public Font getFont(String fontName, String encoding, boolean embedded, float size, int style, BaseColor color, boolean cached) {
        if (fontName == null || size == 0) {
            fontName = _default;
        }

        return super.getFont(fontName, encoding, embedded, size, style, color, cached);
    }
}

The code above embeds arial.ttf which is OK, but how do I make it the default font (instead of Helvetica) for the whole document.

Then..

Map<String,Object> providers = new HashMap<String, Object>();

defaultFontProvider dfp = new defaultFontProvider("arial.ttf");

providers.put(HTMLWorker.FONT_PROVIDER, dfp);

HTMLWorker htmlWorker = new HTMLWorker(document);
htmlWorker.setProviders(providers);
like image 269
monczek Avatar asked Feb 08 '11 16:02

monczek


3 Answers

It will not chage the default font but only that tag where you will apply.

E.g. <Body>

Add style property in html tag

<tag style="font-family: Arial Unicode MS, FreeSans; font-size:16px; font-weight: normal; >Здраво दी फोंट डाउनलोड Ravi Parekh! </tag>

Note: System should found ARIALUNI in XMLWorkerFontProvider

XMLWorkerHelper.getInstance().parseXHtml(writer, document, new ByteArrayInputStream(html.getBytes(Charset.forName("UTF-8"))), null,Charset.forName("UTF-8"), new XMLWorkerFontProvider("/fonts/"));

sample:SamplePDF

like image 184
Ravi Parekh Avatar answered Nov 10 '22 20:11

Ravi Parekh


Idea #1

One answer immediately springs to mind: Change iText. Specifically, Font.getCalculatedBaseFont, line 644.

String fontName = BaseFont.HELVETICA;

Actually, I don't think that will work unless you also change the way fonts are created... Line 712

cfont = BaseFont.createFont(fontName, encoding, false);

Unless a font is one of the "Base 14", you have to provide a path to the font's file rather than a simple font name.

Another option: XSLT

Transform the input such that you add a font definition to the style of any node that contains text.

Finally: register a fontProvider

You can sit on top of FontFactoryImp and simply map blank strings to your font of choice.

class DefaultFontProvider extends FontFactoryImp {
  private String default;
  public DefaultFontProvider(String def) {
    default = def;
  }

  // I believe this is the correct override, but there are quite a few others.
  public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color, boolean cached) {
    if (fontName == null || fontName.size() == 0) {
      fontName = default;
    }
    return super.getFont(fontName, encoding, embedded, size, style, color, cached);
  }
}


Map<String,Object> providers = new HashMap<String, Object)();
providers.put(HTMLWorker.FONT_PROVIDER, new DefaultFontProvider("Arial Bold"));

myHTMLWorker.setProviders(providers);

This strikes me as the most Technically Sound idea. It's written for the freshly released 5.0.6 version of iText. Previous versions set the font provider via setInterfaceProps() instead. "Providers" is more of a name change than anything else at this point. I suspect that will no longer be the case in 5.1.

PS: FontFactoryImp has two public members you might be interested in as well: defaultEncoding and defaultEmbedding. You should be able to tweak the defaultEncoding to something more Polish-friendly. I recommend "Identity-H" (aka BaseFont.IDENTITY_H), but that does force all your fonts to be embedded subsets, thus ignoring defaultEmbedding, and making your files a bit larger than if the fonts weren't embedded at all.


Two possible problems:

  1. Explicitly requesting "Helvetica".

    To be sure, I suggest stuffing System.out.println(("Requested font: " + fontName); into the beginning of your getFont function. This will let you see all the font calls, and make sure you have all your fonts replaced correctly. If that's the case, you can just test for it and replace it with _default.

  2. Your fontFactory might not be finding anything for "Arial Bold" and so falls back to the default (Helvetica again).

    I think you need to call dfp.registerDirectories(). That'll ferret out all the fonts on several different OS's, and let you reference them all by font name rather than by path (which is what a FontFactoryImp is supposed to do in the first place).

like image 3
Mark Storer Avatar answered Nov 10 '22 22:11

Mark Storer


In your style tag, perhaps you can use CSS3 to change the font:

<style>
@font-face {
font-family: myFont;
src: url(Filename);
}
</style>

Not sure if this is what you were asking.

like image 1
Brendan Avatar answered Nov 10 '22 21:11

Brendan