我正在尝试使用视觉签名和pdfBox制作PDF.我有两个流,似乎pdfBox只能处理文件.没有三个临时文件,我没有设法让它工作.我可以从
here看到API已经改变,但它仍处理文件.
public void signPdf(InputStream originalPdf,OutputStream signedPdf,InputStream image,float x,float y,String name,String location,String reason) { File temp = null; File temp2 = null; File scratchFile = null; RandomAccessFile randomAccessFile = null; OutputStream tempOut = null; InputStream tempIn = null; try { /* Copy original to temporary file */ temp = File.createTempFile("signed1",".tmp"); tempOut = new FileOutputStream(temp); copyStream(originalPdf,tempOut); tempOut.close(); /* Read temporary file to second temporary file and stream */ tempIn = new FileInputStream(temp); temp2 = File.createTempFile("signed2",".tmp"); tempOut = new FileOutputStream(temp2); copyStream(tempIn,tempOut); tempIn.close(); tempIn = new FileInputStream(temp2); scratchFile = File.createTempFile("signed3",".bin"); randomAccessFile = new RandomAccessFile(scratchFile,"rw"); /* Read temporary file */ PDDocument document = PDDocument.load(temp,randomAccessFile); document.getCurrentAccessPermission().setCanModify(false); PDSignature signature = new PDSignature(); signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED); signature.setName(name); signature.setLocation(location); signature.setReason(reason); signature.setSignDate(Calendar.getInstance()); PDVisibleSignDesigner signatureDesigner = new PDVisibleSignDesigner( document,image,document.getNumberOfPages()); signatureDesigner.xAxis(250).yAxis(60).zoom(-90).signatureFieldName("signature"); PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties(); signatureProperties.signerName(name).signerLocation(location) .signatureReason(reason).preferredSize(0).page(1) .visualSignEnabled(true).setPdVisibleSignature(signatureDesigner) .buildSignature(); SignatureOptions options = new SignatureOptions(); options.setVisualSignature(signatureProperties); document.addSignature(signature,dataSigner,options); /* Sign */ document.saveIncremental(tempIn,tempOut); document.close(); tempIn.close(); /* Copy temporary file to an output stream */ tempIn = new FileInputStream(temp2); copyStream(tempIn,signedPdf); } catch (IOException e) { logger.error("PDF signing failure",e); } catch (COSVisitorException e) { logger.error("PDF creation failure",e); } catch (SignatureException e) { logger.error("PDF signing failure",e); } finally { closeStream(originalPdf); closeStream(signedPdf); closeStream(randomAccessFile); closeStream(tempOut); deleteTempFile(temp); deleteTempFile(temp2); deleteTempFile(scratchFile); } } private void deleteTempFile(File tempFile) { if (tempFile != null && tempFile.exists() && !tempFile.delete()) { tempFile.deleteOnExit(); } } private void closeStream(Closeable is) { if (is!= null) { try { is.close(); } catch (IOException e) { logger.error("failure",e); } } } private void copyStream(InputStream is,OutputStream os) throws IOException { byte[] buffer = new byte[1024]; int c; while ((c = is.read(buffer)) != -1) { os.write(buffer,c); } is.close(); }
当我用itext库做类似的事情时,这就是它的外观
解决方法
为什么视觉签名表示中缺少名称,位置和原因?
他们不在那里,因为他们没有画画.
iText表示可视化签名的默认方式是将这些信息添加到可视化中.
PDFBox’PDVisibleSigBuilder表示可视化签名的默认方式是没有这些信息.
既不是错误的也不是正确的,两者都只是默认值.
人们应该寻找这些信息的规范场所毕竟是签名小组.
我该如何解决这个问题?
签名可视化的实际内容由signatureProperties.buildSignature()期间的PDVisibleSigBuilder实例创建:
public void buildSignature() throws IOException { PDFTemplateBuilder builder = new PDVisibleSigBuilder(); PDFTemplateCreator creator = new PDFTemplateCreator(builder); setVisibleSignature(creator.buildPDF(getPdVisibleSignature())); }
因此,通过更换
signatureProperties.signerName(name).signerLocation(location) .signatureReason(reason).preferredSize(0).page(1) .visualSignEnabled(true).setPdVisibleSignature(signatureDesigner) .buildSignature();
在你的代码中
signatureProperties.signerName(name).signerLocation(location) .signatureReason(reason).preferredSize(0).page(1) .visualSignEnabled(true).setPdVisibleSignature(signatureDesigner); PDFTemplateBuilder builder = new ExtSigBuilder(); PDFTemplateCreator creator = new PDFTemplateCreator(builder); signatureProperties.setVisibleSignature(creator.buildPDF(signatureProperties.getPdVisibleSignature()));
对于这个PDVisibleSigBuilder类的自定义版本ExtSigBuilder,你可以在那里绘制任何你想要的东西,例如:
class ExtSigBuilder extends PDVisibleSigBuilder { String fontName; public void createImageForm(PDResources imageFormResources,PDResources innerFormResource,PDStream imageFormStream,PDRectangle formrect,AffineTransform affineTransform,PDJpeg img) throws IOException { super.createImageForm(imageFormResources,innerFormResource,imageFormStream,formrect,affineTransform,img); PDFont font = PDType1Font.HELVETICA; fontName = getStructure().getImageForm().getResources().addFont(font); logger.info("Added font to image form: " + fontName); } public void injectAppearanceStreams(PDStream holderFormStream,PDStream innterFormStream,String imageObjectName,String imageName,String innerFormName,PDVisibleSignDesigner properties) throws IOException { super.injectAppearanceStreams(holderFormStream,innterFormStream,imageObjectName,imageName,innerFormName,properties); String imgFormComment = "q " + 100 + " 0 0 50 0 0 cm /" + imageName + " Do Q\n"; String text = "BT /" + fontName + " 10 Tf (Hello) Tj ET\n"; appendRawCommands(getStructure().getImageFormStream().createOutputStream(),imgFormComment + text); logger.info("Added text commands to image form: " + text); } }
在Helvetica中写入“Hello”,大小为10,位于图像形式的左下方(实际显示的形式).
PS:在我看来,这背后的面向对象结构应该彻底改革.