在可见签名上写下unicode文本 - pdfbox

时间:2013-07-17 10:49:12

标签: pdf pdfbox adobe-reader

我使用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字符,那就是“???”而不是text。

示例PDF link here

问题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)如何计算可见签名中文本的宽度?有什么想法吗?

2 个答案:

答案 0 :(得分:1)

  

问题1)当我看到PDF结构时,有问号而不是文字。是。我不知道怎么用unicode字符写?

我假设使用 unicode characters 表示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 ,或完全自定义。此外,在许多情况下,这些编码限制为每个字符一个字节,但在复合字体的情况下,它们也可以是多字节编码。

作为必然结果,并非所有流元素的元素都需要使用相同的编码进行编码。例如。运营商名称 Tm Tf Tj 使用其ASCII码进行编码,而要显示的字符串的字符必须使用相应字体的编码(如果在尖括号中添加,则可以再次进行十六进制编码&lt;&gt;)。

因此,将流创建为字符串然后使用单个编码将它们转换为字节只有在所有使用的字体使用相同的编码(对于实际使用的代码点)时才有效,这些编码还需要ASCII'ish才能正确表示经营者。

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

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

  

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

在有问题的流xobject的资源中,只有一个嵌入字体与名称 / F0 相关联。但是,在您的信息流中,您有 / F1 2 Tf ,即您在大小2中选择字体 / F1

  

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

根据specification,第9.3.1节,

  

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

但最有可能的是,PDF查看器为了与旧文档或损坏文档兼容而使用某些默认字体。

  

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

宽度显然取决于所用字体的指标(本例中为字形宽度)和您设置的图形状态(字体大小,字符间距,字间距,当前转换矩阵,文本转换矩阵......)。

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

答案 1 :(得分: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 ?中缺少一些特殊字符。