飞碟字体用于Unicode字符

12

我正在使用Grails导出插件(基本上是Flying Saucer)生成PDF。我的GSP页面是UTF-8页面(或者至少属性显示它是UTF-8,另外在GSP页面的开头有一个<?xml version="1.0" encoding="UTF-8"?>指令)。最初生成的PDF文件包含umlaut字符 "äöüõ",但Cyrillic字符在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"/>,同时也尝试了在运行 grails 时加上 -Dfile.encoding=UTF-8 参数,如此处所述:http://grails.1312388.n4.nabble.com/PDF-plugin-Having-problems-with-instalation-td2297840.html,但是没有任何帮助。 其中的 Cyrillic 字符根本不显示。还有其他想法吗?

*顺便说一句:* 我正在将我的 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();
    }

你的 content-type 是否也定义为 UTF-8? - Diodeus - James MacFarlane
2个回答

16

我成功地在Java代码中“启用”了Unicode字符(西里尔文或捷克文),并在我的资源文件中提供了一个True Type字体(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();
...

最后,我在文档的 CSS 部分中添加了字体 'Calibri':

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

1
我在使用这个解决方案时遇到了问题。我通过使用 URL fontResourceURL = getClass().getResource("/fonts/CALIBRI.TTF");(请注意字体资源路径中的初始斜杠)和 fontResolver.addFont(fontResourceURL.toString(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);(请注意使用 toString 方法而不是 getPath)来解决它。 - Maciej Łoziński
getResource 文档中:如果名称以 '/' ('\u002f') 开头,则资源的绝对名称是跟在 '/' 后面的部分。 否则,绝对名称的格式如下: modified_package_name/name 其中 modified_package_name 是此对象的包名称,'.' ('\u002e') 替换为 '/'。但是 getPath() 对我来说很好用。 - Wojtek Okoński
基本上,“fonts/CALIBRI.TTF” 可以直接传递:renderer.getFontResolver().addFont("fonts/CALIBRI.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); - Wojtek Okoński

13

由于某种原因,它开始使用以下 CSS 和 .ttf 文件工作,这些文件是由 face-kit-generator 生成的:

@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;
}
奇怪的是,如果我把字体放到某个文件夹里,比如说“fonts”,它会找到字体,但字符不会被渲染。

6
"-fs-pdf-font-encoding: Identity-H;" 是关键,它告诉Flying Saucer这是一种Unicode字体,而不是限定于特定代码页的字体。 - jaygooby
为将字体放入文件夹中,我使用了 src: url('${baseUrl}/assets/ARIALUNI.TTF'); ,其中 baseUrl 是通过 grailsLinkGenerator.serverBaseURL 在模型中传递的。 - fego

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接