当前位置: 首页 > 知识库问答 >
问题:

使用PDFBox编辑pdf中的内容会删除pdf中的最后一行

暴向笛
2023-03-14

我正在尝试用Java中的PDFBox编辑pdf的一些内容。问题是,每当我编辑pdf中的任何字符串,并尝试使用Adobe Reader打开它时,最后一行不会出现在新呈现的pdf中。

当我尝试直接从浏览器顶部打开渲染的pdf时,我能够看到最后一行。但是,它以不同的格式编码。我正在使用以下代码编辑pdf的内容:

PDDocument doc = PDDocument.load(FileName);
PDPage page = (PDPage) doc.getDocumentCatalog().getAllPages().get(0);
PDStream contents = page.getContents();
PDFStreamParser parser = new PDFStreamParser(contents.getStream());
parser.parse();
List<Object> tokens = parser.getTokens();
for (int j = 0; j < tokens.size(); j++) {
    Object next = tokens.get(j);
    if (next instanceof PDFOperator) {
        PDFOperator op = (PDFOperator) next;
        if (op.getOperation().equals("Tj")) {
            COSString previous = (COSString) tokens.get(j - 1);
            String string = previous.getString();

            string = string.replace("@ordnum&", (null != data.getOrderNumber()?data.getOrderNumber():""));
            string = string.replace("@shipid&", (null != data.getShipmentId()?data.getShipmentId():""));
            string = string.replace("@customer&", (null != data.getCustomerNumber()?data.getCustomerNumber():""));
            string = string.replace("@fromname&", (null != data.getFromName()?data.getFromName():""));

            tokens.set(j - 1, new COSString(string.trim()));
        }
    }
}

编辑pdf会删除“有问题?...”这一行。这里有什么问题?我做错了什么吗?

谢谢。

共有1个答案

冯枫涟
2023-03-14

首先,你必须意识到PDF中字符串有两种根本不同的情况

  • 外部内容流,例如文档属性的作者和关键字,以及
  • 内部内容流表示要绘制的某些字体的字形序列。

前一种类型使用PDFDocEncoding(类似于Latin1)或带有前导字节顺序标记的UTF-16BE进行编码。方法costring。getString和构造函数CoString(String)是为这种字符串设计的。

后一种类型使用为该字符串要呈现的PDF字体定义的编码进行编码。这可能是一些标准化的编码,比如WinAncienceODing(类似于Latin1)或UniGB-UTF16-H(Adobe-GB1字符集的Unicode(UTF-16BE)编码)。但它也可能是一些定制的单字节或多字节编码。标准化和自定义多字节编码都没有字节顺序标记。

在PDF中的页面内容流中,大多数字符串使用WinAnSienceODing(因为这是它们字体的编码)。因为WinPdOnCode方法和WinPdOnCode方法非常相似。

不过,最后一行是使用Idtice-H编码的,它是2字节CID的水平标识映射,即直接引用字体程序中的字符ID的2字节编码,没有任何意义,没有该字体程序。

由于该字符串不以字节顺序标记开头,costring。getString假定它使用单字节编码PDFDocencode,因此为每个原始的双字节PDF字符串创建两个Java字符串。由于其中一些字符的字符值超出了实际有效的PDFDocEncoding范围,构造函数CoString(String)创建一个PDF字符串,其中每个中间Java字符都使用一个两字节UTF-16BE字符来表示;此外,还添加了字节顺序标记。

因此,原始PDF字符串(以十六进制编写)

002b004400590048000300540058004800560057004c0052005100560022000300260052
005100570044004600570003005800560003004400570003004b0057005700530056001d
00120012005a005a005a005600110046004c0057005500580056004f0044005100480011
004600520050001200460052005100570044004600570010005800560012

在你的编辑变成

FEFF002B0000004400000059000000480000000300000054000000580000004800000056
000000570000004C00000052000000510000005600000022000000030000002600000052
000000510000005700000044000000460000005700000003000000580000005600000003
0000004400000057000000030000004B00000057000000570000005300000056000002DB
00000012000000120000005A0000005A0000005A0000005600000011000000460000004C
000000570000005500000058000000560000004F00000044000000510000004800000011
000000460000005200000050000000120000004600000052000000510000005700000044
0000004600000057000000100000005800000056

