From 0596609c350efb8af333feb650317c8640921a94 Mon Sep 17 00:00:00 2001 From: Andreas Fitzek Date: Thu, 13 Mar 2014 16:47:23 +0100 Subject: WIP: Appearance Dictionary Signature OK --- .../lib/impl/signing/pdfbox/PADESPDFBOXSigner.java | 11 +- .../impl/stamping/pdfbox/PDFAsTemplateCreator.java | 140 ++++++++ .../pdfbox/PDFAsVisualSignatureBuilder.java | 345 ++++++++++++++++-- .../pdfbox/PDFAsVisualSignatureDesigner.java | 392 +++++++++++++++++++++ .../pdfbox/PDFAsVisualSignatureProperties.java | 17 +- 5 files changed, 872 insertions(+), 33 deletions(-) create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsTemplateCreator.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureDesigner.java diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox/PADESPDFBOXSigner.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox/PADESPDFBOXSigner.java index 93c19fe5..651c2e49 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox/PADESPDFBOXSigner.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox/PADESPDFBOXSigner.java @@ -111,7 +111,16 @@ public class PADESPDFBOXSigner implements IPdfSigner { PDFAsVisualSignatureProperties properties = new PDFAsVisualSignatureProperties( pdfObject.getStatus().getSettings(), pdfObject); properties.buildSignature(); - options.setVisualSignature(properties.getVisibleSignature()); + + ByteArrayOutputStream sigbos = new ByteArrayOutputStream(); + sigbos.write(StreamUtils.inputStreamToByteArray(properties.getVisibleSignature())); + sigbos.close(); + + FileOutputStream fos2 = new FileOutputStream("/tmp/apsig.pdf"); + fos2.write(sigbos.toByteArray()); + fos2.close(); + + options.setVisualSignature(new ByteArrayInputStream(sigbos.toByteArray())); doc.addSignature(signature, signer, options); diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsTemplateCreator.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsTemplateCreator.java new file mode 100644 index 00000000..e952ea73 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsTemplateCreator.java @@ -0,0 +1,140 @@ +package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; + +import java.awt.geom.AffineTransform; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.pdfbox.exceptions.COSVisitorException; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.common.PDStream; +import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDFTemplateBuilder; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDFTemplateCreator; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDFTemplateStructure; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PDFAsTemplateCreator extends PDFTemplateCreator { + + PDFAsVisualSignatureBuilder pdfBuilder; + private static final Logger logger = LoggerFactory.getLogger(PDFAsTemplateCreator.class); + + public PDFAsTemplateCreator(PDFAsVisualSignatureBuilder bookBuilder) { + super(bookBuilder); + this.pdfBuilder = bookBuilder; + } + + + public InputStream buildPDF(PDFAsVisualSignatureDesigner properties) + throws IOException { + logger.info("pdf building has been started"); + PDFTemplateStructure pdfStructure = pdfBuilder.getStructure(); + + // we create array of [Text, ImageB, ImageC, ImageI] + this.pdfBuilder.createProcSetArray(); + + //create page + this.pdfBuilder.createPage(properties); + PDPage page = pdfStructure.getPage(); + + //create template + this.pdfBuilder.createTemplate(page); + PDDocument template = pdfStructure.getTemplate(); + + //create /AcroForm + this.pdfBuilder.createAcroForm(template); + PDAcroForm acroForm = pdfStructure.getAcroForm(); + + // AcroForm contains singature fields + this.pdfBuilder.createSignatureField(acroForm); + PDSignatureField pdSignatureField = pdfStructure.getSignatureField(); + + // create signature + this.pdfBuilder.createSignature(pdSignatureField, page, properties.getSignatureFieldName()); + + // that is /AcroForm/DR entry + this.pdfBuilder.createAcroFormDictionary(acroForm, pdSignatureField); + + // create AffineTransform + this.pdfBuilder.createAffineTransform(properties.getAffineTransformParams()); + AffineTransform transform = pdfStructure.getAffineTransform(); + + // rectangle, formatter, image. /AcroForm/DR/XObject contains that form + this.pdfBuilder.createSignatureRectangle(pdSignatureField, properties); + this.pdfBuilder.createFormaterRectangle(properties.getFormaterRectangleParams()); + PDRectangle formater = pdfStructure.getFormaterRectangle(); + + //this.pdfBuilder.createSignatureImage(template, properties.getImageStream()); + + // create form stream, form and resource. + this.pdfBuilder.createHolderFormStream(template); + PDStream holderFormStream = pdfStructure.getHolderFormStream(); + this.pdfBuilder.createHolderFormResources(); + PDResources holderFormResources = pdfStructure.getHolderFormResources(); + this.pdfBuilder.createHolderForm(holderFormResources, holderFormStream, formater); + + // that is /AP entry the appearance dictionary. + this.pdfBuilder.createAppearanceDictionary(pdfStructure.getHolderForm(), pdSignatureField); + + // inner formstream, form and resource (hlder form containts inner form) + this.pdfBuilder.createInnerFormStream(template); + this.pdfBuilder.createInnerFormResource(); + PDResources innerFormResource = pdfStructure.getInnerFormResources(); + this.pdfBuilder.createInnerForm(innerFormResource, pdfStructure.getInnterFormStream(), formater); + PDXObjectForm innerForm = pdfStructure.getInnerForm(); + + // inner form must be in the holder form as we wrote + this.pdfBuilder.insertInnerFormToHolerResources(innerForm, holderFormResources); + + // Image form is in this structure: /AcroForm/DR/FRM0/Resources/XObject/n0 + //this.pdfBuilder.createImageFormStream(template); + //PDStream imageFormStream = pdfStructure.getImageFormStream(); + //this.pdfBuilder.createImageFormResources(); + //PDResources imageFormResources = pdfStructure.getImageFormResources(); + //this.pdfBuilder.createImageForm(imageFormResources, innerFormResource, imageFormStream, formater, transform, + // pdfStructure.getJpedImage()); + + // now inject procSetArray + /*this.pdfBuilder.injectProcSetArray(innerForm, page, innerFormResource, imageFormResources, holderFormResources, + pdfStructure.getProcSet());*/ + this.pdfBuilder.injectProcSetArray(innerForm, page, innerFormResource, null, holderFormResources, + pdfStructure.getProcSet()); + + + /*String imgFormName = pdfStructure.getImageFormName(); + String imgName = pdfStructure.getImageName();*/ + String innerFormName = pdfStructure.getInnerFormName(); + + // now create Streams of AP + /*this.pdfBuilder.injectAppearanceStreams(holderFormStream, imageFormStream, imageFormStream, imgFormName, + imgName, innerFormName, properties);*/ + this.pdfBuilder.injectAppearanceStreams(holderFormStream, null, null, null, + null, innerFormName, properties); + this.pdfBuilder.createVisualSignature(template); + this.pdfBuilder.createWidgetDictionary(pdSignatureField, holderFormResources); + + ByteArrayInputStream in = null; + try + { + in = pdfStructure.getTemplateAppearanceStream(); + } + catch (COSVisitorException e) + { + logger.error("COSVisitorException: can't get apereance stream ", e); + } + logger.info("stream returning started, size= " + in.available()); + + // we must close the document + template.close(); + + // return result of the stream + return in; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java index 496bc0d8..cd4abdf9 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java @@ -1,16 +1,33 @@ package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; +import java.awt.geom.AffineTransform; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; +import java.util.List; +import org.apache.pdfbox.cos.COSArray; +import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.edit.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg; +import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDFTemplateStructure; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigBuilder; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDField; +import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -119,6 +136,15 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { this.properties = properties; } + @Override + public void createProcSetArray() { + COSArray procSetArr = new COSArray(); + procSetArr.add(COSName.getPDFName("PDF")); + procSetArr.add(COSName.getPDFName("Text")); + getStructure().setProcSet(procSetArr); + logger.info("ProcSet array has been created"); + } + @Override public void createTemplate(PDPage page) throws IOException { PDDocument template = new PDDocument(); @@ -144,30 +170,299 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { e.printStackTrace(); } } + + @Override + public void injectProcSetArray(PDXObjectForm innerForm, PDPage page, + PDResources innerFormResources, PDResources imageFormResources, + PDResources holderFormResources, COSArray procSet) { + innerForm.getResources().getCOSDictionary() + .setItem(COSName.PROC_SET, procSet); // + page.getCOSDictionary().setItem(COSName.PROC_SET, procSet); + innerFormResources.getCOSDictionary() + .setItem(COSName.PROC_SET, procSet); + /*imageFormResources.getCOSDictionary() + .setItem(COSName.PROC_SET, procSet);*/ + holderFormResources.getCOSDictionary().setItem(COSName.PROC_SET, + procSet); + logger.info("inserted ProcSet to PDF"); + } + + public void injectAppearanceStreams(PDStream holderFormStream, + PDStream innterFormStream, PDStream imageFormStream, + String imageObjectName, String imageName, String innerFormName, + PDFAsVisualSignatureDesigner properties) throws IOException { + + // 100 means that document width is 100% via the rectangle. if rectangle + // is 500px, images 100% is 500px. + // String imgFormComment = "q "+imageWidthSize+ " 0 0 50 0 0 cm /" + + // imageName + " Do Q\n" + builder.toString(); + /*String imgFormComment = "q " + 100 + " 0 0 50 0 0 cm /" + imageName + + " Do Q\n";*/ + String holderFormComment = "q 1 0 0 1 0 0 cm /" + innerFormName + + " Do Q \n"; + // String innerFormComment = "q 1 0 0 1 0 0 cm /" + imageObjectName + + // " Do Q\n"; + String innerFormComment = getStructure().getInnterFormStream() + .getInputStreamAsString(); + + logger.info("Inner Form Stream: " + innerFormComment); + + // appendRawCommands(getStructure().getInnterFormStream().createOutputStream(), + // getStructure().getInnterFormStream().getInputStreamAsString()); + + appendRawCommands(getStructure().getHolderFormStream() + .createOutputStream(), holderFormComment); + appendRawCommands(getStructure().getInnterFormStream() + .createOutputStream(), innerFormComment); + // appendRawCommands(getStructure().getImageFormStream().createOutputStream(), + // imgFormComment); + logger.info("Injected apereance stream to pdf"); + + } + + public void createPage(PDFAsVisualSignatureDesigner properties) + { + PDPage page = new PDPage(); + page.setMediaBox(new PDRectangle(properties.getPageWidth(), properties.getPageHeight())); + getStructure().setPage(page); + logger.info("PDF page has been created"); + } + + public void createAcroForm(PDDocument template) + { + PDAcroForm theAcroForm = new PDAcroForm(template); + template.getDocumentCatalog().setAcroForm(theAcroForm); + getStructure().setAcroForm(theAcroForm); + logger.info("Acro form page has been created"); + + } + + public void createSignatureField(PDAcroForm acroForm) throws IOException + { + PDSignatureField sf = new PDSignatureField(acroForm); + getStructure().setSignatureField(sf); + logger.info("Signature field has been created"); + } + + public void createSignature(PDSignatureField pdSignatureField, PDPage page, String signatureName) + throws IOException + { + PDSignature pdSignature = new PDSignature(); + pdSignatureField.setSignature(pdSignature); + pdSignatureField.getWidget().setPage(page); + page.getAnnotations().add(pdSignatureField.getWidget()); + pdSignature.setName(signatureName); + pdSignature.setByteRange(new int[] { 0, 0, 0, 0 }); + pdSignature.setContents(new byte[4096]); + getStructure().setPdSignature(pdSignature); + logger.info("PDSignatur has been created"); + } + + public void createAcroFormDictionary(PDAcroForm acroForm, PDSignatureField signatureField) throws IOException + { + @SuppressWarnings("unchecked") + List acroFormFields = acroForm.getFields(); + COSDictionary acroFormDict = acroForm.getDictionary(); + acroFormDict.setDirect(true); + acroFormDict.setInt(COSName.SIG_FLAGS, 3); + acroFormFields.add(signatureField); + acroFormDict.setString(COSName.DA, "/sylfaen 0 Tf 0 g"); + getStructure().setAcroFormFields(acroFormFields); + getStructure().setAcroFormDictionary(acroFormDict); + logger.info("AcroForm dictionary has been created"); + } + + public void createSignatureRectangle(PDSignatureField signatureField, PDFAsVisualSignatureDesigner properties) + throws IOException + { + + PDRectangle rect = new PDRectangle(); + rect.setUpperRightX(properties.getxAxis() + properties.getWidth()); + rect.setUpperRightY(properties.getPageHeight() - properties.getyAxis()); + rect.setLowerLeftY(properties.getPageHeight() - properties.getyAxis() - properties.getHeight()); + rect.setLowerLeftX(properties.getxAxis()); + signatureField.getWidget().setRectangle(rect); + getStructure().setSignatureRectangle(rect); + logger.info("rectangle of signature has been created"); + } + + public void createAffineTransform(byte[] params) + { + AffineTransform transform = new AffineTransform(params[0], params[1], params[2], params[3], params[4], + params[5]); + getStructure().setAffineTransform(transform); + logger.info("Matrix has been added"); + } + + public void createSignatureImage(PDDocument template, InputStream inputStream) throws IOException + { + PDJpeg img = new PDJpeg(template, inputStream); + getStructure().setJpedImage(img); + logger.info("Visible Signature Image has been created"); + // pdfStructure.setTemplate(template); + inputStream.close(); + + } + + public void createFormaterRectangle(byte[] params) + { + + PDRectangle formrect = new PDRectangle(); + formrect.setUpperRightX(params[0]); + formrect.setUpperRightY(params[1]); + formrect.setLowerLeftX(params[2]); + formrect.setLowerLeftY(params[3]); + + getStructure().setFormaterRectangle(formrect); + logger.info("Formater rectangle has been created"); + + } + + public void createHolderFormStream(PDDocument template) + { + PDStream holderForm = new PDStream(template); + getStructure().setHolderFormStream(holderForm); + logger.info("Holder form Stream has been created"); + } + + public void createHolderFormResources() + { + PDResources holderFormResources = new PDResources(); + getStructure().setHolderFormResources(holderFormResources); + logger.info("Holder form resources have been created"); + + } + + public void createHolderForm(PDResources holderFormResources, PDStream holderFormStream, PDRectangle formrect) + { + + PDXObjectForm holderForm = new PDXObjectForm(holderFormStream); + holderForm.setResources(holderFormResources); + holderForm.setBBox(formrect); + holderForm.setFormType(1); + getStructure().setHolderForm(holderForm); + logger.info("Holder form has been created"); + + } + + public void createAppearanceDictionary(PDXObjectForm holderForml, PDSignatureField signatureField) + throws IOException + { + + PDAppearanceDictionary appearance = new PDAppearanceDictionary(); + appearance.getCOSObject().setDirect(true); + + PDAppearanceStream appearanceStream = new PDAppearanceStream(holderForml.getCOSStream()); + + appearance.setNormalAppearance(appearanceStream); + signatureField.getWidget().setAppearance(appearance); + + getStructure().setAppearanceDictionary(appearance); + logger.info("PDF appereance Dictionary has been created"); + + } + + public void createInnerFormResource() + { + PDResources innerFormResources = new PDResources(); + getStructure().setInnerFormResources(innerFormResources); + logger.info("Resources of another form (inner form - it would be inside holder form) have been created"); + } + + public void createInnerForm(PDResources innerFormResources, PDStream innerFormStream, PDRectangle formrect) + { + PDXObjectForm innerForm = new PDXObjectForm(innerFormStream); + innerForm.setResources(innerFormResources); + innerForm.setBBox(formrect); + innerForm.setFormType(1); + getStructure().setInnerForm(innerForm); + logger.info("Another form (inner form - it would be inside holder form) have been created"); + + } + + public void insertInnerFormToHolerResources(PDXObjectForm innerForm, PDResources holderFormResources) + { + String name = holderFormResources.addXObject(innerForm, "FRM"); + getStructure().setInnerFormName(name); + logger.info("Alerady inserted inner form inside holder form"); + } + + public void createImageFormStream(PDDocument template) + { + PDStream imageFormStream = new PDStream(template); + getStructure().setImageFormStream(imageFormStream); + logger.info("Created image form Stream"); + + } + + public void createImageFormResources() + { + PDResources imageFormResources = new PDResources(); + getStructure().setImageFormResources(imageFormResources); + logger.info("Created image form Resources"); + } + + public void createImageForm(PDResources imageFormResources, PDResources innerFormResource, + PDStream imageFormStream, PDRectangle formrect, AffineTransform affineTransform, PDJpeg img) + throws IOException + { + + /* + * if you need text on the visible signature + * + * PDFont font = PDTrueTypeFont.loadTTF(this.pdfStructure.getTemplate(), new File("D:\\arial.ttf")); + * font.setFontEncoding(new WinAnsiEncoding()); + * + * Map fonts = new HashMap(); fonts.put("arial", font); + */ + PDXObjectForm imageForm = new PDXObjectForm(imageFormStream); + imageForm.setBBox(formrect); + imageForm.setMatrix(affineTransform); + imageForm.setResources(imageFormResources); + imageForm.setFormType(1); + /* + * imageForm.getResources().addFont(font); + * imageForm.getResources().setFonts(fonts); + */ + + imageFormResources.getCOSObject().setDirect(true); + String imageFormName = innerFormResource.addXObject(imageForm, "n"); + String imageName = imageFormResources.addXObject(img, "img"); + this.getStructure().setImageForm(imageForm); + this.getStructure().setImageFormName(imageFormName); + this.getStructure().setImageName(imageName); + logger.info("Created image form"); + } + + public void appendRawCommands(OutputStream os, String commands) throws IOException + { + os.write(commands.getBytes("UTF-8")); + os.close(); + } + + public void createVisualSignature(PDDocument template) + { + this.getStructure().setVisualSignature(template.getDocument()); + logger.info("Visible signature has been created"); + + } + + public void createWidgetDictionary(PDSignatureField signatureField, PDResources holderFormResources) + throws IOException + { + + COSDictionary widgetDict = signatureField.getWidget().getDictionary(); + widgetDict.setNeedToBeUpdate(true); + widgetDict.setItem(COSName.DR, holderFormResources.getCOSObject()); + + getStructure().setWidgetDictionary(widgetDict); + logger.info("WidgetDictionary has been crated"); + } + + public void closeTemplate(PDDocument template) throws IOException + { + template.close(); + this.getStructure().getTemplate().close(); + } - @Override - public void injectAppearanceStreams(PDStream holderFormStream, PDStream innterFormStream, PDStream imageFormStream, - String imageObjectName, String imageName, String innerFormName, PDVisibleSignDesigner properties) - throws IOException - { - - // 100 means that document width is 100% via the rectangle. if rectangle - // is 500px, images 100% is 500px. - // String imgFormComment = "q "+imageWidthSize+ " 0 0 50 0 0 cm /" + - // imageName + " Do Q\n" + builder.toString(); - String imgFormComment = "q " + 100 + " 0 0 50 0 0 cm /" + imageName + " Do Q\n"; - String holderFormComment = "q 1 0 0 1 0 0 cm /" + innerFormName + " Do Q \n"; - String innerFormComment = "q 1 0 0 1 0 0 cm /" + imageObjectName + " Do Q\n"; - - logger.info("Holder Stream: " + getStructure().getInnterFormStream().getInputStreamAsString()); - - //appendRawCommands(getStructure().getInnterFormStream().createOutputStream(), - // getStructure().getInnterFormStream().getInputStreamAsString()); - - appendRawCommands(getStructure().getHolderFormStream().createOutputStream(), holderFormComment); - appendRawCommands(getStructure().getInnterFormStream().createOutputStream(), getStructure().getInnterFormStream().getInputStreamAsString()); - appendRawCommands(getStructure().getImageFormStream().createOutputStream(), imgFormComment); - logger.info("Injected apereance stream to pdf"); - - } } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureDesigner.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureDesigner.java new file mode 100644 index 00000000..5ad36c62 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureDesigner.java @@ -0,0 +1,392 @@ +package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner; + +public class PDFAsVisualSignatureDesigner { + + private Float sigImgWidth; + private Float sigImgHeight; + private float xAxis; + private float yAxis; + private float pageHeight; + private float pageWidth; + private InputStream imgageStream; + private String signatureFieldName = "sig"; // default + private byte[] formaterRectangleParams = { 0, 0, 100, 50 }; // default + private byte[] AffineTransformParams = { 1, 0, 0, 1, 0, 0 }; // default + private float imageSizeInPercents; + private PDDocument document = null; + + /** + * + * @param doc + * - Already created PDDocument of your PDF document + * @param imageStream + * @param page + * @throws IOException + * - If we can't read, flush, or can't close stream + */ + public PDFAsVisualSignatureDesigner(PDDocument doc, + int page) throws IOException { + calculatePageSize(doc, page); + } + + /** + * Each page of document can be different sizes. + * + * @param document + * @param page + */ + private void calculatePageSize(PDDocument document, int page) { + + if (page < 1) { + throw new IllegalArgumentException("First page of pdf is 1, not " + + page); + } + + List pages = document.getDocumentCatalog().getAllPages(); + PDPage firstPage = (PDPage) pages.get(page - 1); + PDRectangle mediaBox = firstPage.findMediaBox(); + this.pageHeight(mediaBox.getHeight()); + this.pageWidth = mediaBox.getWidth(); + + float x = this.pageWidth; + float y = 0; + this.pageWidth = this.pageWidth + y; + float tPercent = (100 * y / (x + y)); + this.imageSizeInPercents = 100 - tPercent; + + } + + /** + * + * @param path + * of image location + * @return image Stream + * @throws IOException + */ + public PDFAsVisualSignatureDesigner signatureImage(String path) throws IOException { + InputStream fin = new FileInputStream(path); + return signatureImageStream(fin); + } + + /** + * zoom signature image with some percent. + * + * @param percent + * - x % increase image with x percent. + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner zoom(float percent) { + sigImgHeight = sigImgHeight + (sigImgHeight * percent) / 100; + sigImgWidth = sigImgWidth + (sigImgWidth * percent) / 100; + return this; + } + + /** + * + * @param xAxis + * - x coordinate + * @param yAxis + * - y coordinate + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner coordinates(float x, float y) { + xAxis(x); + yAxis(y); + return this; + } + + /** + * + * @return xAxis - gets x coordinates + */ + public float getxAxis() { + return xAxis; + } + + /** + * + * @param xAxis + * - x coordinate + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner xAxis(float xAxis) { + this.xAxis = xAxis; + return this; + } + + /** + * + * @return yAxis + */ + public float getyAxis() { + return yAxis; + } + + /** + * + * @param yAxis + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner yAxis(float yAxis) { + this.yAxis = yAxis; + return this; + } + + /** + * + * @return signature image width + */ + public float getWidth() { + return 400; + } + + /** + * + * @param sets + * signature image width + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner width(float signatureImgWidth) { + this.sigImgWidth = signatureImgWidth; + return this; + } + + /** + * + * @return signature image height + */ + public float getHeight() { + return 300; + } + + /** + * + * @param set + * signature image Height + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner height(float signatureImgHeight) { + this.sigImgHeight = signatureImgHeight; + return this; + } + + /** + * + * @return template height + */ + protected float getTemplateHeight() { + return getPageHeight(); + } + + /** + * + * @param templateHeight + * @return Visible Signature Configuration Object + */ + private PDFAsVisualSignatureDesigner pageHeight(float templateHeight) { + this.pageHeight = templateHeight; + return this; + } + + /** + * + * @return signature field name + */ + public String getSignatureFieldName() { + return signatureFieldName; + } + + /** + * + * @param signatureFieldName + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner signatureFieldName(String signatureFieldName) { + this.signatureFieldName = signatureFieldName; + return this; + } + + /** + * + * @return image Stream + */ + public InputStream getImageStream() { + return imgageStream; + } + + /** + * + * @param imgageStream + * - stream of your visible signature image + * @return Visible Signature Configuration Object + * @throws IOException + * - If we can't read, flush, or close stream of image + */ + private PDFAsVisualSignatureDesigner signatureImageStream(InputStream imageStream) + throws IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len; + while ((len = imageStream.read(buffer)) > -1) { + baos.write(buffer, 0, len); + } + baos.flush(); + baos.close(); + + byte[] byteArray = baos.toByteArray(); + byte[] byteArraySecond = byteArray.clone(); + + InputStream inputForBufferedImage = new ByteArrayInputStream(byteArray); + InputStream revertInputStream = new ByteArrayInputStream( + byteArraySecond); + + if (sigImgHeight == null || sigImgWidth == null) { + calcualteImageSize(inputForBufferedImage); + } + + this.imgageStream = revertInputStream; + + return this; + } + + /** + * calculates image width and height. sported formats: all + * + * @param fis + * - input stream of image + * @throws IOException + * - if can't read input stream + */ + private void calcualteImageSize(InputStream fis) throws IOException { + + BufferedImage bimg = ImageIO.read(fis); + int width = bimg.getWidth(); + int height = bimg.getHeight(); + + sigImgHeight = (float) height; + sigImgWidth = (float) width; + + } + + /** + * + * @return Affine Transform parameters of for PDF Matrix + */ + public byte[] getAffineTransformParams() { + return AffineTransformParams; + } + + /** + * + * @param affineTransformParams + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner affineTransformParams( + byte[] affineTransformParams) { + AffineTransformParams = affineTransformParams; + return this; + } + + /** + * + * @return formatter PDRectanle parameters + */ + public byte[] getFormaterRectangleParams() { + return formaterRectangleParams; + } + + /** + * sets formatter PDRectangle; + * + * @param formaterRectangleParams + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner formaterRectangleParams( + byte[] formaterRectangleParams) { + this.formaterRectangleParams = formaterRectangleParams; + return this; + } + + /** + * + * @return page width + */ + public float getPageWidth() { + return pageWidth; + } + + /** + * + * @param sets + * pageWidth + * @return Visible Signature Configuration Object + */ + public PDFAsVisualSignatureDesigner pageWidth(float pageWidth) { + this.pageWidth = pageWidth; + return this; + } + + /** + * + * @return page height + */ + public float getPageHeight() { + return pageHeight; + } + + /** + * get image size in percents + * + * @return + */ + public float getImageSizeInPercents() { + return imageSizeInPercents; + } + + /** + * + * @param imageSizeInPercents + */ + public void imageSizeInPercents(float imageSizeInPercents) { + this.imageSizeInPercents = imageSizeInPercents; + } + + /** + * returns visible signature text + * + * @return + */ + public String getSignatureText() { + throw new UnsupportedOperationException( + "That method is not yet implemented"); + } + + /** + * + * @param signatureText + * - adds the text on visible signature + * @return + */ + public PDFAsVisualSignatureDesigner signatureText(String signatureText) { + throw new UnsupportedOperationException( + "That method is not yet implemented"); + } + +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureProperties.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureProperties.java index a3d02db2..055f035d 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureProperties.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureProperties.java @@ -24,6 +24,8 @@ public class PDFAsVisualSignatureProperties extends PDVisibleSigProperties { private ISettings settings; private Table main; + + private PDFAsVisualSignatureDesigner designer; public PDFAsVisualSignatureProperties(ISettings settings, PDFObject object) { this.settings = settings; @@ -32,7 +34,7 @@ public class PDFAsVisualSignatureProperties extends PDVisibleSigProperties { .createProfile("SIGNATURBLOCK_DE", settings); X509Certificate cert = new X509Certificate(new FileInputStream( - "/home/afitzek/qualified.cer")); + "/home/andy/certificates/test.crt")); CertificateHolderRequest request = new CertificateHolderRequest( cert); @@ -47,10 +49,10 @@ public class PDFAsVisualSignatureProperties extends PDVisibleSigProperties { try { PDDocument origDoc = PDDocument.load(new ByteArrayInputStream( object.getStampedDocument())); - PDVisibleSignDesigner designer = new PDVisibleSignDesigner(origDoc, - new FileInputStream("/home/afitzek/.pdfas/images/signatur-logo_de.png"), 1); - this.setPdVisibleSignature(designer); + designer = new PDFAsVisualSignatureDesigner(origDoc, 1); + + //this.setPdVisibleSignature(designer); } catch (Throwable e) { e.printStackTrace(); } @@ -58,13 +60,14 @@ public class PDFAsVisualSignatureProperties extends PDVisibleSigProperties { @Override public void buildSignature() throws IOException { - PDFTemplateBuilder builder = new PDFAsVisualSignatureBuilder(this); - PDFTemplateCreator creator = new PDFTemplateCreator(builder); - setVisibleSignature(creator.buildPDF(getPdVisibleSignature())); + PDFAsVisualSignatureBuilder builder = new PDFAsVisualSignatureBuilder(this); + PDFAsTemplateCreator creator = new PDFAsTemplateCreator(builder); + setVisibleSignature(creator.buildPDF(designer)); } public Table getMainTable() { return main; } + } -- cgit v1.2.3