Itext PDF 不能正确显示缅甸 Unicode 字体

Itext PDF do not display correctly Myanmar Unicode Font

Itext 5 在为 Myanmar Unicode fonts 生成的 pdf 文件中显示不正确。

文本版本:5.5.13.1

期待结果 : 塞亚拉雅天才看了阿育吠陀药方,发誓比市场边的杏仁树还好

实际结果

Google Drive Link 生成的 PDF。

我的测试字符串与英文的"The quick brown fox jump over the lazy dog"相似。它包含大部分缅甸字母。

Java上面我用来制作的程序pdf

    String fileName = "sample.pdf";
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        Document doc = new Document();
        PdfWriter writer = PdfWriter.getInstance(doc, baos);
        writer.setCloseStream(false);

        BaseFont unicode = BaseFont.createFont("/fonts/NotoSansMyanmar-Regular.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        Font myanmarUniCodeFont = new Font(unicode, 11, Font.NORMAL, BaseColor.BLACK);
        Rectangle pageSize = new Rectangle(PageSize.A4);
        doc.setPageSize(pageSize);
        doc.open();
        String textStr = "သီဟိုဠ်မှ ဉာဏ်ကြီးရှင်သည်အာယုဝဎ္ဍနဆေးညွှန်းစာကို ဇလွန်ဈေးဘေးဗာဒံပင်ထက် အဓိဋ္ဌာန်လျက် ဂဃနဏဖတ်ခဲ့သည်။";
        doc.add(new Paragraph(textStr, myanmarUniCodeFont));
        doc.close();
    }
    catch (Exception e) {
        e.printStackTrace();
    }

    response.setCharacterEncoding(StandardCharsets.UTF_8.name());
    response.setHeader("Cache-Control", "no-cache,no-store,max-age=0");
    response.setHeader("Pragma", "No-cache");
    response.setHeader("Content-Disposition", "inline; filename=" + fileName);
    response.setContentType("application/pdf");
    response.setContentLength(baos.size());
    OutputStream os = response.getOutputStream();
    baos.writeTo(os);
    os.flush();
    os.close();
    baos.close();

输出文本正确(您可以复制并粘贴到文本编辑器如 Notepad++ 中查看结果)但在 pdf 文件中显示错误。

如何使用 itext-pdf-5 正确显示缅甸 Unicode 字体?

现在我正在使用肮脏的方式来查看可读的字体。我将所有 unicode 字符串转换为 "Zawgyi Font" (这是另一种缅甸字体和 we should never use this。) 并嵌入到 pdf 中。这不是一个好的解决方案,我们不能保证所有 unicode 都正确转换为 Zawgyi-One 字体字符串,我不想将 unicode 文本转换为非标准文本。这就是为什么我不想使用这种方式。

用 Itext 编辑了 ZawGyi 字体

有些文本也无法使用 itext 正确呈现。例如:辛尼

我也遇到了同样的问题。但我将 thymeleaf 与 iText 一起使用。我使用该语言的 ttf 字体包(不是 unicode)并使用转换器将 unicode 转换为我的语言并将其作为普通字符串附加到 PDF 中。它就像一个魅力。如果你有可能使用 thymeleaf,试试这个方法。

放在 CSS 下方的样式标签内。

@font-face {
    font-family: 'myfont-family';
    src: url('/fonts/myfont.ttf');
    -fs-pdf-font-embed: embed;
    -fs-pdf-font-encoding: Identity-H;
}

.mylanguage{
    font-family: 'myfontfamily';
}

<p class="mylanguage">your converted font text</p>

Java 生成 pdf 的代码。

context.setVariable("myvariable", myvariable);
String html = templateEngine.process("mypdf", context);
html = templateEngine.process("mythymeleaf", context);
String fileName = "myfile.pdf";
PDFEncryption pdfEncryption  = new PDFEncryption();
String password = "0000";
pdfEncryption.setUserPassword(password.getBytes());

ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.setPDFEncryption(pdfEncryption);
renderer.createPDF(outputStream);
outputStream.flush();
outputStream.close();

这里是关于此方法的完整教程的link,其中包含有效的源代码。 https://medium.com/@natsucoder/create-pdf-in-different-language-fonts-using-spring-boot-thymeleaf-itext-cba7f8612c61

(全面披露:我在 iText Software 工作。)

iText 5 不支持对缅甸书写系统进行正确的基于 Unicode 的处理。尽管 iText 5 具有针对阿拉伯语的特定实现,但其字体基础结构的固有局限性阻碍了对各种其他书写系统所需的字体功能的支持。

iText 7 通过新的字体实现和可选模块(pdfCalligraph,非开源)对此进行了改进,以支持不同的书写系统。但是,(还)不支持缅甸。

相应的 iText 7 代码如下所示:

PdfWriter writer = new PdfWriter(baos);
PdfDocument pdfdoc = new PdfDocument(writer);
Document doc = new Document(pdfdoc);

PdfFont f = PdfFontFactory.createFont("/fonts/NotoSansMyanmar-Regular.ttf",
    PdfEncodings.IDENTITY_H, true);

String textStr =
    "သီဟိုဠ်မှ ဉာဏ်ကြီးရှင်သည်အာယုဝဎ္ဍနဆေးညွှန်းစာကို ဇလွန်ဈေးဘေးဗာဒံပင်ထက် အဓိဋ္ဌာန်လျက် ဂဃနဏဖတ်ခဲ့သည်။";
// Explicit writing system
//doc.add(new Paragraph(textStr).setFont(f).setFontScript(Character.UnicodeScript.MYANMAR));
// Rely on autodetection
doc.add(new Paragraph(textStr).setFont(f));
doc.close();

无论是否使用pdfCalligraph,渲染依然出错:

如果您可以选择商业许可,请提交此功能请求。仍在积极添加其他书写系统。如果没有,恐怕 iText 无法做到这一点,您将不得不寻找其他解决方案。