【问题标题】:Flying Saucer font for unicode charactersUnicode 字符的飞碟字体
【发布时间】:2012-10-01 08:51:41
【问题描述】:

我正在使用 Grails 导出插件(基本上是飞碟)生成 PDF。我的 GSP 页面是一个 UTF-8 页面(或者至少属性显示它是 UTF-8,在 GSP 页面的开头也有一个 <?xml version="1.0" encoding="UTF-8"?> 指令)。最初生成的 PDF 正确包含变音字符“äöüõ”,但 PDF 中缺少西里尔字符(根本没有呈现)。然后我通过添加以下内容更改了我的 css 文件,如文档中所述:

@font-face {
    src: url(ARIALUNI.TTF);
    -fs-pdf-font-embed: embed;
    -fs-pdf-font-encoding: UTF-8;
}
body {
      font-family: "Arial Unicode MS", Arial, sans-serif;
}

ArialUni.ttf 也部署到服务器。但现在我将变音字符和西里尔字符都呈现为框。如果我将 -fs-pdf-encoding 属性值更改为 Identity-H,则元音变音字符会正确呈现,但西里尔字符会呈现为问号。

对于可以使用什么字体来正确渲染变音符号和西里尔字符有什么想法吗?或者可能是我的 CSS 有点错误?任何提示将不胜感激。

更新 1: 我也尝试了以下css(由http://fontface.codeandmore.com/生成):

@font-face {
    font-family: 'ArialUnicodeMS';
    src: url('arialuni.ttf');
    src: url('arialuni.eot?#iefix') format('embedded-opentype'),
        url('arialuni.woff') format('woff'),
        url('arialuni.ttf') format('truetype'),
        url('arialuni.svg#arialuni') format('svg');
    font-weight: normal;
    font-style: normal;
    -fs-pdf-font-embed: embed;
    -fs-pdf-font-encoding: UTF-8;
}

body {
    font-family:'ArialUnicodeMS';
}

我添加了<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 我还尝试使用 -Dfile.encoding=UTF-8 运行 grails,正如这里提到的:http://grails.1312388.n4.nabble.com/PDF-plugin-Having-problems-with-instalation-td2297840.html,但没有任何帮助。西里尔字符根本不显示。任何其他想法可能是什么问题?

*顺便说一句:*我将我的 PDF 打包为 zip 并在响应中将其发送回浏览器:

response.setHeader "Content-disposition", "attachment; filename=test.zip"
response.setHeader "Content-Encoding", "UTF-8"
response.contentType = 'application/zip'
response.outputStream << zip
response.outputStream.flush()
response.outputStream.close()

我是否需要在压缩时以某种方式考虑编码????,我确实喜欢这样:

public static byte[] zipBytes(Map<String, ByteArrayOutputStream> fileNameToByteContentMap) throws IOException {
        ByteArrayOutputStream zipBaos = new ByteArrayOutputStream();
        ZipOutputStream zos = new ZipOutputStream(zipBaos);
        fileNameToByteContentMap.eachWithIndex {String fileName, ByteArrayOutputStream baos, i  ->
            byte[] content = baos.buf
            ZipEntry entry = new ZipEntry(fileName)
            entry.setSize(content.length)
            zos.putNextEntry(entry)
            zos.write(content)
            zos.closeEntry()
        }
        zos.close()
        return zipBaos.toByteArray();
    }

【问题讨论】:

  • 如果您的内容类型也定义为 UTF-8?

标签: css grails encoding pdf-generation flying-saucer


【解决方案1】:

由于某种原因,它开始使用由 face-kit-generator 生成的以下 css 和 .ttf 文件:

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

body {
    font-family: Arial Unicode MS, Lucida Sans Unicode, Arial, verdana, arial, helvetica, sans-serif;
    font-size: 8.8pt;
}

奇怪的是,如果我将字体放入某个文件夹,比如说“字体”,它会找到字体但不会呈现字符。

【讨论】:

  • -fs-pdf-font-encoding: Identity-H;是关键;它告诉 Flying Saucer 这是一种 Unicode 字体,而不是仅限于某些代码页的字体
  • 将字体放在我使用src: url('${baseUrl}/assets/ARIALUNI.TTF');的文件夹中,其中baseUrl通过grailsLinkGenerator.serverBaseURL在模型中传递
【解决方案2】:

我设法在 java 代码中“启用”unicode 字符(西里尔文或捷克文),并在我的资源中提供了真正的字体 (CALIBRI.TTF)。

import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.pdf.BaseFont; 

...
    ITextRenderer renderer = new ITextRenderer();
    URL fontResourceURL = getClass().getResource("fonts/CALIBRI.TTF");
    //System.out.println("font-path:"+fontResourceURL.getPath());

    /* HERE comes my solution: */
    renderer.getFontResolver().addFont(fontResourceURL.getPath(), 
                BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

    renderer.setDocument(doc, null);
    renderer.layout();
    baos = new ByteArrayOutputStream();
    renderer.createPDF(baos);
    baos.flush();
    result = baos.toByteArray();
...

最后,我将字体系列“Calibri”添加到文档的 css 部分:

...
<style type="text/css">
    span { font-size: 11pt; font-family: Calibri; }
...

【讨论】:

  • 我在使用此解决方案时遇到了问题。我通过使用URL fontResourceURL = getClass().getResource("/fonts/CALIBRI.TTF");(注意字体资源路径中的初始斜杠)和fontResolver.addFont(fontResourceURL.toString(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);(注意 toString 方法而不是 getPath)来修复它
  • 来自getResource 文档:If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'. Otherwise, the absolute name is of the following form: modified_package_name/name Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e'). 但是getPath() 对我来说很好。
  • 而且基本上可以直接传"fonts/CALIBRI.TTF":renderer.getFontResolver().addFont("fonts/CALIBRI.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
猜你喜欢
  • 2013-05-24
  • 2011-03-20
  • 2018-11-18
  • 1970-01-01
  • 2018-03-22
  • 2014-01-03
  • 2023-04-07
  • 2013-07-30
  • 2020-04-05
相关资源
最近更新 更多