我想在不使用临时文件的情况下从PDF文件中签署一个InputStream 在这里,我将InputStream转换为File,这很好用:
InputStream inputStream = this.signatureObjPAdES.getSignatureDocument().getInputStream();
OutputStream outputStream = new FileOutputStream(new File("C:/temp.pdf"));
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
PDDocument document = PDDocument.load(new File("C:/temp.pdf"));
...
document.addSignature(new PDSignature(this.dts.getDocumentTimeStamp()), this);
document.saveIncremental(new FileOutputStream("C:/result.pdf");
document.close();
但我想直接这样做:
PDDocument document = PDDocument.load(inputStream);
问题:在运行
Exception in thread "main" java.lang.NullPointerException
at java.io.RandomAccessFile.<init>(Unknown Source)
at org.apache.pdfbox.io.RandomAccessBufferedFileInputStream.<init>(RandomAccessBufferedFileInputStream.java:77)
at org.apache.pdfbox.pdmodel.PDDocument.saveIncremental(PDDocument.java:961)
欢迎所有想法。
谢谢。
编辑: 它现在正在发布PDFBox 2.0.0。
答案 0 :(得分:3)
直接障碍在方法PDDocument.saveIncremental()
本身:
public void saveIncremental(OutputStream output) throws IOException { InputStream input = new RandomAccessBufferedFileInputStream(incrementalFile); COSWriter writer = null; try { writer = new COSWriter(output, input); writer.write(this, signInterface); writer.close(); } finally { if (writer != null) { writer.close(); } } }
第一行中使用的成员incrementalFile
仅在具有PDDocument.load
参数的File
期间设置。
因此,不能使用此方法。
幸运的是,方法PDDocument.saveIncremental()
仅使用公开提供的方法和值,但signInterface
除外,但您知道它的价值,因为您在代码之前的代码中设置了它{1}}致电:
saveIncremental
因此,您可以在代码中执行等效操作,而不是调用document.addSignature(new PDSignature(this.dts.getDocumentTimeStamp()), this);
document.saveIncremental(new FileOutputStream("C:/result.pdf"));
。
为此,您还需要PDDocument.saveIncremental()
的替换值。它需要在
InputStream input
相同内容的流
inputStream
所以你需要两次使用那个流。由于您尚未说明是否可以重置PDDocument document = PDDocument.load(inputStream);
,我们会先将其复制到inputStream
,我们会将其转发到byte[]
和PDDocument.load
。
因此,请替换
new COSWriter
通过
PDDocument document = PDDocument.load(inputStream);
...
document.addSignature(new PDSignature(this.dts.getDocumentTimeStamp()), this);
document.saveIncremental(new FileOutputStream("C:/result.pdf"));
document.close();
并根据原始byte[] inputBytes = IOUtils.toByteArray(inputStream);
PDDocument document = PDDocument.load(new ByteArrayInputStream(inputBytes));
...
document.addSignature(new PDSignature(this.dts.getDocumentTimeStamp()), this);
saveIncremental(new FileOutputStream("C:/result.pdf"),
new ByteArrayInputStream(inputBytes), document, this);
document.close();
的灵感为您的课程添加新方法saveIncremental
:
PDDocument.saveIncremental()
我上面说过
由于您尚未说明
void saveIncremental(OutputStream output, InputStream input, PDDocument document, SignatureInterface signatureInterface) throws IOException { COSWriter writer = null; try { writer = new COSWriter(output, input); writer.write(document, signatureInterface); writer.close(); } finally { if (writer != null) { writer.close(); } } }
是否可以重置,我们会先将其复制到inputStream
,我们会将其转发至byte[]
和PDDocument.load
实际上还有另外一个原因:new COSWriter
检索原始PDF的长度,如下所示:
COSWriter.doWriteSignature()
long inLength = incrementalInput.available();
州的文件:
请注意,虽然
InputStream.available()
的某些实现将返回流中的总字节数,但许多实现不会。
要重复使用InputStream
而不是使用上述inputStream
和byte[]
,因此,ByteArrayInputStream
不仅需要支持inputStream
,还需要支持reset()
需要成为少数InputStream
实现之一,它将流中的总字节数返回为available
。
FileInputStream
和ByteArrayInputStream
都会将流中的总字节数返回为available
。
使用通用InputStream
而不是这两个时,可能还会有更多问题。
答案 1 :(得分:1)
嘿Cyril Bremaud,你可以使用这种方法,因为PDDocument
类有3个重载的构造函数,你可以继续只提供文件路径,如果你喜欢它也可以工作。但是,为了能够将InputStream
直接传递给PDDocument
构造函数,请使用以下代码:
lStrInputPDFfile = "samples_pdf_signing\Country Calendar.pdf";
lOsPDFInput = new java.io.FileInputStream(lStrInputPDFfile);
jPDFDocument = new org.apache.pdfbox.pdmodel.PDDocument().load(lOsPDFInput);
但这也适用于我的情况:
lStrInputPDFfile = "samples_pdf_signing\Country Calendar.pdf";
jPDFDocument = new org.apache.pdfbox.pdmodel.PDDocument().load(lStrInputPDFfile);
注意:`InputStream是FileInputStream的父类,这就是上述代码的工作原理。
更新了我的代码,请再次检查。感谢@mkl指出了这一点。