根据PDF查看器的不同,这可能会产生不同的效果。你原来的台词

例如,可能变得传播很广:

或者彻底消失

因此,简而言之,如果需要编辑这样的PDF,请确保只编辑具有类似拉丁文1编码的PDF字符串。

如果您还需要编辑不同编码的PDF字符串,请使用CoString方法getBytes将其提取为byte[],以适用于相关编码的方式编辑此数组,并使用构造函数CoString(byte[])从编辑的字节中创建一个新的CoString

但即使这样也不是一个好主意。

还有很多其他的陷阱等着你当编辑流像那样

>

  • 而不是e. g.

    (@customer&) Tj
    

    您的流可能包含

    (@cust) Tj
    (omer&) Tj
    

    [(@cust) -6 (omer&) ] TJ 
    

    甚至

    (omer&) Tj
    -62 0 Td
    (@cust) Tj
    

    因此,如果新模板使用稍微不同的表示,突然替换可能不起作用。

    字体只能部分嵌入。如果替换字符的图示符不包括在内,它们将被绘制为间隙。

    编辑后的文本绘制操作可能会依赖于前一个操作使用了特定的宽度。你的替代品会破坏原来的布局。

    ...

    本质上,正确编辑通用文档中的流是非常困难的。

    而不是像您的@客户这样的内容占位符

    表单字段有名称,可以被它们识别。填写它们不会改变内容中的任何内容。

    如果你不想让人们事后编辑你的PDF表单字段,你可以将它们标记为只读,甚至将它们展平到内容中。

  •  类似资料:
    • 我已经实现了从pdf中删除图层的功能,但问题是,我在图层上绘制的内容无法删除。下面是我用来删除图层的代码:

    • 我需要比较PDF文档,这些文档是用iText创建的。我实际上设法比较了文件,但我发现了一个微小的差异。 当在像Notepad++这样的编辑器中打开PDF文件时,我可以看到文件末尾有这样的东西:

    • 问题内容: 链接到pdf 当我尝试从上面的pdf中提取文本时,我混合了在evince查看器中不可见的文本和可见的文本。此外,某些所需的文本缺少查看器中未缺少的字符,例如“ FALCONS”中的“ S”和许多缺少的“ 1/2”字符。我认为这是由于来自不可见文本的干扰,因为在查看器中突出显示pdf时,可以看到不可见文本与可见文本重叠。 有没有办法删除不可见的文字?还是有其他解决方案? 码: 输出(粗体

    • 链接到pdf 当我尝试从上面的pdf中提取文本时,我得到了在evince viewer中不可见的文本和可见的文本的混合。此外,一些所需的文本缺少查看器中没有缺少的字符,例如,“FALCONS”中的“S”和许多缺少的“½”字符。我认为这是由于不可见文本的干扰,因为在查看器中突出显示pdf时,可以看到不可见文本与可见文本重叠。 有没有办法去掉不可见的文字?还是有别的解决办法? 代码: 输出(粗体文本为

    • 使用QPDF,您可以简单地从PDF文件中删除限制/加密,如下所示: 我想用Java中的PDFBox做同样的事情: 我已经用尝试过了,但是我不知道所有者密码是什么。QPDF是如何做到这一点的? 示例文档: https://issues.apache.org/jira/secure/attachment/12514714/in.pdf

    • 问题内容: 全部 我正在使用IText在PDF上添加文本层。现在我想编辑PDF上的现有图层,图层也仅由IText创建。似乎IText没有支持这种方法。 我想到的另一种方法是删除现有图层并在其位置放置新图层。似乎IText也不支持删除。有什么办法吗? 非常感谢。 问题答案: 事实证明,所讨论的图层是iText确实称为图层的,但实际上在PDF术语中却称为 可选内容组。 实际上,确实存在一个实用程序类,