【问题标题】:write in unicode text on visible signature - pdfbox在可见签名上写上 unicode 文本 - pdfbox
【发布时间】:2013-07-17 10:49:11
【问题描述】:

我们使用 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字符,就会有“???”而不是文本。

这是示例 PDFlink here

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

【问题讨论】:

    标签: pdf pdfbox adobe-reader


    【解决方案1】:

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

    我假设 unicode characters 是指 Unicode 中存在的字符,而不是例如拉丁语-1。 (例如,因为字母 'a' 也有 Unicode 表示,但很可能不会给您带来麻烦。)

    您在 StringBuilder 结果上调用 getBytes("ISO-8859-1")。您的 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) 当我删除字体时,文本仍然存在(当文本是英文时)。默认字体是什么?

    根据specification,第 9.3.1 节,

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

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

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

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

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

    【讨论】:

    • 我用 unicode 符号写了文本。例如 \u10D0\u10D1\u10D2\u10D3\u10D4\u10D5\u10D6\u10D7 那么当我在 pdf 中看到的结果是 "áƒáƒ‘áƒ'დევზთ" 。 adobe reader 像 ANSI 一样读取文本。我将该结果字符串转换为 UTF-8,它是原始的 unicode 文本。
    • Adobe Reader 使用的字体似乎确实使用了 WinAnsiEncoding。 这显然将您限制为 WinAnsi 字符集。还有一个更一般的说明:正如我在对@Joop 的回答的评论中已经提到的那样,我建议不要尝试手动完成所有这些操作,而是使用已经提供您需要的库。我不确定 PDFBox 目前是否可以。它确实缺少有关具有良好可视化的集成签名的文档。
    • 它使用 Ansi 编码。我已经看过了。是的,但最后一步。我几乎做了所有事情,除了:-)
    【解决方案2】:

    广告 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 中的一些特殊字符丢失为 ?

    【讨论】:

    • 我已经用 UTF-8 进行了更改,但还有一些其他字符。可能是因为没有引用我的字体目录。
    • 如果问题是如何使用 UTF-8 编码序列化字符串,那将是解决方案。但是,实际的问题是不同的,它是将其序列化为具有混合编码的 PDF 流。
    • @mki 我知道 PDF 的内在特性(例如 Base 96)。所有这些你都很好地呈现出来。然而,问号问题很容易解决,因为它是由 java 中的转换产生的。我非常喜欢您的专业知识;你可以让它更“用户友好”,建设性的交付解决方案——我做不到。
    • 建设性的交付解决方案在这里有点困难,因为 PDF 流和字体不是微不足道的东西。本质上,我对@LadyBird 的建议是 手动构建此类内容流,而是使用可以的库。我不知道 PDFBox 是否适合创建具有良好可视化效果的集成 PDF 签名。前几天有个用户 GNUCIOUS 也试过了,好像不太成功……
    • @AVA 最近添加到 PDFBox 的是包org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible;有一个使用它的例子:CreateVisibleSignature。我还没有尝试过它,因此无法确定它是否已经准备好用于生产。
    猜你喜欢
    • 1970-01-01
    • 2014-10-20
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    相关资源
    最近更新 更多