如何在使用PDFBox将字符串打印为PDF之前清理字符串

时间:2017-02-24 14:16:11

标签: java pdf encoding utf-8 pdfbox

我正在使用UTF-8的用户输入创建PDF文档。

除了显示PDF之外,创建本身也失败了java.lang.IllegalArgumentException: U+039B is not available in this font's encoding: WinAnsiEncoding

这里的大多数答案都指向“使用支持更好UTF-8的字体”,但由于我无法控制用户输入,因此这种UTF-8支持永远不会足够好,我需要一个防弹解决方案(就像打印一些东西而不是错误一样。)

答案Using PDFBox to write unicode strings to a PDF表明在将文本添加到PDF之前应对文本进行清理。

问题是我找不到有效的例子来实现这一点。 所有示例似乎都指向已删除的代码(font.setToUnicode或某些编码方法,以便一次转换一个字符)。

简而言之,我有一个字符串我想要一个防弹方法将大部分写入PDFBox文档(显然,字体中缺少的字符将被替换或不打印)。

非常感谢, JM

1 个答案:

答案 0 :(得分:0)

我结束了角色消毒的角色。

这就是我的清理功能。

为了避免重新处理字符,我正在为每个给定字体缓存每个字符的可用性。

当代码点没有字体时,我正在尝试"标准"替换字符,如果不可用,我将替换为问号。

这确实是效率低下的,但我还没有找到另一种更有效的方法,因为我没有控制权,也没有预先知道所印刷的内容。

可能有很多事情需要改进,但这适用于我的用例。

private String getPrintableString(String string, PDFont font) {

    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < string.length(); i++) {

        int codePoint = string.codePointAt(i);

        if (codePoint == 0x000A) {
            sb.appendCodePoint(codePoint);
            continue;
        }

        String fontName = font.getName();
        int cpKey = fontName.hashCode();
        cpKey = 31 * cpKey + codePoint;

        if (codePointAvailCache.get(cpKey) == null) {

            try {
                font.encode(string.substring(i, i + 1));
                codePointAvailCache.put(cpKey, true);
            } catch (Exception e) {
                codePointAvailCache.put(cpKey, false);
            }
        }

        if (!codePointAvailCache.get(cpKey)) {

            // Need to make sure our font has a replacement character
            try {
                codePoint = 0xFFFD;
                font.encode(new String(new int[] { codePoint }, 0, 1));
            } catch (Exception e) {
                codePoint = 0x003F;
            }
        }

        sb.appendCodePoint(codePoint);
    }

    return sb.toString();
}