加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 使用pdfbox 1.8.8进行可视签名

发布时间:2020-12-14 06:06:01 所属栏目:Java 来源:网络整理
导读:我正在尝试使用视觉签名和pdfbox制作PDF.我有两个流,似乎pdfbox只能处理文件.没有三个临时文件,我没有设法让它工作.我可以从 here看到API已经改变,但它仍处理文件. public void signPdf(InputStream originalPdf,OutputStream signedPdf,InputStream image,f
我正在尝试使用视觉签名和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 Qn";
        String text = "BT /" + fontName + " 10 Tf (Hello) Tj ETn";
        appendRawCommands(getStructure().getImageFormStream().createOutputStream(),imgFormComment + text);

        logger.info("Added text commands to image form: " + text);
    }
}

在Helvetica中写入“Hello”,大小为10,位于图像形式的左下方(实际显示的形式).

PS:在我看来,这背后的面向对象结构应该彻底改革.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读