TomRoush / PdfBox-Android

The Apache PdfBox project ported to work on Android
Apache License 2.0
1.02k stars 261 forks source link

Signature with transparent image doesn't works #106

Closed peru1981 closed 7 years ago

peru1981 commented 7 years ago

Hi Tom, thanks for all.

In my android application I need to create a VisibileSignature with a trasparent image,but my code doesn't work. Note: signImage is a .png file

public boolean createSignature(SignLocation signLocation, Bitmap signImage) throws PDFException {

    boolean signResult = false;

    PDSignature signature;
    InputStream isImage = null;
    SignatureOptions signatureOptions = new SignatureOptions();

    try {
        signature = findExistingSignature(pdfDocument, signLocation.getFieldName());
        if(signature==null)
            signature = new PDSignature();

        signature.setName(signLocation.getFieldName());
        signature.setReason(signLocation.getReason());
        signature.setLocation(signLocation.getLocation());
        signature.setSignDate(Calendar.getInstance());

        PDVisibleSignDesigner visibleSignDesigner;
        isImage = new ByteArrayInputStream(ImageUtil.convertImageToByteArray(signImage));

        if(signLocation.isVisible()) {
            float zoom;
            try {
                zoom = (float) ImageUtil.zoom4Signature(signImage.getWidth(), signImage.getHeight(), (int)signLocation.getWidth(), (int)signLocation.getHeight());
            } catch ( Throwable e) {
                zoom = 1;
            }

            if(zoom!=1)
                zoom = -zoom;

            //PDImageXObject pdImageXObject = LosslessFactory.createFromImage(pdfDocument, signImage);
            //isImage = pdImageXObject.getStream().createInputStream();
            //signature.getDictionary().setItem(COSName.IMAGE, pdImageXObject);

            visibleSignDesigner = new PDVisibleSignDesigner(pdfDocument, isImage, signLocation.getPageNumber());
            visibleSignDesigner.xAxis(signLocation.getLeft()).yAxis(signLocation.getTop()).zoom(zoom);

            PDVisibleSigProperties visibleSignatureProperties = new PDVisibleSigProperties();

            visibleSignatureProperties.signerName(signLocation.getFieldName()).signerLocation(signLocation.getLocation()).signatureReason(signLocation.getReason()).
                    preferredSize(0).page(signLocation.getPageNumber()).visualSignEnabled(true).
                    setPdVisibleSignature(visibleSignDesigner);

            visibleSignatureProperties.buildSignature();

            signatureOptions.setVisualSignature(visibleSignatureProperties.getVisibleSignature());
            signatureOptions.setPage(visibleSignatureProperties.getPage() - 1);
        }

        signDetachedFromStore(signature, signatureOptions);
        signResult = true;
    } catch (Throwable e) {
        e.printStackTrace();
        signResult = false;
    } finally {
        try {
            if(isImage!=null)
                isImage.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        if(signatureOptions!=null)
            IOUtils.closeQuietly(signatureOptions);

    }

    return signResult;
}

Thanks in advance for your help

BR Marco

TomRoush commented 7 years ago

You'll need to download the latest version of the library from GitHub, but you should be able to use PNGs for your signatures now.

peru1981 commented 7 years ago

Hi Tom, thnaks a lots!

BR Marco

androindev commented 6 years ago

Hi Marco,

I have same requirement of implementing VisibileSignature with a trasparent image(png).

Could you please share your code? its is very helpful for me. Thanks in advance.

Regards, Andev

peru1981 commented 6 years ago

Hi Andev, at top of this page there a code

androindev commented 6 years ago

Hi Marco,

Thanks for your quick response. Could you please share following method implementations in the above code 1) findExistingSignature(pdfDocument, signLocation.getFieldName()); 2) signDetachedFromStore(signature, signatureOptions) 3) IImageUtil.zoom4Signature(signImage.getWidth(), signImage.getHeight(), (int)signLocation.getWidth(), (int)signLocation.getHeight());

Thanks in advance.

Regards, Andev

peru1981 commented 6 years ago

Hi Andev,

