我使用一个应用程序将注释从fdf文件添加到Pdf文件有了iText可以这样做
FdfReader aFdfReader = new FdfReader(new FileInputStream(args[0]));
PdfReader aReader = new PdfReader(new FileInputStream(args[1]));
PdfStamper aStamper = new PdfStamper(aReader, new FileOutputStream(args[2]));
aStamper.addComments(aFdfReader);
aStamper.close();
但是当我加载fdf时,我会出现这个异常。fdf有一个带有类型附件文件的注释。
线程"main"com.itextpdf.text.exceptions.InvalidPdfException中的异常:读取文件指针5106590处的字符串时出错网址:com.itextpdf.text.pdf.PRTokeniser.throwError(PRTokeiser.java:220)网址:com.itextpdf.text.pdf.PRTokeniser.nextToken(PRTokeniser.java:411)网址:com.itextpdf.text.pdf.PRTokeniser.nextValidToken(PRTokeniser.java:282)网址:com.itextpdf.text.pdf.PdfReader.readPRObject(PdfReader.java:1908)网址:com.itextpdf.text.pdf.PdfReader.readArray(PdfReader.java:1891)网址:com.itextpdf.text.pdf.PdfReader.readPRObject(PdfReader.java:1946)网址:com.itextpdf.text.pdf.PdfReader.readDictionary(PdfReader.java:1877)网址:com.itextpdf.text.pdf.PdfReader.readPRObject(PdfReader.java:11913)网址:com.itextpdf.text.pdf.PdfReader.readDocObj(PdfReader.java:1411)网址:com.itextpdf.text.pdf.FdfReader.readPdf(FdfReader.java:105)网址:com.itextpdf.text.pdf.PdfReader.(PdfReader.java:181)网址:com.itextpdf.text.pdf.PdfReader.(PdfReader.java:395)网址:com.itextpdf.text.pdf.PdfReader.(PdfReader.java:415)网址:com.itextpdf.text.pdf.FdfReader.(FdfReader.java:92)网址:com.arteys.pdf.itext.pdf.AddFdf.main(AddFdf.java:18)
我用itext_so.pdf进行测试,以附加到注释
如果我用问候语做了测试,我的效果很好
我使用了版本5.5.9
提前感谢您的回复
问候
Fabien
FDF是特别的,因为它在流中包含PDF;该PDF流是部分未压缩的;因此,PDF语法,特别是PDF间接对象的开头是可见的。
FdfReader
工作不正确:它假设流内容中间接对象的这些开始是顶级FDF对象,在尝试读取这些对象时启动并失败。
可以通过使FdfReader
对象读取更宽容来快速解决此问题。
FDF
你的FDF是这样的:
%FDF-1.2
%âãÏÓ
1 0 obj
<</FDF<</Annots[2 0 R]/F(http://localhost:8780/PachaServer/downloadpacha?pathpdf=Rendition.pdf&edit=false&loginname=fhfgh)/ID[<2175D5400E41761374A2EB01E7026C68><5E9C3BFFF121CE737ED66FF7318CA58D>]/UF(http://localhost:8780/PachaServer/downloadpacha?pathpdf=Rendition.pdf&edit=false&loginname=fhfgh)>>/Type/Catalog/Version/1.6>>
endobj
2 0 obj
<</C[0.25 0.333328 1.0]/Contents(itext_so.pdf)/CreationDate(D:20160519150439+02'00')/F 28/FS 3 0 R/M(D:20160519150439+02'00')/NM(79bcf116-d9bd-4ade-a8cd-7575351271fd)/Name/Paperclip/Page 0/RC(<?xml version="1.0"?><body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/" xfa:APIVersion="Acrobat:15.16.0" xfa:spec="2.0.2" ><p>itext_so.pdf</p></body>)/Rect[183.106 684.663 190.106 701.663]/Subj(Pièce jointe)/Subtype/FileAttachment/T(Fabien.Levalois)/Type/Annot>>
endobj
3 0 obj
<</EF<</F 4 0 R>>/F(itext_so.pdf)/Type/Filespec/UF(itext_so.pdf)>>
endobj
4 0 obj
<</DL 10536008/Filter/FlateDecode/Length 10207532/Params<</CheckSum("}þ¶îô/Óý‡†d’ÒÎ)/CreationDate(D:20160511112202+02'00')/ModDate(D:20160511112205+02'00')/Size 10536008>>/Subtype/application#2Fpdf>>stream
... [10207532 data bytes] ...
endstream
endobj
trailer
<</Root 1 0 R>>
%%EOF
这种结构是正确的。但大流的内容,即对象4中的10207532个数据字节是特殊的:它们构成了一个PDF文档,由于该文档已经被压缩,当嵌入到FDF中时,它部分无法进一步压缩,原始PDF语法变得分段可见,例如,流中的大约660000个字节突然出现了表示当前PDF流的结束和另一个间接PDF对象的开始的字节序列
endstream
endobj
10283 0 obj
<</Extends 10282 0 R/Filter/FlateDecode/First 1139/Length 4195/N 100/Type/ObjStm>>stream
...
endstream
endobj
10284 0 obj
<</Extends 10282 0 R/Filter/FlateDecode/First 1139/Length 4018/N 100/Type/ObjStm>>stream
...
endstream
endobj
10285 0 obj
<</Extends 10282 0 R/Filter/FlateDecode/First 190/Length 1001/N 18/Type/ObjStm>>stream
等等。等等。
然而,由于这些PDF对象只是分段可见的,因此尝试按原样读取它们可能会导致错误。
FdfReader
由于FDF不需要包含交叉引用部分,FdfReader
作为第一步,试图通过在文件中搜索似乎是间接对象开始的字节序列来创建交叉引用部分。
然而,这是不正确的,因为在像FDF这样的情况下,它会创建许多错误的交叉引用条目,并且在读取这些错误的间接对象时,除非错误对象在语法上正确,否则会发生错误。
在PDF的情况下,许多错误对象在语法上是正确的,直到错误间接对象被部分重新压缩的异常中提到的偏移5106590附近的位置。当尝试读取时,FdfReader
抛出您观察到的异常。
但问题不仅在于这样的语法错误(毕竟这些错误可能会被捕获并忽略),还在于假对象和真对象可能具有相同的对象编号。因此,FdfReader
可能使用假对象而不是真对象!
快速解决方案
虽然FdfReader
的交叉引用重建代码从根本上必须重新实现才能实现真正的修复,但它有一个快速的修复方法,允许它正确处理"假FDF对象"与真FDF对象不冲突的FDF,只需从FdfReader
派生一个类,并覆盖方法readPRObject()
,如下所示:
@Override
protected PdfObject readPRObject() throws IOException
{
try
{
return super.readPRObject();
}
catch (InvalidPdfException e)
{
return PdfNull.PDFNULL;
}
}
(ImprovedFdfReader.java)
当使用具有正常FdfReader
的ReadFdf.java测试方法testReadFdfFabienLevalois
读取所提供的FDF itext-SO.FDF失败时,使用具有ImprovedFdfReader
的测试方法testReadFdfFabienLevaloisImproved
进行读取成功。