1

我使用 PDFBox 构建 PDF。我也有可见的签名。我写了一些这样的文字:

...
builderSting.append("Tm\n");
builderSting.append(" /F1 " + fontSize + "\n");
builderSting.append("Tf\n");
builderSting.append("(hello world)");
builderSting.append("Tj\n");
builderSting.append("ET");
...
PDStream stream= ...;
stream.createOutputStream().write(builder.toString().getBytes("ISO-8859-1"));

一切正常。但是如果我在builderString中写了一些unicode字符,就会有“???”而不是文本。

这是示例 PDF链接在这里

问题 1)当我看到 PDF 结构时,有问号而不是文本。是的。而且我不知道如何用 unicode 字符编写?

9 0 obj
<<
/Type /XObject
/Subtype /Form
/BBox [100 50 0 0]
/Matrix [1 0 0 1 0 0]
/Resources <<
/Font 11 0 R
/XObject <<
/img0 12 0 R
>>
/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
>>
/FormType 1
/Length 13 0 R
>>
stream
q 93.70079 0 0 50 0 0 cm /img0 Do Q
BT
1 0 0 1 93.70079 25 Tm
 /F1 2
Tf
(????)Tj
ET
endstream
endobj

我有 Encoding WinAsciEncoding 的字体。我可以在 pdfbox 中使用另一种编码吗?

PDFont font = PDTrueTypeFont.loadTTF(template, new File("//fontName.ttf"));
    font.setFontEncoding(new WinAnsiEncoding());

问题 2)我在 PDF 中嵌入了字体。但是文本不是用这种字体写的(在可见的签名矩形中)。为什么?

问题 3) 当我删除字体时,文本仍然存在(当文本是英文时)。默认字体是什么? /F1 - 这是第一种字体?

问题 4)如何计算可见签名中文本的宽度?有任何想法吗?

4

2 回答 2

1

问题 1)当我看到 PDF 结构时,有问号而不是文本。是的。而且我不知道如何用 unicode 字符编写?

我假设对于unicode 字符,您的意思是 Unicode 中存在的字符,而不是例如 Latin-1 中的字符。(例如,因为字母“a”也有 Unicode 表示,但很可能不会给您带来麻烦。)

你呼吁getBytes("ISO-8859-1")你的StringBuilder结果。您的unicode 字符 很可能不在 ISO 8859-1 中。因此,String.getBytes在各自的位置返回问号的 ASCII 代码。

如果问题仅仅是如何在 Java 中使用 unicode 字符写入输出流,那么答案将很简单:选择包含所有字符的编码,例如 UTF-8,您的程序的所有消费者都支持,然后String.getBytes调用编码。

但是,手头的情况有所不同,因为您希望将这些信息序列化为 PDF 表单 xobject 流。在这种情况下,您的整个方法处于从高度可疑到完全错误的路线上:

在 PDF 中,每种字体都可能带有自己的编码,这可能类似于常见的编码,例如/WinAnsiEncoding,或者完全自定义。此外,这些编码在许多情况下仅限于每个字符一个字节,但在复合字体的情况下,它们也可以是多字节编码。

作为推论,并非流元素的所有元素都需要使用相同的编码进行编码。例如,运算符名称TmTfTj使用它们的 ASCII 代码进行编码,而要显示的字符串的字符必须使用相应字体的编码进行编码(如果添加在尖括号中,则可能随后再次进行十六进制编码 < >)。

因此,仅当所有使用的字体都使用相同的编码(对于实际使用的代码点)并且需要是 ASCII'ish 才能正确表示运算符时,将流创建为字符串然后将它们转换为具有单一编码的字节才有效。

本质上,您应该直接在某个字节缓冲区中构造流,并为每个插入的元素使用适当的编码。因此,如果要显示字符,您必须了解当前所选字体使用的编码。

如果你想把它做好,首先研究 PDF 规范ISO 32000-1,特别是关于一般语法和第 9 章文本的部分。

问题 2)我在 PDF 中嵌入了字体。但是文本不是用这种字体写的(在可见的签名矩形中)。为什么?

在所讨论的流 xobject 的资源中,只有一种嵌入字体与名称/F0相关联。但是,在您的流中,您有/F1 2 Tf,即您选择大小为 2 的字体/F1

问题 3)当我删除字体时,文本仍然存在(当文本是英文时)。默认字体是什么?

根据规范,第 9.3.1 节,

font应该是当前资源字典的Font子字典中字体资源的名称[...] 字体或大小都没有初始值

不过,为了与旧的或损坏的文档兼容,PDF 查看器很可能会使用一些默认字体。

问题 4)如何计算可见签名中文本的宽度?有任何想法吗?

宽度显然取决于所用字体的度量(在这种情况下为字形宽度)和您设置的图形状态(字体大小、字符间距、字间距、当前转换矩阵、文本转换矩阵......)。

在您的情况下,您几乎不会在图形状态下做任何事情,因此,只有从中选择的字体大小是感兴趣的。所以更有趣的部分是字体度量中的字符宽度。只要您使用标准的 14 种字体,您就可以在此处找到指标。一旦您开始使用其他自定义字体,您必须自己从字体定义文件中读取它们。

于 2013-07-17T13:22:33.860 回答
0

广告 1)

难道是这样

stream.createOutputStream().write(builder.toString().getBytes("ISO-8859-1"));

应该

stream.createOutputStream().write(builderString.toString().getBytes("UTF-8"));

getBytes 到 ISO-8859-1 的转换会使 ISO-8859-1 a 中缺少一些特殊字符?

于 2013-07-17T12:50:16.727 回答