private PDSignature findExistingSignature(PDDocument doc, SignLocation signLocation) throws SDKErrorException { Log.i(TAG, "Begin findExistingSignature()");

    PDSignature signature = null;
    PDSignatureField signatureField;
    PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
    if (acroForm != null) {
        try {
            signatureField = (PDSignatureField) acroForm.getField(signLocation.getFieldName());
            if(signatureField==null)
            {
                Log.i(TAG, "End findExistingSignature() - signatureField is NULL return null");
                return null;
            }

            PDRectangle pdRectangle = PDFDocument.getFieldArea(signatureField);

            /* Ricalcolo le posizioni */
            Point fieldPosition = new Point((int) pdRectangle.getLowerLeftX(), (int) pdRectangle.getLowerLeftY());
            Point newPosition = NormalizePoint.normalizePoint(ReferenceCorner.UPPERLEFT, fieldPosition, pdRectangle.getHeight(), doc.getPage(0).getMediaBox());

            signLocation.setLeft(newPosition.x);
            signLocation.setTop(newPosition.y);
            signLocation.setWidth(pdRectangle.getWidth());
            signLocation.setHeight(pdRectangle.getHeight());
            int page = PDFDocument.getPage(signatureField);
            if(page!=-1)
                signLocation.setPageNumber(page);
        } catch ( Throwable e ) {
            Log.i(TAG, "End findExistingSignature() - return null");
            return null;
        }

        if (signatureField != null) {
            // retrieve signature dictionary
            signature = signatureField.getSignature();
            if (signature == null) {
                signature = new PDSignature();
                signatureField.getCOSObject().setItem(COSName.V, signature);

            } else {
                throw new SDKErrorException(ErrorCode.DOC_ALREADY_SIGN.getDescription(), ErrorCode.ERROR_SIGNATURE);
            }
        }
    }

    Log.i(TAG, "End findExistingSignature()");
    return signature;
}

private void signDetachedFromStore(PDSignature signature, SignatureOptions signatureOptions) throws SDKErrorException {
    Log.i(TAG, "Begin signDetachedFromStore()");

    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);

    ByteArrayOutputStream baos = null;
    try {
        pdfDocument.addSignature(signature, this, signatureOptions);

        baos = new ByteArrayOutputStream();
        pdfDocument.saveIncremental(baos);

        docSigned = baos.toByteArray();
    } catch (Throwable e) {
        throw new SDKErrorException(ErrorCode.ERROR_SIGNATURE.getDescription(), e, ErrorCode.ERROR_SIGNATURE);
    } finally {
        try {
            if(baos!=null)
                baos.close();
        } catch (IOException e) {
            Log.w(TAG, ErrorCode.ERROR_SIGNATURE.getDescription(), e);
        }

        Log.i(TAG, "End signDetachedFromStore()");
    }

BR Marco

androindev commented 6 years ago

Hi Marco,

Thanks a lot for your response. Could you please share following method implementations as well? 1) public byte[] sign(InputStream content);// SignatureInterface implement method 2) ImageUtil.zoom4Signature()

Thanks again.

Regards, Andev

peru1981 commented 6 years ago

Hi Andev,

private byte[] sign(byte[] messageDigest, X509Certificate cert, PrivateKey pk) throws SDKErrorException {
    Log.i(TAG, "Begin sign()");
    try {
        CMSProcessableByteArray msg = new CMSProcessableByteArray(messageDigest);

        List<X509Certificate> certList = new ArrayList<X509Certificate>();
        certList.add(cert);

        JcaCertStore  certs = new JcaCertStore(certList);

        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();

        ContentSigner conteinerSigner;
        if(provider!=null) {
            conteinerSigner = new JcaContentSignerBuilder(algorithm).setProvider(provider).build(pk);
            gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(provider).build()).build(conteinerSigner, cert));
        } else {
            conteinerSigner = new JcaContentSignerBuilder(algorithm).build(pk);
            gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(conteinerSigner, cert));
        }

        //adding the certificate
        gen.addCertificates(certs);

        //Getting the signed data
        CMSSignedData sigData = gen.generate(msg, false);
        return sigData.getEncoded();
    } catch(Throwable e) {
        throw new SDKErrorException(ErrorCode.ERROR_SIGNATURE.getDescription(), e, ErrorCode.ERROR_SIGNATURE);
    } finally {
        Log.i(TAG, "End sign()");
    }
}

The method ImageUtil.zoom4Signature() resize image, I worked i lot to do it.

BR Marco

androindev commented 6 years ago

Hi Marco,

Thanks a lot.

Regards, Andev