From 4f1e143c6eac9e1b57b2400bf5b0761a8b072419 Mon Sep 17 00:00:00 2001 From: Andreas Fitzek Date: Tue, 1 Apr 2014 16:50:03 +0200 Subject: PDFBOX Table generation incl. QR Code detection and Positioning is done --- pdf-as-common/build.gradle | 2 +- .../pdfas/common/settings/IProfileConstants.java | 1 + .../common/settings/SignatureProfileSettings.java | 9 + .../java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java | 177 +---------- .../lib/impl/placeholder/PlaceholderFilter.java | 69 ++++ .../lib/impl/signing/pdfbox/PADESPDFBOXSigner.java | 353 +++++++++++++++------ .../egiz/pdfas/lib/impl/stamping/IPDFStamper.java | 4 +- .../pdfas/lib/impl/stamping/StamperFactory.java | 3 +- .../impl/stamping/pdfbox/PDFAsTemplateCreator.java | 6 +- .../pdfbox/PDFAsVisualSignatureBuilder.java | 344 +++++++++++--------- .../pdfbox/PDFAsVisualSignatureDesigner.java | 24 +- .../pdfbox/PDFAsVisualSignatureProperties.java | 41 +-- .../pdfas/lib/impl/stamping/pdfbox/PDFBoxFont.java | 146 +++++++++ .../lib/impl/stamping/pdfbox/PDFBoxTable.java | 161 +++++++--- .../lib/impl/stamping/pdfbox/PdfBoxStamper.java | 106 +------ .../impl/stamping/pdfbox/PdfBoxVisualObject.java | 60 +++- .../gv/egiz/pdfas/lib/impl/status/PDFObject.java | 9 - .../at/knowcenter/wag/egov/egiz/table/Table.java | 14 +- .../resources/icm/sRGB Color Space Profile.icm | Bin 0 -> 3144 bytes .../icm/sRGB Color Space Profile.icm.LICENSE.txt | 14 + pdf-as-web/.gitignore | 1 + 21 files changed, 907 insertions(+), 637 deletions(-) create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/PlaceholderFilter.java create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFBoxFont.java create mode 100644 pdf-as-lib/src/main/resources/icm/sRGB Color Space Profile.icm create mode 100644 pdf-as-lib/src/main/resources/icm/sRGB Color Space Profile.icm.LICENSE.txt diff --git a/pdf-as-common/build.gradle b/pdf-as-common/build.gradle index 0198dc31..484b31b4 100644 --- a/pdf-as-common/build.gradle +++ b/pdf-as-common/build.gradle @@ -13,7 +13,7 @@ repositories { dependencies { compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.5' - compile group: 'org.apache.pdfbox', name: 'pdfbox', version: '1.8.2' + compile group: 'org.apache.pdfbox', name: 'pdfbox', version: '1.8.4' compile group: 'commons-collections', name: 'commons-collections', version: '3.2' compile group: 'ognl', name: 'ognl', version: '3.0.6' testCompile group: 'junit', name: 'junit', version: '4.+' diff --git a/pdf-as-common/src/main/java/at/gv/egiz/pdfas/common/settings/IProfileConstants.java b/pdf-as-common/src/main/java/at/gv/egiz/pdfas/common/settings/IProfileConstants.java index 1ed90cec..02780b8c 100644 --- a/pdf-as-common/src/main/java/at/gv/egiz/pdfas/common/settings/IProfileConstants.java +++ b/pdf-as-common/src/main/java/at/gv/egiz/pdfas/common/settings/IProfileConstants.java @@ -89,4 +89,5 @@ public interface IProfileConstants { public final static String TMP_DIR_DEFAULT_VALUE = "pdfastmp"; public final static String SIGNING_REASON = "adobeSignReasonValue"; + public final static String SIG_PDFA1B_VALID = "SIG_PDFA1B_VALID"; } diff --git a/pdf-as-common/src/main/java/at/gv/egiz/pdfas/common/settings/SignatureProfileSettings.java b/pdf-as-common/src/main/java/at/gv/egiz/pdfas/common/settings/SignatureProfileSettings.java index 8af69382..84a9e6f8 100644 --- a/pdf-as-common/src/main/java/at/gv/egiz/pdfas/common/settings/SignatureProfileSettings.java +++ b/pdf-as-common/src/main/java/at/gv/egiz/pdfas/common/settings/SignatureProfileSettings.java @@ -190,4 +190,13 @@ public class SignatureProfileSettings implements IProfileConstants { public String getSigningReason() { return this.getValue(SIGNING_REASON); } + + public boolean isPDFA() { + SignatureProfileEntry entry = profileInformations.get(SIG_PDFA1B_VALID); + if (entry != null) { + String value = entry.getCaption(); + return "true".equals(value); + } + return false; + } } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java index 3fdfb576..7946f966 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java @@ -26,7 +26,6 @@ package at.gv.egiz.pdfas.lib.impl; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; @@ -39,7 +38,6 @@ import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.encryption.AccessPermission; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +47,6 @@ import at.gv.egiz.pdfas.common.exceptions.PdfAsSettingsException; import at.gv.egiz.pdfas.common.exceptions.PdfAsValidationException; import at.gv.egiz.pdfas.common.settings.ISettings; import at.gv.egiz.pdfas.common.settings.Settings; -import at.gv.egiz.pdfas.common.settings.SignatureProfileSettings; import at.gv.egiz.pdfas.common.utils.PDFUtils; import at.gv.egiz.pdfas.lib.api.Configuration; import at.gv.egiz.pdfas.lib.api.IConfigurationConstants; @@ -60,27 +57,14 @@ import at.gv.egiz.pdfas.lib.api.sign.SignResult; import at.gv.egiz.pdfas.lib.api.verify.VerifyParameter; import at.gv.egiz.pdfas.lib.api.verify.VerifyResult; import at.gv.egiz.pdfas.lib.impl.configuration.ConfigurationImpl; -import at.gv.egiz.pdfas.lib.impl.configuration.PlaceholderConfiguration; -import at.gv.egiz.pdfas.lib.impl.configuration.SignatureProfileConfiguration; -import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData; -import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderExtractor; -import at.gv.egiz.pdfas.lib.impl.positioning.Positioning; import at.gv.egiz.pdfas.lib.impl.signing.IPdfSigner; import at.gv.egiz.pdfas.lib.impl.signing.PdfSignerFactory; import at.gv.egiz.pdfas.lib.impl.signing.pdfbox.PdfboxSignerWrapper; import at.gv.egiz.pdfas.lib.impl.signing.sig_interface.SignatureDataExtractor; -import at.gv.egiz.pdfas.lib.impl.stamping.IPDFStamper; -import at.gv.egiz.pdfas.lib.impl.stamping.IPDFVisualObject; -import at.gv.egiz.pdfas.lib.impl.stamping.StamperFactory; -import at.gv.egiz.pdfas.lib.impl.stamping.TableFactory; import at.gv.egiz.pdfas.lib.impl.status.OperationStatus; import at.gv.egiz.pdfas.lib.impl.status.RequestedSignature; import at.gv.egiz.pdfas.lib.impl.verify.IVerifyFilter; import at.gv.egiz.pdfas.lib.impl.verify.VerifierDispatcher; -import at.knowcenter.wag.egov.egiz.pdf.PDFUtilities; -import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; -import at.knowcenter.wag.egov.egiz.pdf.TablePos; -import at.knowcenter.wag.egov.egiz.table.Table; public class PdfAsImpl implements PdfAs, IConfigurationConstants { @@ -158,8 +142,8 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants { ISettings settings = (ISettings) parameter.getConfiguration(); OperationStatus status = new OperationStatus(settings, parameter); - PlaceholderConfiguration placeholderConfiguration = status - .getPlaceholderConfiguration(); + //PlaceholderConfiguration placeholderConfiguration = status + // .getPlaceholderConfiguration(); RequestedSignature requestedSignature = new RequestedSignature( status); @@ -184,7 +168,7 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants { status.getPdfObject().setOriginalDocument( parameter.getDataSource().getByteData()); - this.stampPdf(status); + //this.stampPdf(status); // Create signature IPdfSigner signer = PdfSignerFactory.createPdfSigner(); @@ -371,7 +355,7 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants { status.getSignParamter().getDataSource().getByteData()); // STAMPER! - stampPdf(status); + //stampPdf(status); request.setNeedCertificate(false); status.setSigningDate(Calendar.getInstance()); @@ -450,159 +434,6 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants { } } - private boolean checkPlaceholderSignature(OperationStatus status) - throws PdfAsException, IOException { - if (status.getPlaceholderConfiguration().isGlobalPlaceholderEnabled()) { - SignaturePlaceholderData signaturePlaceholderData = SignaturePlaceholderExtractor - .extract(new ByteArrayInputStream(status.getPdfObject() - .getOriginalDocument()), null, 1); - - if (signaturePlaceholderData != null) { - RequestedSignature requestedSignature = status - .getRequestedSignature(); - - if (signaturePlaceholderData.getProfile() != null) { - requestedSignature - .setSignatureProfileID(signaturePlaceholderData - .getProfile()); - } - - String signatureProfileID = requestedSignature - .getSignatureProfileID(); - - TablePos tablePos = signaturePlaceholderData.getTablePos(); - - SignatureProfileSettings signatureProfileSettings = TableFactory - .createProfile(signatureProfileID, settings); - - Table main = TableFactory.createSigTable( - signatureProfileSettings, MAIN, settings, - requestedSignature); - - IPDFStamper stamper = StamperFactory - .createDefaultStamper(settings); - IPDFVisualObject visualObject = stamper.createVisualPDFObject( - status.getPdfObject(), main); - - PDDocument originalDocument = PDDocument - .load(new ByteArrayInputStream(status.getPdfObject() - .getOriginalDocument())); - - PositioningInstruction positioningInstruction = Positioning - .determineTablePositioning(tablePos, "", - originalDocument, visualObject, false); - - // ================================================================ - // StampingStage (visual) -> stamp logical signature block to - // location (itext) - - byte[] incrementalUpdate = stamper.writeVisualObject( - visualObject, positioningInstruction, status - .getPdfObject().getOriginalDocument(), - signaturePlaceholderData.getPlaceholderName()); - - 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); - - status.getPdfObject().setStampedDocument(incrementalUpdate); - return true; - } - } - return false; - } - - private void stampPdf(OperationStatus status) throws PdfAsException, - IOException { - - RequestedSignature requestedSignature = status.getRequestedSignature(); - String signatureProfileID = requestedSignature.getSignatureProfileID(); - SignatureProfileConfiguration signatureProfileConfiguration = status - .getSignatureProfileConfiguration(signatureProfileID); - - if (checkPlaceholderSignature(status)) { - logger.info("Placeholder found for Signature"); - return; - } - - if (requestedSignature.isVisual() && false) { - logger.info("Creating visual siganture block"); - // ================================================================ - // SignBlockCreationStage (visual) -> create visual signature - // block (logicaly) - SignatureProfileSettings signatureProfileSettings = TableFactory - .createProfile(signatureProfileID, settings); - - Table main = TableFactory.createSigTable(signatureProfileSettings, - MAIN, settings, requestedSignature); - - IPDFStamper stamper = StamperFactory.createDefaultStamper(settings); - IPDFVisualObject visualObject = stamper.createVisualPDFObject( - status.getPdfObject(), main); - - // ================================================================ - // PositioningStage (visual) -> find position or use fixed - // position - - String posString = status.getSignParamter().getSignaturePosition(); - - if (posString == null) { - posString = signatureProfileConfiguration - .getDefaultPositioning(); - } - - logger.debug("using Positioning: " + posString); - - boolean legacy32Position = signatureProfileConfiguration - .getLegacy32Positioning(); - - TablePos tablePos = null; - - if (posString == null) { - tablePos = new TablePos(); - } else { - tablePos = new TablePos(posString); - } - - PDDocument originalDocument = PDDocument - .load(new ByteArrayInputStream(status.getPdfObject() - .getOriginalDocument())); - - PositioningInstruction positioningInstruction = Positioning - .determineTablePositioning(tablePos, "", originalDocument, - visualObject, legacy32Position); - - // ================================================================ - // StampingStage (visual) -> stamp logical signature block to - // location (itext) - - byte[] incrementalUpdate = stamper.writeVisualObject(visualObject, - positioningInstruction, status.getPdfObject() - .getOriginalDocument(), null); - - 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); - - status.getPdfObject().setStampedDocument(incrementalUpdate); - } else { - logger.info("No visual siganture block"); - // Stamped Object is equal to original - status.getPdfObject().setStampedDocument( - status.getPdfObject().getOriginalDocument()); - } - } - private SignResult createSignResult(OperationStatus status) throws IOException { // ================================================================ diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/PlaceholderFilter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/PlaceholderFilter.java new file mode 100644 index 00000000..a4d2c7aa --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/PlaceholderFilter.java @@ -0,0 +1,69 @@ +package at.gv.egiz.pdfas.lib.impl.placeholder; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import at.gv.egiz.pdfas.common.exceptions.PdfAsException; +import at.gv.egiz.pdfas.common.settings.ISettings; +import at.gv.egiz.pdfas.lib.api.IConfigurationConstants; +import at.gv.egiz.pdfas.lib.impl.status.OperationStatus; + +public class PlaceholderFilter implements IConfigurationConstants { + + public static SignaturePlaceholderData checkPlaceholderSignature( + OperationStatus status, ISettings settings) + throws PdfAsException, IOException { + + if (status.getPlaceholderConfiguration().isGlobalPlaceholderEnabled()) { + SignaturePlaceholderData signaturePlaceholderData = SignaturePlaceholderExtractor + .extract(new ByteArrayInputStream(status.getPdfObject() + .getOriginalDocument()), null, 1); + + return signaturePlaceholderData; + /* + if (signaturePlaceholderData != null) { + RequestedSignature requestedSignature = status + .getRequestedSignature(); + + if (signaturePlaceholderData.getProfile() != null) { + requestedSignature + .setSignatureProfileID(signaturePlaceholderData + .getProfile()); + } + + //String signatureProfileID = requestedSignature + // .getSignatureProfileID(); + + TablePos tablePos = signaturePlaceholderData.getTablePos(); + + return tablePos; + + */ + /* + SignatureProfileSettings signatureProfileSettings = TableFactory + .createProfile(signatureProfileID, settings); + + Table main = TableFactory.createSigTable( + signatureProfileSettings, MAIN, settings, + requestedSignature); + + IPDFStamper stamper = StamperFactory + .createDefaultStamper(settings); + + IPDFVisualObject visualObject = stamper.createVisualPDFObject( + status.getPdfObject(), main); + + PDDocument originalDocument = PDDocument + .load(new ByteArrayInputStream(status.getPdfObject() + .getOriginalDocument())); + + PositioningInstruction positioningInstruction = Positioning + .determineTablePositioning(tablePos, "", + originalDocument, visualObject, false); + + return positioningInstruction;*/ + //} + } + return null; + } +} 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 651c2e49..767887b3 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 @@ -29,12 +29,21 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; import java.util.Calendar; +import java.util.List; +import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.exceptions.COSVisitorException; import org.apache.pdfbox.exceptions.SignatureException; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentCatalog; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageNode; +import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent; +import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions; import org.slf4j.Logger; @@ -45,111 +54,275 @@ import at.gv.egiz.pdfas.common.messages.MessageResolver; import at.gv.egiz.pdfas.common.settings.SignatureProfileSettings; import at.gv.egiz.pdfas.common.utils.StreamUtils; import at.gv.egiz.pdfas.common.utils.TempFileHelper; +import at.gv.egiz.pdfas.lib.api.IConfigurationConstants; +import at.gv.egiz.pdfas.lib.impl.SignaturePositionImpl; +import at.gv.egiz.pdfas.lib.impl.configuration.SignatureProfileConfiguration; +import at.gv.egiz.pdfas.lib.impl.placeholder.PlaceholderFilter; +import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData; +import at.gv.egiz.pdfas.lib.impl.positioning.Positioning; import at.gv.egiz.pdfas.lib.impl.signing.IPdfSigner; import at.gv.egiz.pdfas.lib.impl.signing.sig_interface.PDFASSignatureInterface; +import at.gv.egiz.pdfas.lib.impl.stamping.IPDFStamper; +import at.gv.egiz.pdfas.lib.impl.stamping.IPDFVisualObject; +import at.gv.egiz.pdfas.lib.impl.stamping.StamperFactory; import at.gv.egiz.pdfas.lib.impl.stamping.TableFactory; import at.gv.egiz.pdfas.lib.impl.stamping.ValueResolver; import at.gv.egiz.pdfas.lib.impl.stamping.pdfbox.PDFAsVisualSignatureProperties; +import at.gv.egiz.pdfas.lib.impl.stamping.pdfbox.PdfBoxVisualObject; import at.gv.egiz.pdfas.lib.impl.status.PDFObject; import at.gv.egiz.pdfas.lib.impl.status.RequestedSignature; +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; +import at.knowcenter.wag.egov.egiz.pdf.TablePos; +import at.knowcenter.wag.egov.egiz.table.Table; -public class PADESPDFBOXSigner implements IPdfSigner { +public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants { - private static final Logger logger = LoggerFactory.getLogger(PADESPDFBOXSigner.class); + private static final Logger logger = LoggerFactory + .getLogger(PADESPDFBOXSigner.class); - public void signPDF(PDFObject pdfObject, RequestedSignature requestedSignature, - PDFASSignatureInterface signer) - throws PdfAsException { - String fisTmpFile = null; - - TempFileHelper helper = pdfObject.getStatus().getTempFileHelper(); - - try { - fisTmpFile = helper.getStaticFilename(); + public void signPDF(PDFObject pdfObject, + RequestedSignature requestedSignature, + PDFASSignatureInterface signer) throws PdfAsException { + String fisTmpFile = null; - // write to temporary file - FileOutputStream fos = new FileOutputStream(new File(fisTmpFile)); - fos.write(pdfObject.getStampedDocument()); + TempFileHelper helper = pdfObject.getStatus().getTempFileHelper(); + try { + fisTmpFile = helper.getStaticFilename(); - FileInputStream fis = new FileInputStream(new File(fisTmpFile)); + // write to temporary file + FileOutputStream fos = new FileOutputStream(new File(fisTmpFile)); + fos.write(pdfObject.getOriginalDocument()); - PDDocument doc = PDDocument.load( - new ByteArrayInputStream(pdfObject.getStampedDocument())); + FileInputStream fis = new FileInputStream(new File(fisTmpFile)); - PDSignature signature = new PDSignature(); - signature.setFilter(COSName.getPDFName(signer.getPDFFilter())); // default filter - signature.setSubFilter(COSName.getPDFName(signer.getPDFSubFilter())); + PDDocument doc = PDDocument.load(new ByteArrayInputStream(pdfObject + .getOriginalDocument())); - SignatureProfileSettings signatureProfileSettings = TableFactory - .createProfile(requestedSignature.getSignatureProfileID(), + 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(); - String signerName = resolver.resolve("SIG_SUBJECT", signatureProfileSettings.getValue("SIG_SUBJECT"), - signatureProfileSettings, requestedSignature); - - signature.setName(signerName); - signature.setSignDate(Calendar.getInstance()); - 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); - SignatureOptions options = new SignatureOptions(); - - // FOR DEVELOPING: Call custom visual signature creation - PDFAsVisualSignatureProperties properties = new PDFAsVisualSignatureProperties( - pdfObject.getStatus().getSettings(), pdfObject); - properties.buildSignature(); - - 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); - - // pdfbox patched (FIS -> IS) - doc.saveIncremental(fis, fos); - fis.close(); - fos.close(); - - fis = new FileInputStream(new File(fisTmpFile)); - - // write to resulting output stream - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - bos.write(StreamUtils.inputStreamToByteArray(fis)); - fis.close(); - bos.close(); - - pdfObject.setSignedDocument(bos.toByteArray()); - - helper.deleteFile(fisTmpFile); - - } catch (IOException e) { - logger.error(MessageResolver.resolveMessage("error.pdf.sig.01"), e); - throw new PdfAsException("error.pdf.sig.01", e); - } catch(SignatureException e) { - logger.error(MessageResolver.resolveMessage("error.pdf.sig.01"), e); - throw new PdfAsException("error.pdf.sig.01", e); - } catch (COSVisitorException e) { - logger.error(MessageResolver.resolveMessage("error.pdf.sig.01"), e); - throw new PdfAsException("error.pdf.sig.01", e); - } - } + + ValueResolver resolver = new ValueResolver(); + String signerName = resolver.resolve("SIG_SUBJECT", + signatureProfileSettings.getValue("SIG_SUBJECT"), + signatureProfileSettings, requestedSignature); + + signature.setName(signerName); + signature.setSignDate(Calendar.getInstance()); + 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); + SignatureOptions options = new SignatureOptions(); + + // Is visible Signature + if (requestedSignature.isVisual()) { + logger.info("Creating visual siganture block"); + + SignatureProfileConfiguration signatureProfileConfiguration = pdfObject + .getStatus().getSignatureProfileConfiguration( + requestedSignature.getSignatureProfileID()); + + SignaturePlaceholderData signaturePlaceholderData = PlaceholderFilter + .checkPlaceholderSignature(pdfObject.getStatus(), + pdfObject.getStatus().getSettings()); + + TablePos tablePos = null; + + if (signaturePlaceholderData != null) { + // Placeholder found! + + if (signaturePlaceholderData.getProfile() != null) { + requestedSignature + .setSignatureProfileID(signaturePlaceholderData + .getProfile()); + } + + tablePos = signaturePlaceholderData.getTablePos(); + } + + if (tablePos == null) { + // ================================================================ + // PositioningStage (visual) -> find position or use fixed + // position + + String posString = pdfObject.getStatus().getSignParamter() + .getSignaturePosition(); + + if (posString == null) { + posString = signatureProfileConfiguration + .getDefaultPositioning(); + } + + logger.debug("using Positioning: " + posString); + + if (posString == null) { + tablePos = new TablePos(); + } else { + tablePos = new TablePos(posString); + } + } + boolean legacy32Position = signatureProfileConfiguration + .getLegacy32Positioning(); + + // create Table describtion + Table main = TableFactory.createSigTable( + signatureProfileSettings, MAIN, pdfObject.getStatus() + .getSettings(), 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, "", + originalDocument, visualObject, + legacy32Position); + + 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); + + PDFAsVisualSignatureProperties properties = new PDFAsVisualSignatureProperties( + pdfObject.getStatus().getSettings(), pdfObject, + (PdfBoxVisualObject) visualObject, + positioningInstruction); + + properties.buildSignature(); + + 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(); + + if (signaturePlaceholderData != null) { + // Placeholder found! + // replace placeholder + InputStream 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 kids = new ArrayList(); + rootPages.getAllKids(kids); + int pageNumber = positioningInstruction.getPage(); + rootPages.getAllKids(kids); + PDPage page = kids.get(pageNumber); + + 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()); + } + + if (positioningInstruction.isMakeNewPage()) { + int last = doc.getNumberOfPages() - 1; + PDDocumentCatalog root = doc.getDocumentCatalog(); + PDPageNode rootPages = root.getPages(); + List kids = new ArrayList(); + rootPages.getAllKids(kids); + PDPage lastPage = kids.get(last); + rootPages.getCOSObject().setNeedToBeUpdate(true); + PDPage p = new PDPage(lastPage.findMediaBox()); + + doc.addPage(p); + } + + if (signatureProfileSettings.isPDFA()) { + PDDocumentCatalog root = doc.getDocumentCatalog(); + InputStream 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) { + e.printStackTrace(); + throw new PdfAsException("Failed to add Output Intent", + e); + } + } + + options.setPreferedSignatureSize(0x1000); + options.setPage(positioningInstruction.getPage()); + options.setVisualSignature(new ByteArrayInputStream(sigbos + .toByteArray())); + } + + doc.addSignature(signature, signer, options); + + // pdfbox patched (FIS -> IS) + doc.saveIncremental(fis, fos); + fis.close(); + fos.close(); + + fis = new FileInputStream(new File(fisTmpFile)); + + // write to resulting output stream + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + bos.write(StreamUtils.inputStreamToByteArray(fis)); + fis.close(); + bos.close(); + + pdfObject.setSignedDocument(bos.toByteArray()); + + helper.deleteFile(fisTmpFile); + + } catch (IOException e) { + logger.error(MessageResolver.resolveMessage("error.pdf.sig.01"), e); + throw new PdfAsException("error.pdf.sig.01", e); + } catch (SignatureException e) { + logger.error(MessageResolver.resolveMessage("error.pdf.sig.01"), e); + throw new PdfAsException("error.pdf.sig.01", e); + } catch (COSVisitorException e) { + logger.error(MessageResolver.resolveMessage("error.pdf.sig.01"), e); + throw new PdfAsException("error.pdf.sig.01", e); + } + } } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/IPDFStamper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/IPDFStamper.java index 6de356ed..22e20767 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/IPDFStamper.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/IPDFStamper.java @@ -23,6 +23,8 @@ ******************************************************************************/ package at.gv.egiz.pdfas.lib.impl.stamping; +import java.io.IOException; + import at.gv.egiz.pdfas.common.exceptions.PdfAsException; import at.gv.egiz.pdfas.common.settings.ISettings; import at.gv.egiz.pdfas.lib.impl.status.PDFObject; @@ -30,7 +32,7 @@ import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; import at.knowcenter.wag.egov.egiz.table.Table; public interface IPDFStamper { - public IPDFVisualObject createVisualPDFObject(PDFObject pdf, Table table); + public IPDFVisualObject createVisualPDFObject(PDFObject pdf, Table table) throws IOException; public byte[] writeVisualObject(IPDFVisualObject visualObject, PositioningInstruction positioningInstruction, byte[] pdfData, String placeholderName) throws PdfAsException; diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/StamperFactory.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/StamperFactory.java index 05bccc89..42dee32d 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/StamperFactory.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/StamperFactory.java @@ -28,7 +28,8 @@ import at.gv.egiz.pdfas.common.settings.ISettings; public class StamperFactory { - public static final String DEFAULT_STAMPER_CLASS = "at.gv.egiz.pdfas.stmp.itext.ITextStamper"; + //public static final String DEFAULT_STAMPER_CLASS = "at.gv.egiz.pdfas.stmp.itext.ITextStamper"; + public static final String DEFAULT_STAMPER_CLASS = "at.gv.egiz.pdfas.lib.impl.stamping.pdfbox.PdfBoxStamper"; public static IPDFStamper createDefaultStamper(ISettings settings) throws PdfAsException { try { 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 index 058b08b0..e7582137 100644 --- 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 @@ -1,12 +1,10 @@ package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; -import java.awt.geom.AffineTransform; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.exceptions.COSVisitorException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -14,10 +12,8 @@ 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; @@ -66,7 +62,7 @@ public class PDFAsTemplateCreator extends PDFTemplateCreator { // create AffineTransform this.pdfBuilder.createAffineTransform(properties.getAffineTransformParams()); - AffineTransform transform = pdfStructure.getAffineTransform(); + //AffineTransform transform = pdfStructure.getAffineTransform(); // rectangle, formatter, image. /AcroForm/DR/XObject contains that form this.pdfBuilder.createSignatureRectangle(pdSignatureField, properties); 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 49d7b4bd..8da6d149 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,15 @@ package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; import java.awt.Color; -import java.awt.Image; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -19,13 +18,13 @@ import javax.imageio.ImageIO; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; -import org.apache.pdfbox.cos.COSStream; 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.PDFont; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg; import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; @@ -45,7 +44,6 @@ import at.gv.egiz.pdfas.common.settings.ISettings; import at.gv.egiz.pdfas.lib.test.mains.TestPDFBoxTable; import at.knowcenter.wag.egov.egiz.table.Entry; import at.knowcenter.wag.egov.egiz.table.Style; -import at.knowcenter.wag.egov.egiz.table.Table; public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { @@ -53,14 +51,16 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { .getLogger(TestPDFBoxTable.class); private void drawTable(PDPage page, PDPageContentStream contentStream, - float x, float y, PDFBoxTable abstractTable, PDDocument doc, boolean subtable) - throws IOException, PdfAsException { + float x, float y, PDFBoxTable abstractTable, PDDocument doc, + boolean subtable) throws IOException, PdfAsException { final int rows = abstractTable.getRowCount(); final int cols = abstractTable.getColCount(); float[] colsSizes = abstractTable.getColsRelativeWith(); int max_cols = abstractTable.getColCount(); float padding = abstractTable.getPadding(); + float fontSize = PDFBoxFont.defaultFontSize; + PDFont textFont = PDFBoxFont.defaultFont; if (colsSizes == null) { colsSizes = new float[max_cols]; // set the column ratio for all columns to 1 @@ -71,11 +71,13 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { logger.info("Drawing Table:"); abstractTable.dumpTable(); - - contentStream.setNonStrokingColor(Color.blue); - contentStream.fillRect(x, y, abstractTable.getWidth(), abstractTable.getHeight()); - contentStream.setNonStrokingColor(Color.BLACK); - + + if(abstractTable.getBGColor() != null) { + contentStream.setNonStrokingColor(abstractTable.getBGColor()); + contentStream.fillRect(x, y, abstractTable.getWidth(), + abstractTable.getHeight()); + contentStream.setNonStrokingColor(Color.BLACK); + } float total = 0; for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) { @@ -91,15 +93,16 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { logger.info("Col: " + cols_idx + " : " + colsSizes[cols_idx]); } - contentStream.setLineWidth(0.1f); + float border = abstractTable.style.getBorder(); + contentStream.setLineWidth(border); float tableHeight = abstractTable.getHeight(); float tableWidth = abstractTable.getWidth(); final float colWidth = tableWidth / (float) cols; - // TODO: check boarder width - if (1 != 0) { - + // draw if boarder > 0 + if (border != 0) { + // draw the rows float nexty = y + tableHeight; for (int i = 0; i <= rows; i++) { @@ -109,7 +112,7 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { if (i < abstractTable.getRowHeights().length) { nexty -= abstractTable.getRowHeights()[i] + padding * 2; } - if(subtable && i+1 == abstractTable.getRowHeights().length) { + if (subtable && i + 1 == abstractTable.getRowHeights().length) { nexty -= padding; } } @@ -118,14 +121,17 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { float nextx = x; float ypos = y; float yheight = y + abstractTable.getHeight(); - if(subtable) { + if (subtable) { ypos -= padding; yheight = y + abstractTable.getHeight(); } for (int i = 0; i <= cols; i++) { - logger.info("COL LINE: {} {} {} {}", nextx, ypos, nextx, yheight); - contentStream.drawLine(nextx, ypos, nextx, + if(subtable && i == cols) { + continue; + } + logger.info("COL LINE: {} {} {} {}", nextx, ypos, nextx, yheight); + contentStream.drawLine(nextx, ypos, nextx, yheight); if (i < colsSizes.length) { nextx += (colsSizes != null) ? colsSizes[i] : colWidth; } @@ -135,24 +141,43 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { float textx = x + padding; float texty = y + tableHeight; for (int i = 0; i < abstractTable.getRowCount(); i++) { - ArrayList row = abstractTable.getRow(i); + ArrayList row = abstractTable.getRow(i); for (int j = 0; j < row.size(); j++) { Entry cell = (Entry) row.get(j); if (cell.getType() == Entry.TYPE_CAPTION || cell.getType() == Entry.TYPE_VALUE) { + + if (cell.getType() == Entry.TYPE_CAPTION) { + textFont = abstractTable.getFont().getFont(doc); + fontSize = abstractTable.getFont().getFontSize(); + } else if (cell.getType() == Entry.TYPE_VALUE) { + textFont = abstractTable.getValueFont().getFont(doc); + fontSize = abstractTable.getValueFont().getFontSize(); + } + String text = (String) cell.getValue(); - float fontsize = 5.f; - float ttexty = texty - padding - fontsize; - COSName name = COSName.getPDFName("ANDI_TAG!"); - contentStream.beginMarkedContentSequence(COSName.ALT, name); + float ttexty = texty - padding - fontSize; + // COSName name = COSName.getPDFName("ANDI_TAG!"); + // contentStream.beginMarkedContentSequence(COSName.ALT, + // name); + String fontName = textFont.equals(PDType1Font.COURIER) ? "COURIER" : "HELVETICA"; + contentStream.beginText(); + + if(innerFormResources.getFonts().containsValue(textFont)) { + String fontID = getFontID(textFont); + logger.info("Using Font: " + fontID); + contentStream.appendRawCommands("/" + fontID + " " + fontSize + " Tf\n"); + } else { + contentStream.setFont(textFont, fontSize); + } logger.info("Writing: " + textx + " : " + ttexty + " = " - + text); + + text + " as " + cell.getType() + " w " + fontName); contentStream.moveTextPositionByAmount(textx, ttexty); if (text.contains("\n")) { String[] lines = text.split("\n"); - contentStream.appendRawCommands(fontsize + " TL\n"); + contentStream.appendRawCommands(fontSize + " TL\n"); for (int k = 0; k < lines.length; k++) { contentStream.drawString(lines[k]); if (k < lines.length - 1) { @@ -163,67 +188,87 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { contentStream.drawString(text); } contentStream.endText(); - contentStream.endMarkedContentSequence(); + // contentStream.endMarkedContentSequence(); } else if (cell.getType() == Entry.TYPE_IMAGE) { String img_ref = (String) cell.getValue(); - if(!images.containsKey(img_ref)) { + if (!images.containsKey(img_ref)) { logger.error("Image not prepared! : " + img_ref); - throw new PdfAsException("Image not prepared! : " + img_ref); + throw new PdfAsException("Image not prepared! : " + + img_ref); } ImageObject image = images.get(img_ref); PDXObjectImage pdImage = image.getImage(); // text = "Row :" + i + "COL: " + j; - COSName name = COSName.getPDFName("ANDI_TAG!"); - contentStream.beginMarkedContentSequence(COSName.ALT, name); - + // COSName name = COSName.getPDFName("ANDI_TAG!"); + // contentStream.beginMarkedContentSequence(COSName.ALT, + // name); + float imgy = texty; - if(cell.getStyle().getImageVAlign() != null && - cell.getStyle().getImageVAlign().equals(Style.TOP)) { + if (cell.getStyle().getImageVAlign() != null + && cell.getStyle().getImageVAlign() + .equals(Style.TOP)) { imgy = texty - padding - image.getSize(); - } else if(cell.getStyle().getImageVAlign() != null && - cell.getStyle().getImageVAlign().equals(Style.BOTTOM)) { + } else if (cell.getStyle().getImageVAlign() != null + && cell.getStyle().getImageVAlign() + .equals(Style.BOTTOM)) { // Should allready be at bottom ... - imgy = texty - abstractTable.getRowHeights()[i] + padding; + imgy = texty - abstractTable.getRowHeights()[i] + + padding; } else { // default to middle - imgy = texty - padding - abstractTable.getRowHeights()[i] / 2; + imgy = texty - padding + - abstractTable.getRowHeights()[i] / 2; imgy = imgy - image.getSize() / 2; } logger.info("Image: " + textx + " : " + imgy); - contentStream.drawXObject(pdImage, textx, imgy, + contentStream.drawXObject(pdImage, textx, imgy, image.getSize(), image.getSize()); - contentStream.endMarkedContentSequence(); - + // contentStream.endMarkedContentSequence(); + } else if (cell.getType() == Entry.TYPE_TABLE) { - float tableY = texty - abstractTable.getRowHeights()[i] - padding; + float tableY = texty - abstractTable.getRowHeights()[i] + - padding; float tableX = textx; - //texty = texty - padding; + // texty = texty - padding; tableX = textx - padding; PDFBoxTable tbl_value = (PDFBoxTable) cell.getValue(); - logger.info("Table: " + tableX + " : " + tableY ); - drawTable(page, contentStream, tableX, tableY, tbl_value, doc, true); + logger.info("Table: " + tableX + " : " + tableY); + drawTable(page, contentStream, tableX, tableY, tbl_value, + doc, true); } textx += (colsSizes != null) ? colsSizes[j] : colWidth; } - //if (i + 1 < abstractTable.getRowHeights().length) { - logger.info("Row {} from {} - {} - {} = {}", i, texty, - abstractTable.getRowHeights()[i], padding * 2, - texty - (abstractTable.getRowHeights()[i] + padding * 2)); - texty -= abstractTable.getRowHeights()[i] + padding * 2; - //texty = texty - abstractTable.getRowHeights()[i + 1] - padding - // * 2; - //texty = texty - abstractTable.getRowHeights()[i] - padding - // * 2; - //} + // if (i + 1 < abstractTable.getRowHeights().length) { + logger.info("Row {} from {} - {} - {} = {}", i, texty, + abstractTable.getRowHeights()[i], padding * 2, texty + - (abstractTable.getRowHeights()[i] + padding * 2)); + texty -= abstractTable.getRowHeights()[i] + padding * 2; + // texty = texty - abstractTable.getRowHeights()[i + 1] - padding + // * 2; + // texty = texty - abstractTable.getRowHeights()[i] - padding + // * 2; + // } textx = x + padding; } } private PDFAsVisualSignatureProperties properties; private ISettings settings; + private List addedFonts = new ArrayList(); private PDResources innerFormResources; private Map images = new HashMap(); + private String getFontID(PDFont font) { + Iterator> it = innerFormResources.getFonts().entrySet().iterator(); + while(it.hasNext()) { + java.util.Map.Entry entry = it.next(); + if(entry.getValue().equals(font)) { + return entry.getKey(); + } + } + return ""; + } + public PDFAsVisualSignatureBuilder( PDFAsVisualSignatureProperties properties, ISettings settings) { this.properties = properties; @@ -250,99 +295,114 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { getStructure().setTemplate(template); } - @Override - public void createInnerFormStream(PDDocument template) { - try { - float[] colsSizes = properties.getMainTable().getColsRelativeWith(); - int max_cols = properties.getMainTable().getColCount(); - float padding = properties.getMainTable().getPadding(); - if (colsSizes == null) { - colsSizes = new float[max_cols]; - // set the column ratio for all columns to 1 - for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) { - colsSizes[cols_idx] = 1; - } + private void readTableResources(PDFBoxTable table, PDDocument template) throws PdfAsException, IOException { + + float[] colsSizes = table.getColsRelativeWith(); + int max_cols = table.getColCount(); + float padding = table.getPadding(); + if (colsSizes == null) { + colsSizes = new float[max_cols]; + // set the column ratio for all columns to 1 + for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) { + colsSizes[cols_idx] = 1; } + } - logger.info("TOTAL Width: " + properties.getMainTable().getWidth()); + logger.info("TOTAL Width: " + table.getWidth()); - float total = 0; + float total = 0; - for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) { - total += colsSizes[cols_idx]; - } + for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) { + total += colsSizes[cols_idx]; + } - for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) { - colsSizes[cols_idx] = (colsSizes[cols_idx] / total) - * properties.getMainTable().getWidth(); - } + for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) { + colsSizes[cols_idx] = (colsSizes[cols_idx] / total) + * table.getWidth(); + } - for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) { - logger.info("Col: " + cols_idx + " : " + colsSizes[cols_idx]); - } - - // Hint we have to create all PDXObjectImages before creating the - // PDPageContentStream - // only PDFbox developers know why ... - innerFormResources = new PDResources(); - for (int i = 0; i < properties.getMainTable().getRowCount(); i++) { - ArrayList row = properties.getMainTable().getRow(i); - for (int j = 0; j < row.size(); j++) { - Entry cell = (Entry) row.get(j); - if (cell.getType() == Entry.TYPE_IMAGE) { - String img_ref = (String) cell.getValue(); - if (!images.containsKey(img_ref)) { - File img_file = new File(img_ref); - if (!img_file.isAbsolute()) { - logger.debug("Image file declaration is relative. Prepending path of resources directory."); - logger.debug("Image Location: " - + settings.getWorkingDirectory() - + File.separator + img_ref); - img_file = new File( - settings.getWorkingDirectory() - + File.separator + img_ref); - } else { - logger.debug("Image file declaration is absolute. Skipping file relocation."); - } + for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) { + logger.info("Col: " + cols_idx + " : " + colsSizes[cols_idx]); + } - if (!img_file.exists()) { - logger.debug("Image file \"" - + img_file.getCanonicalPath() - + "\" doesn't exist."); - throw new PdfAsException("error.pdf.stamp.04"); - } + /*if(!addedFonts.contains(table.getFont().getFont(null))) { + PDFont font = table.getFont().getFont(template); + addedFonts.add(font); + innerFormResources.addFont(font); + } + + if(!addedFonts.contains(table.getValueFont().getFont(null))) { + PDFont font = table.getValueFont().getFont(template); + addedFonts.add(font); + innerFormResources.addFont(font); + }*/ + + for (int i = 0; i < table.getRowCount(); i++) { + ArrayList row = table.getRow(i); + for (int j = 0; j < row.size(); j++) { + Entry cell = (Entry) row.get(j); + if (cell.getType() == Entry.TYPE_IMAGE) { + String img_ref = (String) cell.getValue(); + if (!images.containsKey(img_ref)) { + File img_file = new File(img_ref); + if (!img_file.isAbsolute()) { + logger.debug("Image file declaration is relative. Prepending path of resources directory."); + logger.debug("Image Location: " + + settings.getWorkingDirectory() + + File.separator + img_ref); + img_file = new File(settings.getWorkingDirectory() + + File.separator + img_ref); + } else { + logger.debug("Image file declaration is absolute. Skipping file relocation."); + } - BufferedImage img = null; - try { - img = ImageIO.read(img_file); - } catch (IOException e) { - throw new PdfAsException("error.pdf.stamp.04", - e); - } - - float width = colsSizes[j]; - - int size = (int)Math.floor((double)width); - size -= 2*padding; - logger.debug("Scaling image to: " + size); - - PDXObjectImage pdImage = new PDJpeg(template, - img); - ImageObject image = new ImageObject(pdImage, size); - images.put(img_ref, image); - innerFormResources.addXObject(pdImage, "Im"); + if (!img_file.exists()) { + logger.debug("Image file \"" + + img_file.getCanonicalPath() + + "\" doesn't exist."); + throw new PdfAsException("error.pdf.stamp.04"); + } + + BufferedImage img = null; + try { + img = ImageIO.read(img_file); + } catch (IOException e) { + throw new PdfAsException("error.pdf.stamp.04", e); } + + float width = colsSizes[j]; + + int size = (int) Math.floor((double) width); + size -= 2 * padding; + logger.debug("Scaling image to: " + size); + + PDXObjectImage pdImage = new PDJpeg(template, img); + ImageObject image = new ImageObject(pdImage, size); + images.put(img_ref, image); + innerFormResources.addXObject(pdImage, "Im"); } + } else if(cell.getType() == Entry.TYPE_TABLE) { + PDFBoxTable tbl_value = (PDFBoxTable) cell.getValue(); + readTableResources(tbl_value, template); } } - - //innerFormResources.getCOSObject().setDirect(true); - // TODO create Fonts caption and Value - innerFormResources.addFont(PDType1Font.COURIER); + } + } + + @Override + public void createInnerFormStream(PDDocument template) { + try { + // Hint we have to create all PDXObjectImages before creating the + // PDPageContentStream + // only PDFbox developers know why ... + innerFormResources = new PDResources(); + getStructure().getPage().setResources(innerFormResources); + readTableResources(properties.getMainTable(), template); + PDPageContentStream stream = new PDPageContentStream(template, getStructure().getPage()); - stream.setFont(PDType1Font.COURIER, 5); + //stream.setFont(PDType1Font.COURIER, 5); drawTable(getStructure().getPage(), stream, 1, 1, properties.getMainTable(), template, false); @@ -619,24 +679,6 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder { os.close(); } - public void appendCosStreamCommands(OutputStream os, COSStream stream) - throws IOException { - // stream.getScratchFile(); - byte[] data = new byte[1024]; - long i = 0; - long pos = stream.getScratchFile().getPosition(); - stream.getScratchFile().seek(0); - while (i < stream.getScratchFile().length()) { - int read = stream.getScratchFile().read(data, 0, data.length); - i += read; - os.write(data, 0, read); - } - // /byte[] data = - // StreamUtils.inputStreamToByteArray(stream.getFilteredStream()); - // os.write(data); - os.close(); - } - public void createVisualSignature(PDDocument template) { this.getStructure().setVisualSignature(template.getDocument()); logger.info("Visible signature has been created"); 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 index f9e63a48..bd516100 100644 --- 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 @@ -49,9 +49,9 @@ public class PDFAsVisualSignatureDesigner { * - If we can't read, flush, or can't close stream */ public PDFAsVisualSignatureDesigner(PDDocument doc, int page, - PDFAsVisualSignatureProperties properties) throws IOException { + PDFAsVisualSignatureProperties properties, boolean newpage) throws IOException { this.properties = properties; - calculatePageSize(doc, page); + calculatePageSize(doc, page, newpage); } /** @@ -60,19 +60,25 @@ public class PDFAsVisualSignatureDesigner { * @param document * @param page */ - private void calculatePageSize(PDDocument document, int page) { + private void calculatePageSize(PDDocument document, int page, boolean newpage) { 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(); - + if(newpage) { + PDPage lastPage = (PDPage) pages.get(pages.size()-1); + PDRectangle mediaBox = lastPage.findMediaBox(); + this.pageHeight(mediaBox.getHeight()); + this.pageWidth = mediaBox.getWidth(); + } else { + 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; 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 24ef3881..05cce46d 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 @@ -1,26 +1,16 @@ package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; -import iaik.x509.X509Certificate; - import java.io.ByteArrayInputStream; -import java.io.FileInputStream; import java.io.IOException; import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.font.PDFont; -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.PDVisibleSigProperties; -import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.egiz.pdfas.common.settings.ISettings; -import at.gv.egiz.pdfas.common.settings.SignatureProfileSettings; -import at.gv.egiz.pdfas.lib.impl.stamping.TableFactory; import at.gv.egiz.pdfas.lib.impl.status.PDFObject; -import at.gv.egiz.pdfas.lib.test.mains.CertificateHolderRequest; -import at.knowcenter.wag.egov.egiz.table.Table; +import at.knowcenter.wag.egov.egiz.pdf.PositioningInstruction; public class PDFAsVisualSignatureProperties extends PDVisibleSigProperties { @@ -29,40 +19,25 @@ public class PDFAsVisualSignatureProperties extends PDVisibleSigProperties { private ISettings settings; private PDFBoxTable main; - private PDFont tableFont; private PDFAsVisualSignatureDesigner designer; - public PDFAsVisualSignatureProperties(ISettings settings, PDFObject object) { + public PDFAsVisualSignatureProperties(ISettings settings, PDFObject object, + PdfBoxVisualObject visObj, PositioningInstruction pos) { this.settings = settings; try { - SignatureProfileSettings profileSettings = TableFactory - .createProfile(object.getStatus().getRequestedSignature().getSignatureProfileID(), - settings); - //float width = object.getStatus().getRequestedSignature().getSignaturePosition().getWidth(); - object.getStatus().getRequestedSignature().getCertificate(); - X509Certificate cert = object.getStatus().getRequestedSignature().getCertificate(); - - CertificateHolderRequest request = new CertificateHolderRequest( - cert); - - Table mainTable = TableFactory.createSigTable(profileSettings, "main", - settings, request); - - main = new PDFBoxTable(mainTable, null, 230.f); - - //tableFont = PDFont. + main = visObj.getTable(); - //main.setWidth(100); } catch (Throwable e) { e.printStackTrace(); } try { PDDocument origDoc = PDDocument.load(new ByteArrayInputStream( - object.getStampedDocument())); + object.getOriginalDocument())); - designer = new PDFAsVisualSignatureDesigner(origDoc, 1, this); - designer.coordinates(100, 100); + designer = new PDFAsVisualSignatureDesigner(origDoc, pos.getPage(), this, pos.isMakeNewPage()); + float posy = designer.getPageHeight() - pos.getY(); + designer.coordinates(pos.getX(), posy); float[] form_rect = new float[] {0,0, main.getWidth() + 2, main.getHeight() + 2}; logger.info("AP Rect: {} {} {} {}", form_rect[0], form_rect[1], form_rect[2], form_rect[3]); designer.formaterRectangleParams(form_rect); diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFBoxFont.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFBoxFont.java new file mode 100644 index 00000000..62aaf5a8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFBoxFont.java @@ -0,0 +1,146 @@ +package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.pdfas.common.settings.ISettings; + +public class PDFBoxFont { + + private static final Logger logger = LoggerFactory + .getLogger(PDFBoxFont.class); + + private static final String HELVETICA = "HELVETICA"; + private static final String COURIER = "COURIER"; + private static final String TIMES_ROMAN = "TIMES_ROMAN"; + private static final String BOLD = "BOLD"; + private static final String NORMAL = "NORMAL"; + private static final String ITALIC = "ITALIC"; + private static final String SEP = ":"; + + public static PDFont defaultFont = PDType1Font.HELVETICA; + public static float defaultFontSize = 8; + + private static Map fontStyleMap = new HashMap(); + + static { + fontStyleMap.put(HELVETICA+SEP+NORMAL, PDType1Font.HELVETICA); + fontStyleMap.put(HELVETICA+SEP+BOLD, PDType1Font.HELVETICA_BOLD); + + fontStyleMap.put(COURIER+SEP+NORMAL, PDType1Font.COURIER); + fontStyleMap.put(COURIER+SEP+BOLD, PDType1Font.COURIER_BOLD); + + fontStyleMap.put(TIMES_ROMAN+SEP+NORMAL, PDType1Font.TIMES_ROMAN); + fontStyleMap.put(TIMES_ROMAN+SEP+BOLD, PDType1Font.TIMES_BOLD); + fontStyleMap.put(TIMES_ROMAN+SEP+ITALIC, PDType1Font.TIMES_ITALIC); + } + + public static void showBuildinFonts() { + Iterator it = fontStyleMap.keySet().iterator(); + logger.info("Available Fonts:"); + while(it.hasNext()) { + logger.info(it.next()); + } + } + + PDFont font; + PDFont cachedfont = null; + float fontSize; + String fontDesc; + String ttfFontDesc; + PDDocument doc; + ISettings settings; + + private PDFont generateTTF(String fonttype, PDDocument doc) throws IOException { + boolean cacheNow = false; + if(doc == null) { + if(this.doc == null) { + this.doc = new PDDocument(); + } + doc = this.doc; + } else { + cacheNow = true; + } + ttfFontDesc = fonttype; + String fontName = fonttype.replaceFirst("TTF:", ""); + + logger.debug("Instantiating font."); + String fontPath = this.settings.getWorkingDirectory() + File.separator + "fonts" + File.separator + fontName; + logger.debug("Instantiating \"" + fontPath + "\"."); + + if(cacheNow) { + cachedfont = PDTrueTypeFont.loadTTF(doc, fontPath); + return cachedfont; + } else { + return PDTrueTypeFont.loadTTF(doc, fontPath); + } + } + + private PDFont generateFont(String fonttype, String fontder) throws IOException { + if(fonttype.startsWith("TTF:")) { + // Load TTF Font + return generateTTF(fonttype, null); + } else { + if(fontder == null) { + fontder = NORMAL; + } + + String fontDesc = fonttype + SEP + fontder; + PDFont font = fontStyleMap.get(fontDesc); + if(font == null) { + showBuildinFonts(); + throw new IOException("Invalid font descriptor"); + } + return font; + } + } + + private void setFont(String desc) throws IOException { + String[] fontArr = desc.split(","); + + if(fontArr.length == 3) { + font = generateFont(fontArr[0], fontArr[2]); + fontSize = Integer.parseInt(fontArr[1]); + } else if(fontArr.length == 2 && fontArr[0].startsWith("TTF:")) { + font = generateFont(fontArr[0], null); + fontSize = Integer.parseInt(fontArr[1]); + } else { + logger.warn("Using default font because: {} is not a valid font descriptor.", desc); + this.font = defaultFont; + this.fontSize = defaultFontSize; + } + + } + + public PDFBoxFont(String fontDesc, ISettings settings) throws IOException { + this.settings = settings; + this.fontDesc = fontDesc; + logger.info("Creating Font: " + fontDesc); + this.setFont(fontDesc); + } + + public PDFont getFont(PDDocument doc) throws IOException { + if(cachedfont != null) { + return cachedfont; + } + if(font instanceof PDTrueTypeFont && doc != null) { + return generateTTF(ttfFontDesc, doc); + } else { + return font; + } + } + + public float getFontSize() { + return fontSize; + } +} diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFBoxTable.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFBoxTable.java index 6555b82d..2ef653d8 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFBoxTable.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFBoxTable.java @@ -1,5 +1,6 @@ package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; +import java.awt.Color; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -9,6 +10,7 @@ import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import at.gv.egiz.pdfas.common.settings.ISettings; import at.knowcenter.wag.egov.egiz.table.Entry; import at.knowcenter.wag.egov.egiz.table.Style; import at.knowcenter.wag.egov.egiz.table.Table; @@ -20,15 +22,16 @@ public class PDFBoxTable { Table table; Style style; - PDFont font; - PDFont valueFont; + PDFBoxFont font; + PDFBoxFont valueFont; + ISettings settings; float padding; int positionX = 0; int positionY = 0; float tableWidth; float tableHeight; - float fontSize; + Color bgColor; float[] rowHeights; float[] colWidths; @@ -50,17 +53,26 @@ public class PDFBoxTable { } String fontString = style.getFont(); - font = PDType1Font.COURIER; String vfontString = style.getValueFont(); - valueFont = font; + if (parent != null && style == parent.style) { + font = parent.getFont(); + valueFont = parent.getValueFont(); + } else { + + font = new PDFBoxFont(fontString, settings); + + valueFont = new PDFBoxFont(vfontString, settings); + } padding = style.getPadding(); - fontSize = 5f; + + bgColor = style.getBgColor(); } - public PDFBoxTable(Table abstractTable, PDFBoxTable parent, float fixSize) - throws IOException { + public PDFBoxTable(Table abstractTable, PDFBoxTable parent, float fixSize, + ISettings settings) throws IOException { + this.settings = settings; initializeStyle(abstractTable, parent); float[] relativSizes = abstractTable.getColsRelativeWith(); colWidths = new float[relativSizes.length]; @@ -80,8 +92,9 @@ public class PDFBoxTable { calculateHeightsBasedOnWidths(); } - public PDFBoxTable(Table abstractTable, PDFBoxTable parent) - throws IOException { + public PDFBoxTable(Table abstractTable, PDFBoxTable parent, + ISettings settings) throws IOException { + this.settings = settings; initializeStyle(abstractTable, parent); this.calculateWidthHeight(); } @@ -95,7 +108,7 @@ public class PDFBoxTable { } for (int i = 0; i < rows; i++) { - ArrayList row = (ArrayList) this.table.getRows().get(i); + ArrayList row = this.table.getRows().get(i); for (int j = 0; j < row.size(); j++) { Entry cell = (Entry) row.get(j); @@ -132,7 +145,7 @@ public class PDFBoxTable { } for (int i = 0; i < rows; i++) { - ArrayList row = (ArrayList) this.table.getRows().get(i); + ArrayList row = this.table.getRows().get(i); for (int j = 0; j < row.size(); j++) { Entry cell = (Entry) row.get(j); float cellWidth = getCellWidth(cell); @@ -180,13 +193,19 @@ public class PDFBoxTable { isValue = false; case Entry.TYPE_VALUE: PDFont c = null; + float fontSize; String string = (String) cell.getValue(); if (isValue) { - c = valueFont; + c = valueFont.getFont(null); + fontSize = valueFont.getFontSize(); } else { - c = font; + c = font.getFont(null); + fontSize = font.getFontSize(); + } + if (string == null) { + string = ""; + cell.setValue(string); } - if (string.contains("\n")) { float maxWidth = 0; String[] lines = string.split("\n"); @@ -205,7 +224,8 @@ public class PDFBoxTable { case Entry.TYPE_TABLE: PDFBoxTable pdfBoxTable = null; if (cell.getValue() instanceof Table) { - pdfBoxTable = new PDFBoxTable((Table) cell.getValue(), this); + pdfBoxTable = new PDFBoxTable((Table) cell.getValue(), this, + this.settings); cell.setValue(pdfBoxTable); } else if (cell.getValue() instanceof PDFBoxTable) { pdfBoxTable = (PDFBoxTable) cell.getValue(); @@ -243,17 +263,49 @@ public class PDFBoxTable { if (lineBreaks.length > 1) { for (int j = 0; j < lineBreaks.length; j++) { String subword = lineBreaks[j]; - //if (cLine + subword.length() > maxline) { - lines.add(cLineValue.trim()); - cLineValue = ""; - cLine = 0; - //} + // if (cLine + subword.length() > maxline) { + lines.add(cLineValue.trim()); + cLineValue = ""; + cLine = 0; + // } cLineValue += subword + " "; cLine += subword.length(); } } else { - if (cLine + word.length() > maxline && - cLineValue.length() != 0) { + if (cLine + word.length() > maxline && cLineValue.length() != 0) { + lines.add(cLineValue.trim()); + cLineValue = ""; + cLine = 0; + } + cLineValue += word + " "; + cLine += word.length(); + } + } + lines.add(cLineValue.trim()); + return lines.toArray(new String[0]); + } + + private String[] breakString(String value, PDFont f, float maxwidth) throws IOException { + String[] words = value.split(" "); + List lines = new ArrayList(); + int cLine = 0; + String cLineValue = ""; + for (int i = 0; i < words.length; i++) { + String word = words[i]; + String[] lineBreaks = word.split("\n"); + if (lineBreaks.length > 1) { + for (int j = 0; j < lineBreaks.length; j++) { + String subword = lineBreaks[j]; + // if (cLine + subword.length() > maxline) { + lines.add(cLineValue.trim()); + cLineValue = ""; + cLine = 0; + // } + cLineValue += subword + " "; + cLine += subword.length(); + } + } else { + if (f.getStringWidth(cLineValue + word) > maxwidth && cLineValue.length() != 0) { lines.add(cLineValue.trim()); cLineValue = ""; cLine = 0; @@ -273,23 +325,31 @@ public class PDFBoxTable { isValue = false; case Entry.TYPE_VALUE: PDFont c = null; + float fontSize; String string = (String) cell.getValue(); if (isValue) { - c = valueFont; + c = valueFont.getFont(null); + fontSize = valueFont.getFontSize(); } else { - c = font; + c = font.getFont(null); + fontSize = font.getFontSize(); } - float fwidth = c.getFontDescriptor().getFontBoundingBox() - .getWidth() - / 1000 * fontSize; + float fwidth; + if (c instanceof PDType1Font) { + fwidth = c.getFontDescriptor().getFontBoundingBox().getWidth() + / 1000 * fontSize; + } else { + fwidth = c.getFontDescriptor().getMaxWidth(); + } + logger.debug("Font Width: {}", fwidth); int maxcharcount = (int) ((width - padding * 2) / fwidth) - 1; - logger.info("Max {} chars per line!", maxcharcount); + logger.debug("Max {} chars per line!", maxcharcount); float fheight = c.getFontDescriptor().getFontBoundingBox() .getHeight() / 1000 * fontSize; - + String[] lines = breakString(string, maxcharcount); cell.setValue(concatLines(lines)); return fheight * lines.length; @@ -299,10 +359,14 @@ public class PDFBoxTable { PDFBoxTable pdfBoxTable = null; if (cell.getValue() instanceof Table) { pdfBoxTable = new PDFBoxTable((Table) cell.getValue(), this, - width - padding); + width - padding, this.settings); cell.setValue(pdfBoxTable); } else if (cell.getValue() instanceof PDFBoxTable) { + // recreate here beacuse of fixed width! pdfBoxTable = (PDFBoxTable) cell.getValue(); + pdfBoxTable = new PDFBoxTable(pdfBoxTable.table, this, width + - padding, this.settings); + cell.setValue(pdfBoxTable); } else { throw new IOException("Failed to build PDFBox Table"); } @@ -320,11 +384,14 @@ public class PDFBoxTable { isValue = false; case Entry.TYPE_VALUE: PDFont c = null; + float fontSize; String string = (String) cell.getValue(); if (isValue) { - c = valueFont; + c = valueFont.getFont(null); + fontSize = valueFont.getFontSize(); } else { - c = font; + c = font.getFont(null); + fontSize = font.getFontSize(); } float fheight = c.getFontDescriptor().getFontBoundingBox() .getHeight() @@ -341,7 +408,8 @@ public class PDFBoxTable { case Entry.TYPE_TABLE: PDFBoxTable pdfBoxTable = null; if (cell.getValue() instanceof Table) { - pdfBoxTable = new PDFBoxTable((Table) cell.getValue(), this); + pdfBoxTable = new PDFBoxTable((Table) cell.getValue(), this, + this.settings); cell.setValue(pdfBoxTable); } else if (cell.getValue() instanceof PDFBoxTable) { pdfBoxTable = (PDFBoxTable) cell.getValue(); @@ -394,7 +462,8 @@ public class PDFBoxTable { public void dumpTable() { logger.info("====================================================================="); logger.info("Information about: " + this.table.getName()); - logger.info("\tDimensions: {} x {} (W x H)", this.tableWidth, this.tableHeight); + logger.info("\tDimensions: {} x {} (W x H)", this.tableWidth, + this.tableHeight); logger.info("\tPadding: {}", padding); logger.info("\t================================"); logger.info("\tRow Heights:"); @@ -408,8 +477,24 @@ public class PDFBoxTable { } logger.info("====================================================================="); } - - public ArrayList getRow(int i) { - return (ArrayList) this.table.getRows().get(i); + + public Table getOrigTable() { + return this.table; + } + + public ArrayList getRow(int i) { + return this.table.getRows().get(i); + } + + public PDFBoxFont getFont() { + return font; + } + + public PDFBoxFont getValueFont() { + return valueFont; + } + + public Color getBGColor() { + return this.bgColor; } } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PdfBoxStamper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PdfBoxStamper.java index 559c8c9b..1bd4fed5 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PdfBoxStamper.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PdfBoxStamper.java @@ -1,13 +1,9 @@ package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; -import java.io.InputStream; +import java.io.IOException; -import org.apache.pdfbox.pdmodel.PDPage; -import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDFTemplateBuilder; -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.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,109 +25,13 @@ public class PdfBoxStamper implements IPDFStamper { this.pdfBuilder = new PDVisibleSigBuilder(); } - /* - private InputStream renderTable(Table abstractTable) throws PdfAsException - { - logger.info("pdf building has been started"); - PDFTemplateStructure pdfStructure = pdfBuilder.getStructure(); - //pdfStructure.setIm - // 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.getImage()); - - // 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); - PDFormXObject 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.getImage()); - - // now inject procSetArray - this.pdfBuilder.injectProcSetArray(innerForm, page, innerFormResource, imageFormResources, 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.createVisualSignature(template); - this.pdfBuilder.createWidgetDictionary(pdSignatureField, holderFormResources); - - ByteArrayInputStream in = pdfStructure.getTemplateAppearanceStream(); - logger.info("stream returning started, size= " + in.available()); - - // we must close the document - template.close(); - - // return result of the stream - return in; - } - */ - - public IPDFVisualObject createVisualPDFObject(PDFObject pdf, Table table) { - - return null; + public IPDFVisualObject createVisualPDFObject(PDFObject pdf, Table table) throws IOException { + return new PdfBoxVisualObject(table, pdf.getStatus().getSettings()); } public byte[] writeVisualObject(IPDFVisualObject visualObject, PositioningInstruction positioningInstruction, byte[] pdfData, String placeholderName) throws PdfAsException { - // TODO Auto-generated method stub return null; } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PdfBoxVisualObject.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PdfBoxVisualObject.java index 25028073..c10a5f68 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PdfBoxVisualObject.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PdfBoxVisualObject.java @@ -1,46 +1,74 @@ package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox; +import java.io.IOException; + +import at.gv.egiz.pdfas.common.settings.ISettings; import at.gv.egiz.pdfas.lib.impl.stamping.IPDFVisualObject; +import at.knowcenter.wag.egov.egiz.table.Table; public class PdfBoxVisualObject implements IPDFVisualObject { - public void setWidth(float width) { + private Table abstractTable; + private PDFBoxTable table; + private float width; + private float x; + private float y; + private int page; + private ISettings settings; + public PdfBoxVisualObject(Table table, ISettings settings) + throws IOException { + this.abstractTable = table; + this.table = new PDFBoxTable(table, null, settings); + this.settings = settings; + } + + public void setWidth(float width) { + this.width = width; } public void fixWidth() { - // TODO Auto-generated method stub - + try { + table = new PDFBoxTable(abstractTable, null, this.width, settings); + } catch (IOException e) { + // should not occur + e.printStackTrace(); + } } public float getHeight() { - // TODO Auto-generated method stub - return 0; + return table.getHeight(); } public float getWidth() { - // TODO Auto-generated method stub - return 0; + return table.getWidth(); } public void setXPos(float x) { - // TODO Auto-generated method stub - + this.x = x; } - public void setYPos(float x) { - // TODO Auto-generated method stub - + public void setYPos(float y) { + this.y = y; } + + public float getX() { + return x; + } + + public float getY() { + return y; + } public int getPage() { - // TODO Auto-generated method stub - return 0; + return page; } public void setPage(int page) { - // TODO Auto-generated method stub - + this.page = page; } + public PDFBoxTable getTable() { + return this.table; + } } diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/status/PDFObject.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/status/PDFObject.java index 514d0fa3..b402d0d2 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/status/PDFObject.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/status/PDFObject.java @@ -28,7 +28,6 @@ public class PDFObject { private OperationStatus status; private byte[] originalDocument; - private byte[] stampedDocument; private byte[] signedDocument; public PDFObject(OperationStatus operationStatus) { @@ -43,14 +42,6 @@ public class PDFObject { this.originalDocument = originalDocument; } - public byte[] getStampedDocument() { - return stampedDocument; - } - - public void setStampedDocument(byte[] stampedDocument) { - this.stampedDocument = stampedDocument; - } - public byte[] getSignedDocument() { return signedDocument; } diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java index de471e11..72bdfc4d 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/table/Table.java @@ -78,7 +78,7 @@ public class Table implements Serializable /** * The row definitions. */ - private Map rows_ = new HashMap(); + private Map> rows_ = new HashMap>(); /** * The table width. @@ -192,12 +192,12 @@ public class Table implements Serializable * * @return Returns the sorted (by row number) table rows. */ - public ArrayList getRows() + public ArrayList> getRows() { - ArrayList rows = new ArrayList(); + ArrayList> rows = new ArrayList>(); for (int row_idx = 1; row_idx <= rows_.size(); row_idx++) { - ArrayList row = (ArrayList) rows_.get("" + row_idx); + ArrayList row = (ArrayList) rows_.get("" + row_idx); rows.add(row); } return rows; @@ -213,7 +213,7 @@ public class Table implements Serializable * @param row * the entry list to store */ - public void addRow(String rowNumber, ArrayList row) + public void addRow(String rowNumber, ArrayList row) { rows_.put(rowNumber, row); if (row.size() > maxCols_) @@ -230,10 +230,10 @@ public class Table implements Serializable String the_string = "\n#### TABLE " + name_ + " BEGIN #####"; the_string += " Width:" + width_ + " max cols:" + maxCols_ + " cols:" + colsRelativeWith_; the_string += "\nStyle:" + style_; - ArrayList rows = getRows(); + ArrayList> rows = getRows(); for (int row_idx = 0; row_idx < rows.size(); row_idx++) { - ArrayList row = (ArrayList) rows.get(row_idx); + ArrayList row = rows.get(row_idx); String row_prefix = "\n ++ ROW " + row_idx + " ++ "; for (int entry_idx = 0; entry_idx < row.size(); entry_idx++) { diff --git a/pdf-as-lib/src/main/resources/icm/sRGB Color Space Profile.icm b/pdf-as-lib/src/main/resources/icm/sRGB Color Space Profile.icm new file mode 100644 index 00000000..7f9d18d0 Binary files /dev/null and b/pdf-as-lib/src/main/resources/icm/sRGB Color Space Profile.icm differ diff --git a/pdf-as-lib/src/main/resources/icm/sRGB Color Space Profile.icm.LICENSE.txt b/pdf-as-lib/src/main/resources/icm/sRGB Color Space Profile.icm.LICENSE.txt new file mode 100644 index 00000000..9b817e33 --- /dev/null +++ b/pdf-as-lib/src/main/resources/icm/sRGB Color Space Profile.icm.LICENSE.txt @@ -0,0 +1,14 @@ +Obtained from: http://www.srgb.com/usingsrgb.html + +The file "sRGB Color Space Profile.icm" is: +Copyright (c) 1998 Hewlett-Packard Company + +To anyone who acknowledges that the file "sRGB Color Space Profile.icm" +is provided "AS IS" WITH NO EXPRESS OR IMPLIED WARRANTY: +permission to use, copy and distribute this file for any purpose is hereby +granted without fee, provided that the file is not changed including the HP +copyright notice tag, and that the name of Hewlett-Packard Company not be +used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. Hewlett-Packard Company makes +no representations about the suitability of this software for any purpose. + diff --git a/pdf-as-web/.gitignore b/pdf-as-web/.gitignore index 5e56e040..81631c69 100644 --- a/pdf-as-web/.gitignore +++ b/pdf-as-web/.gitignore @@ -1 +1,2 @@ /bin +/build -- cgit v1.2.3