Example usage for org.apache.pdfbox.cos COSDictionary getCOSObject

List of usage examples for org.apache.pdfbox.cos COSDictionary getCOSObject

Introduction

In this page you can find the example usage for org.apache.pdfbox.cos COSDictionary getCOSObject.

Prototype

@Override
public COSBase getCOSObject() 

Source Link

Document

Convert this standard java object to a COS object.

Usage

From source file:at.gv.egiz.pdfas.lib.impl.signing.pdfbox.PADESPDFBOXSigner.java

License:EUPL

public void signPDF(PDFObject genericPdfObject, RequestedSignature requestedSignature,
        PDFASSignatureInterface genericSigner) throws PdfAsException {
    String fisTmpFile = null;/* ww w.j  a  v a2 s. c o m*/

    PDFAsVisualSignatureProperties properties = null;

    if (!(genericPdfObject instanceof PDFBOXObject)) {
        // tODO:
        throw new PdfAsException();
    }

    PDFBOXObject pdfObject = (PDFBOXObject) genericPdfObject;

    if (!(genericSigner instanceof PDFASPDFBOXSignatureInterface)) {
        // tODO:
        throw new PdfAsException();
    }

    PDFASPDFBOXSignatureInterface signer = (PDFASPDFBOXSignatureInterface) genericSigner;

    TempFileHelper helper = pdfObject.getStatus().getTempFileHelper();
    PDDocument doc = pdfObject.getDocument();
    SignatureOptions options = new SignatureOptions();
    COSDocument visualSignatureDocumentGuard = null;
    try {
        fisTmpFile = helper.getStaticFilename();

        FileOutputStream tmpOutputStream = null;
        try {
            // write to temporary file
            tmpOutputStream = new FileOutputStream(new File(fisTmpFile));
            InputStream tmpis = null;
            try {
                tmpis = pdfObject.getOriginalDocument().getInputStream();
                IOUtils.copy(tmpis, tmpOutputStream);
                tmpis.close();
            } finally {
                IOUtils.closeQuietly(tmpis);
            }

            SignaturePlaceholderData signaturePlaceholderData = PlaceholderFilter
                    .checkPlaceholderSignature(pdfObject.getStatus(), pdfObject.getStatus().getSettings());

            TablePos tablePos = null;

            if (signaturePlaceholderData != null) {
                // Placeholder found!
                logger.info("Placeholder data found.");
                if (signaturePlaceholderData.getProfile() != null) {
                    logger.debug("Placeholder Profile set to: " + signaturePlaceholderData.getProfile());
                    requestedSignature.setSignatureProfileID(signaturePlaceholderData.getProfile());
                }

                tablePos = signaturePlaceholderData.getTablePos();
                if (tablePos != null) {

                    SignatureProfileConfiguration signatureProfileConfiguration = pdfObject.getStatus()
                            .getSignatureProfileConfiguration(requestedSignature.getSignatureProfileID());

                    float minWidth = signatureProfileConfiguration.getMinWidth();

                    if (minWidth > 0) {
                        if (tablePos.getWidth() < minWidth) {
                            tablePos.width = minWidth;
                            logger.debug("Correcting placeholder with to minimum width {}", minWidth);
                        }
                    }
                    logger.debug("Placeholder Position set to: " + tablePos.toString());
                }
            }

            PDSignature signature = new PDSignature();
            signature.setFilter(COSName.getPDFName(signer.getPDFFilter())); // default
            // filter
            signature.setSubFilter(COSName.getPDFName(signer.getPDFSubFilter()));

            SignatureProfileSettings signatureProfileSettings = TableFactory.createProfile(
                    requestedSignature.getSignatureProfileID(), pdfObject.getStatus().getSettings());

            ValueResolver resolver = new ValueResolver(requestedSignature, pdfObject.getStatus());
            String signerName = resolver.resolve("SIG_SUBJECT",
                    signatureProfileSettings.getValue("SIG_SUBJECT"), signatureProfileSettings);

            signature.setName(signerName);

            // take signing time from provided signer...
            signature.setSignDate(signer.getSigningDate());
            // ...and update operation status in order to use exactly this date for the complete signing process
            requestedSignature.getStatus().setSigningDate(signer.getSigningDate());

            String signerReason = signatureProfileSettings.getSigningReason();

            if (signerReason == null) {
                signerReason = "PAdES Signature";
            }

            signature.setReason(signerReason);
            logger.debug("Signing reason: " + signerReason);

            logger.debug("Signing @ " + signer.getSigningDate().getTime().toString());

            // the signing date, needed for valid signature
            // signature.setSignDate(signer.getSigningDate());

            signer.setPDSignature(signature);

            int signatureSize = 0x1000;
            try {
                String reservedSignatureSizeString = signatureProfileSettings.getValue(SIG_RESERVED_SIZE);
                if (reservedSignatureSizeString != null) {
                    signatureSize = Integer.parseInt(reservedSignatureSizeString);
                }
                logger.debug("Reserving {} bytes for signature", signatureSize);
            } catch (NumberFormatException e) {
                logger.warn("Invalid configuration value: {} should be a number using 0x1000",
                        SIG_RESERVED_SIZE);
            }
            options.setPreferedSignatureSize(signatureSize);

            // Is visible Signature
            if (requestedSignature.isVisual()) {
                logger.debug("Creating visual signature block");

                SignatureProfileConfiguration signatureProfileConfiguration = pdfObject.getStatus()
                        .getSignatureProfileConfiguration(requestedSignature.getSignatureProfileID());

                if (tablePos == null) {
                    // ================================================================
                    // PositioningStage (visual) -> find position or use
                    // fixed
                    // position

                    String posString = pdfObject.getStatus().getSignParamter().getSignaturePosition();

                    TablePos signaturePos = null;

                    String signaturePosString = signatureProfileConfiguration.getDefaultPositioning();

                    if (signaturePosString != null) {
                        logger.debug("using signature Positioning: " + signaturePos);
                        signaturePos = new TablePos(signaturePosString);
                    }

                    logger.debug("using Positioning: " + posString);

                    if (posString != null) {
                        // Merge Signature Position
                        tablePos = new TablePos(posString, signaturePos);
                    } else {
                        // Fallback to signature Position!
                        tablePos = signaturePos;
                    }

                    if (tablePos == null) {
                        // Last Fallback default position
                        tablePos = new TablePos();
                    }
                }
                boolean legacy32Position = signatureProfileConfiguration.getLegacy32Positioning();
                boolean legacy40Position = signatureProfileConfiguration.getLegacy40Positioning();

                // create Table describtion
                Table main = TableFactory.createSigTable(signatureProfileSettings, MAIN, pdfObject.getStatus(),
                        requestedSignature);

                IPDFStamper stamper = StamperFactory.createDefaultStamper(pdfObject.getStatus().getSettings());

                IPDFVisualObject visualObject = stamper.createVisualPDFObject(pdfObject, main);

                /*
                 * PDDocument originalDocument = PDDocument .load(new
                 * ByteArrayInputStream(pdfObject.getStatus()
                 * .getPdfObject().getOriginalDocument()));
                 */

                PositioningInstruction positioningInstruction = Positioning.determineTablePositioning(tablePos,
                        "", doc, visualObject, legacy32Position, legacy40Position);

                logger.debug("Positioning: {}", positioningInstruction.toString());

                if (positioningInstruction.isMakeNewPage()) {
                    int last = doc.getNumberOfPages() - 1;
                    PDDocumentCatalog root = doc.getDocumentCatalog();
                    PDPageNode rootPages = root.getPages();
                    List<PDPage> kids = new ArrayList<PDPage>();
                    rootPages.getAllKids(kids);
                    PDPage lastPage = kids.get(last);
                    rootPages.getCOSObject().setNeedToBeUpdate(true);
                    PDPage p = new PDPage(lastPage.findMediaBox());
                    p.setResources(new PDResources());
                    p.setRotation(lastPage.findRotation());
                    doc.addPage(p);
                }

                // handle rotated page
                PDDocumentCatalog documentCatalog = doc.getDocumentCatalog();
                PDPageNode documentPages = documentCatalog.getPages();
                List<PDPage> documentPagesKids = new ArrayList<PDPage>();
                documentPages.getAllKids(documentPagesKids);
                int targetPageNumber = positioningInstruction.getPage();
                logger.debug("Target Page: " + targetPageNumber);
                // rootPages.getAllKids(kids);
                PDPage targetPage = documentPagesKids.get(targetPageNumber - 1);
                int rot = targetPage.findRotation();
                logger.debug("Page rotation: " + rot);
                // positioningInstruction.setRotation(positioningInstruction.getRotation()
                // + rot);
                logger.debug("resulting Sign rotation: " + positioningInstruction.getRotation());

                SignaturePositionImpl position = new SignaturePositionImpl();
                position.setX(positioningInstruction.getX());
                position.setY(positioningInstruction.getY());
                position.setPage(positioningInstruction.getPage());
                position.setHeight(visualObject.getHeight());
                position.setWidth(visualObject.getWidth());

                requestedSignature.setSignaturePosition(position);

                properties = new PDFAsVisualSignatureProperties(pdfObject.getStatus().getSettings(), pdfObject,
                        (PdfBoxVisualObject) visualObject, positioningInstruction, signatureProfileSettings);

                properties.buildSignature();

                /*
                 * ByteArrayOutputStream sigbos = new
                 * ByteArrayOutputStream();
                 * sigbos.write(StreamUtils.inputStreamToByteArray
                 * (properties .getVisibleSignature())); sigbos.close();
                 */

                if (signaturePlaceholderData != null) {
                    // Placeholder found!
                    // replace placeholder
                    InputStream is = null;
                    try {
                        is = PADESPDFBOXSigner.class.getResourceAsStream("/placeholder/empty.jpg");
                        PDJpeg img = new PDJpeg(doc, is);

                        img.getCOSObject().setNeedToBeUpdate(true);

                        PDDocumentCatalog root = doc.getDocumentCatalog();
                        PDPageNode rootPages = root.getPages();
                        List<PDPage> kids = new ArrayList<PDPage>();
                        rootPages.getAllKids(kids);
                        int pageNumber = positioningInstruction.getPage();
                        // rootPages.getAllKids(kids);
                        PDPage page = kids.get(pageNumber - 1);

                        logger.info("Placeholder name: " + signaturePlaceholderData.getPlaceholderName());
                        COSDictionary xobjectsDictionary = (COSDictionary) page.findResources()
                                .getCOSDictionary().getDictionaryObject(COSName.XOBJECT);
                        xobjectsDictionary.setItem(signaturePlaceholderData.getPlaceholderName(), img);
                        xobjectsDictionary.setNeedToBeUpdate(true);
                        page.findResources().getCOSObject().setNeedToBeUpdate(true);
                        logger.info("Placeholder name: " + signaturePlaceholderData.getPlaceholderName());
                    } finally {
                        IOUtils.closeQuietly(is);
                    }
                }

                if (signatureProfileSettings.isPDFA()) {
                    PDDocumentCatalog root = doc.getDocumentCatalog();
                    COSBase base = root.getCOSDictionary().getItem(COSName.OUTPUT_INTENTS);
                    if (base == null) {
                        InputStream colorProfile = null;
                        try {
                            colorProfile = PDDocumentCatalog.class
                                    .getResourceAsStream("/icm/sRGB Color Space Profile.icm");

                            try {
                                PDOutputIntent oi = new PDOutputIntent(doc, colorProfile);
                                oi.setInfo("sRGB IEC61966-2.1");
                                oi.setOutputCondition("sRGB IEC61966-2.1");
                                oi.setOutputConditionIdentifier("sRGB IEC61966-2.1");
                                oi.setRegistryName("http://www.color.org");

                                root.addOutputIntent(oi);
                                root.getCOSObject().setNeedToBeUpdate(true);
                                logger.info("added Output Intent");
                            } catch (Throwable e) {
                                throw new PdfAsException("Failed to add Output Intent", e);
                            }
                        } finally {
                            IOUtils.closeQuietly(colorProfile);
                        }
                    }
                }

                options.setPage(positioningInstruction.getPage());

                options.setVisualSignature(properties.getVisibleSignature());
            }

            visualSignatureDocumentGuard = options.getVisualSignature();

            doc.addSignature(signature, signer, options);

            // set need to update indirect fields array in acro form
            COSDictionary trailer = doc.getDocument().getTrailer();
            if (trailer != null) {
                COSDictionary troot = (COSDictionary) trailer.getDictionaryObject(COSName.ROOT);
                if (troot != null) {
                    COSDictionary acroForm = (COSDictionary) troot.getDictionaryObject(COSName.ACRO_FORM);
                    if (acroForm != null) {
                        COSArray tfields = (COSArray) acroForm.getDictionaryObject(COSName.FIELDS);
                        if (tfields != null && !tfields.isDirect()) {
                            tfields.setNeedToBeUpdate(true);
                        }
                    }
                }
            }

            String sigFieldName = signatureProfileSettings.getSignFieldValue();

            if (sigFieldName == null) {
                sigFieldName = "PDF-AS Signatur";
            }

            int count = PdfBoxUtils.countSignatures(doc, sigFieldName);

            sigFieldName = sigFieldName + count;

            PDAcroForm acroFormm = doc.getDocumentCatalog().getAcroForm();

            PDSignatureField signatureField = null;
            if (acroFormm != null) {
                @SuppressWarnings("unchecked")
                List<PDField> fields = acroFormm.getFields();

                if (fields != null) {
                    for (PDField pdField : fields) {
                        if (pdField != null) {
                            if (pdField instanceof PDSignatureField) {
                                PDSignatureField tmpSigField = (PDSignatureField) pdField;

                                if (tmpSigField.getSignature() != null
                                        && tmpSigField.getSignature().getDictionary() != null) {
                                    if (tmpSigField.getSignature().getDictionary()
                                            .equals(signature.getDictionary())) {
                                        signatureField = (PDSignatureField) pdField;

                                    }
                                }
                            }
                        }
                    }
                } else {
                    logger.warn("Failed to name Signature Field! [Cannot find Field list in acroForm!]");
                }

                if (signatureField != null) {
                    signatureField.setPartialName(sigFieldName);
                }
                if (properties != null) {
                    signatureField.setAlternateFieldName(properties.getAlternativeTableCaption());
                } else {
                    signatureField.setAlternateFieldName(sigFieldName);
                }
            } else {
                logger.warn("Failed to name Signature Field! [Cannot find acroForm!]");
            }

            // PDF-UA
            logger.info("Adding pdf/ua content.");
            try {
                PDDocumentCatalog root = doc.getDocumentCatalog();
                PDStructureTreeRoot structureTreeRoot = root.getStructureTreeRoot();
                if (structureTreeRoot != null) {
                    logger.info("Tree Root: {}", structureTreeRoot.toString());
                    List<Object> kids = structureTreeRoot.getKids();

                    if (kids == null) {
                        logger.info("No kid-elements in structure tree Root, maybe not PDF/UA document");
                    }

                    PDStructureElement docElement = null;
                    for (Object k : kids) {
                        if (k instanceof PDStructureElement) {
                            docElement = (PDStructureElement) k;
                            break;

                        }
                    }

                    PDStructureElement sigBlock = new PDStructureElement("Form", docElement);

                    // create object dictionary and add as child element
                    COSDictionary objectDic = new COSDictionary();
                    objectDic.setName("Type", "OBJR");
                    objectDic.setItem("Pg", signatureField.getWidget().getPage());
                    objectDic.setItem("Obj", signatureField.getWidget());

                    List<Object> l = new ArrayList<Object>();
                    l.add(objectDic);
                    sigBlock.setKids(l);
                    sigBlock.setPage(signatureField.getWidget().getPage());

                    sigBlock.setTitle("Signature Table");
                    sigBlock.setParent(docElement);
                    docElement.appendKid(sigBlock);

                    // Create and add Attribute dictionary to mitigate PAC
                    // warning
                    COSDictionary sigBlockDic = (COSDictionary) sigBlock.getCOSObject();
                    COSDictionary sub = new COSDictionary();

                    sub.setName("O", "Layout");
                    sub.setName("Placement", "Block");
                    sigBlockDic.setItem(COSName.A, sub);
                    sigBlockDic.setNeedToBeUpdate(true);

                    // Modify number tree
                    PDNumberTreeNode ntn = structureTreeRoot.getParentTree();
                    int parentTreeNextKey = structureTreeRoot.getParentTreeNextKey();
                    if (ntn == null) {
                        ntn = new PDNumberTreeNode(objectDic, null);
                        logger.info("No number-tree-node found!");
                    }

                    COSArray ntnKids = (COSArray) ntn.getCOSDictionary().getDictionaryObject(COSName.KIDS);
                    COSArray ntnNumbers = (COSArray) ntn.getCOSDictionary().getDictionaryObject(COSName.NUMS);

                    if (ntnNumbers == null && ntnKids != null) {//no number array, so continue with the kids array

                        //create dictionary with limits and nums array
                        COSDictionary pTreeEntry = new COSDictionary();
                        COSArray limitsArray = new COSArray();
                        //limits for exact one entry
                        limitsArray.add(COSInteger.get(parentTreeNextKey));
                        limitsArray.add(COSInteger.get(parentTreeNextKey));

                        COSArray numsArray = new COSArray();
                        numsArray.add(COSInteger.get(parentTreeNextKey));
                        numsArray.add(sigBlock);

                        pTreeEntry.setItem(COSName.NUMS, numsArray);
                        pTreeEntry.setItem(COSName.LIMITS, limitsArray);

                        PDNumberTreeNode newKidsElement = new PDNumberTreeNode(pTreeEntry,
                                PDNumberTreeNode.class);

                        ntnKids.add(newKidsElement);
                        ntnKids.setNeedToBeUpdate(true);

                        //working
                        //                     List<PDNumberTreeNode> treeRootKids = structureTreeRoot.getParentTree().getKids();
                        //                     PDNumberTreeNode last = (PDNumberTreeNode)treeRootKids.get(treeRootKids.size()-1);
                        //                     COSArray lim1 = (COSArray) last.getCOSDictionary().getDictionaryObject(COSName.LIMITS);
                        //                     lim1.remove(1);
                        //                     lim1.add(1, COSInteger.get(parentTreeNextKey));
                        //                     PDNumberTreeNode verylast = (PDNumberTreeNode)last.getKids().get(last.getKids().size()-1);
                        //                     COSArray numa = (COSArray) verylast.getCOSDictionary().getDictionaryObject(COSName.NUMS);
                        //                     COSArray lim = (COSArray) verylast.getCOSDictionary().getDictionaryObject(COSName.LIMITS);
                        //                     lim.remove(1);
                        //                     lim.add(1, COSInteger.get(parentTreeNextKey));
                        //
                        //                     int size = numa.size();
                        //                     numa.add(size, COSInteger.get(parentTreeNextKey));
                        //                     numa.add(sigBlock);
                        //working end

                    } else if (ntnNumbers != null && ntnKids == null) {

                        int arrindex = ntnNumbers.size();

                        ntnNumbers.add(arrindex, COSInteger.get(parentTreeNextKey));
                        ntnNumbers.add(arrindex + 1, sigBlock.getCOSObject());

                        ntnNumbers.getCOSObject().setNeedToBeUpdate(true);

                        structureTreeRoot.setParentTree(ntn);

                    } else if (ntnNumbers == null && ntnKids == null) {
                        //document is not pdfua conform before signature creation
                        throw new PdfAsException("error.pdf.sig.pdfua.1");
                    } else {
                        //this is not allowed
                        throw new PdfAsException("error.pdf.sig.pdfua.1");
                    }

                    // set StructureParent for signature field annotation
                    signatureField.getWidget().setStructParent(parentTreeNextKey);

                    //Increase the next Key value in the structure tree root
                    structureTreeRoot.setParentTreeNextKey(parentTreeNextKey + 1);

                    // add the Tabs /S Element for Tabbing through annots
                    PDPage p = signatureField.getWidget().getPage();
                    p.getCOSDictionary().setName("Tabs", "S");
                    p.getCOSObject().setNeedToBeUpdate(true);

                    //check alternative signature field name
                    if (signatureField != null) {
                        if (signatureField.getAlternateFieldName().equals(""))
                            signatureField.setAlternateFieldName(sigFieldName);
                    }

                    ntn.getCOSDictionary().setNeedToBeUpdate(true);
                    sigBlock.getCOSObject().setNeedToBeUpdate(true);
                    structureTreeRoot.getCOSObject().setNeedToBeUpdate(true);
                    objectDic.getCOSObject().setNeedToBeUpdate(true);
                    docElement.getCOSObject().setNeedToBeUpdate(true);

                }

            } catch (Throwable e) {
                if (signatureProfileSettings.isPDFUA() == true) {
                    logger.error("Could not create PDF-UA conform document!");
                    throw new PdfAsException("error.pdf.sig.pdfua.1", e);
                } else {
                    logger.info("Could not create PDF-UA conform signature");
                }
            }

            try {
                applyFilter(doc, requestedSignature);
            } catch (PDFASError e) {
                throw new PdfAsErrorCarrier(e);
            }

            FileInputStream tmpFileIs = null;

            try {
                tmpFileIs = new FileInputStream(new File(fisTmpFile));
                synchronized (doc) {
                    doc.saveIncremental(tmpFileIs, tmpOutputStream);
                }
                tmpFileIs.close();
            } finally {
                IOUtils.closeQuietly(tmpFileIs);
                if (options != null) {
                    if (options.getVisualSignature() != null) {
                        options.getVisualSignature().close();
                    }
                }
            }
            tmpOutputStream.flush();
            tmpOutputStream.close();
        } finally {
            IOUtils.closeQuietly(tmpOutputStream);
            COSDocument visualSignature = options.getVisualSignature();
            if (visualSignature != null) {
                visualSignature.close();
            }
        }

        FileInputStream readReadyFile = null;
        try {
            readReadyFile = new FileInputStream(new File(fisTmpFile));

            // write to resulting output stream
            // ByteArrayOutputStream bos = new ByteArrayOutputStream();
            // bos.write();
            // bos.close();

            pdfObject.setSignedDocument(StreamUtils.inputStreamToByteArray(readReadyFile));
            readReadyFile.close();
        } finally {
            IOUtils.closeQuietly(readReadyFile);
        }
    } catch (IOException e) {
        logger.info(MessageResolver.resolveMessage("error.pdf.sig.01") + ": {}", e.toString());
        throw new PdfAsException("error.pdf.sig.01", e);
    } catch (SignatureException e) {
        logger.info(MessageResolver.resolveMessage("error.pdf.sig.01") + ": {}", e.toString());
        throw new PdfAsException("error.pdf.sig.01", e);
    } catch (COSVisitorException e) {
        logger.info(MessageResolver.resolveMessage("error.pdf.sig.01") + ": {}", e.toString());
        throw new PdfAsException("error.pdf.sig.01", e);
    } finally {
        if (doc != null) {
            try {
                doc.close();
            } catch (IOException e) {
                logger.debug("Failed to close COS Doc!", e);
                // Ignore
            }
        }

        if (fisTmpFile != null) {
            helper.deleteFile(fisTmpFile);
        }
        logger.debug("Signature done!");

    }
}