本文介绍了pdfbox 1.8.8的视觉签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作带有视觉签名和pdfbox的PDF。我有两个流,似乎pdfbox只能处理文件。没有三个临时文件,我无法使其正常运行。我可以从该API已更改,但仍然可以处理文件。

I'm trying to produce PDF with visual signature and pdfbox. I have two streams and it seems that pdfbox can deal only with files. I didn't manage to make it work without three temporary files. I can see from here that API has changed, but still it deals with files.

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, 0, c);
    }
    is.close();
}

除了文件疯狂之外,签名上没有看到任何文本。结果如下所示:

Apart from file madness I don't see any text on the signature. This is how result looks like:

这就是它的外观,当我使用itext库做类似的事情时

and this is how it looks, when I do similar thing with itext library

为什么名称,位置和原因从中丢失视觉签名表示?我该如何解决?

Why name, location and reason missing from the visual signature representation? How can I fix that?

推荐答案

为什么视觉签名表示中缺少名称,位置和原因?



它们不存在是因为未绘制。

Why name, location and reason missing from the visual signature representation?

They are not there because they are not drawn.

iText表示可视化签名的默认方式是将这些信息添加到

The default way of iText to represent a visualized signature is by adding those information to the visualization.

PDFBox的 PDVisibleSigBuilder 表示可视化签名的默认方式是不包含此类信息。

The default way of PDFBox' PDVisibleSigBuilder to represent a visualized signature is without such information.

既不是错也不是正确,两者都是默认值。

Neither is wrong or right, both merely are defaults.

人们应该寻找此类信息的规范位置是

The canonical place where people shall look for such information is the signature panel after all.

签名可视化的实际内容是由 PDVisibleSigBuilder 实例在 signatureProperties.buildSignature()中创建:

The actual contents of the signature visualization are created by a PDVisibleSigBuilder instance during signatureProperties.buildSignature():

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()));

自定义版本 ExtSigBuilder 的自定义版本 PDVisibleSigBuilder 类,您可以在其中绘制任何内容,例如:

for a customized version ExtSigBuilder of this PDVisibleSigBuilder class, you can draw anything you want there, e.g.:

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, PDStream imageFormStream,
            String imageObjectName, String imageName, String innerFormName, PDVisibleSignDesigner properties)
            throws IOException
    {
        super.injectAppearanceStreams(holderFormStream, innterFormStream, imageFormStream, 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中用10号大小写 Hello

writes "Hello" in Helvetica at size 10 atop the lower left of the image form (the form actually displaying something).

PS:在我看来,应该完全检查其背后的面向对象结构。

PS: In my opinion the object oriented structure behind this should be completely overhauled.

这篇关于pdfbox 1.8.8的视觉签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-27 21:48