diff options
9 files changed, 160 insertions, 26 deletions
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 2c2b941b..a2cee944 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 @@ -92,6 +92,7 @@ public interface IProfileConstants { public final static String SIGNFIELD_VALUE = "adobeSignFieldValue"; public final static String TIMEZONE_BASE = "timezone"; public final static String SIG_PDFA1B_VALID = "SIG_PDFA1B_VALID"; + public final static String SIG_PDFA3B_VALID = "SIG_PDFA3B_VALID"; public final static String SIG_PDFUA_FORCE = "SIG_PDFUA_FORCE"; } 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 cbc1d601..b6a1b6ca 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 @@ -39,6 +39,8 @@ public class SignatureProfileSettings implements IProfileConstants { private String profileID; + private String pdfAVersion = null; + private ISettings configuration; public SignatureProfileSettings(String profileID, ISettings configuration) { @@ -203,8 +205,17 @@ public class SignatureProfileSettings implements IProfileConstants { public String getProfileTimeZone() { return this.getValue(TIMEZONE_BASE); } - + + public void setPDFAVersion(String version) { + this.pdfAVersion = version; + } + public boolean isPDFA() { + + if(this.pdfAVersion != null) { + return "1".equals(this.pdfAVersion); + } + SignatureProfileEntry entry = profileInformations.get(SIG_PDFA1B_VALID); if (entry != null) { String value = entry.getCaption(); @@ -221,4 +232,17 @@ public class SignatureProfileSettings implements IProfileConstants { } return false; } + + public boolean isPDFA3() { + if(this.pdfAVersion != null) { + return "3".equals(this.pdfAVersion); + } + + SignatureProfileEntry entry = profileInformations.get(SIG_PDFA3B_VALID); + if (entry != null) { + String value = entry.getCaption(); + return "true".equals(value); + } + return false; + } } diff --git a/pdf-as-pdfbox-2/build.gradle b/pdf-as-pdfbox-2/build.gradle index 970ca038..c5d7d41e 100644 --- a/pdf-as-pdfbox-2/build.gradle +++ b/pdf-as-pdfbox-2/build.gradle @@ -16,6 +16,7 @@ jar { repositories { + mavenLocal() mavenCentral() } diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java index 8965ce0e..901e47db 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java @@ -48,6 +48,7 @@ import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.common.PDMetadata; import org.apache.pdfbox.pdmodel.common.PDNumberTreeNode; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureElement; @@ -68,6 +69,9 @@ import org.apache.pdfbox.preflight.exception.ValidationException; import org.apache.pdfbox.preflight.parser.PreflightParser; import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.schema.PDFAIdentificationSchema; +import org.apache.xmpbox.xml.DomXmpParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -132,6 +136,8 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants { PDFASPDFBOXSignatureInterface signer = (PDFASPDFBOXSignatureInterface) genericSigner; + String pdfaVersion = null; + PDDocument doc = null; SignatureOptions options = new SignatureOptions(); COSDocument visualSignatureDocumentGuard = null; @@ -221,6 +227,11 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants { } options.setPreferredSignatureSize(signatureSize); + if(signatureProfileSettings.isPDFA() || signatureProfileSettings.isPDFA3()) { + pdfaVersion = getPDFAVersion(doc); + signatureProfileSettings.setPDFAVersion(pdfaVersion); + } + // Is visible Signature if (requestedSignature.isVisual()) { logger.info("Creating visual siganture block"); @@ -352,7 +363,7 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants { } - if (signatureProfileSettings.isPDFA()) { + if (signatureProfileSettings.isPDFA() || signatureProfileSettings.isPDFA3()) { PDDocumentCatalog root = doc.getDocumentCatalog(); COSBase base = root.getCOSObject().getItem(COSName.OUTPUT_INTENTS); if (base == null) { @@ -807,4 +818,31 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants { throw ErrorExtractor.searchPdfAsError(e, status); } } + + private String getPDFAVersion(PDDocument doc) { + try { + PDDocumentCatalog cat = doc.getDocumentCatalog(); + PDMetadata metadata = cat.getMetadata(); + + if(metadata != null) { + DomXmpParser xmpParser = new DomXmpParser(); + XMPMetadata xmpMetadata = xmpParser.parse(metadata.exportXMPMetadata()); + if(xmpMetadata != null) { + PDFAIdentificationSchema pdfaIdentificationSchema = xmpMetadata.getPDFIdentificationSchema(); + if (pdfaIdentificationSchema != null) { + Integer pdfaversion = pdfaIdentificationSchema.getPart(); + String conformance = pdfaIdentificationSchema.getConformance(); + logger.info("Detected PDF/A Version: {} - {}", pdfaversion, conformance); + + if(pdfaversion != null) { + return String.valueOf(pdfaversion); + } + } + } + } + } catch (Throwable e) { + logger.warn("Failed to determine PDF/A Version!", e); + } + return null; + } } diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsTemplateCreator.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsTemplateCreator.java index b8c15119..b07e6ed5 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsTemplateCreator.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsTemplateCreator.java @@ -23,11 +23,10 @@ ******************************************************************************/ package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox2; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; +import at.gv.egiz.pdfas.common.settings.SignatureProfileSettings; +import at.gv.egiz.pdfas.lib.impl.stamping.TableFactory; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -143,7 +142,9 @@ public class PDFAsTemplateCreator extends PDFTemplateCreator { null, innerFormName, properties); this.pdfBuilder.createVisualSignature(template); this.pdfBuilder.createWidgetDictionary(pdSignatureField, holderFormResources); - + + + ByteArrayInputStream in = null; //COSDocument doc = pdfStructure.getVisualSignature(); @@ -152,7 +153,31 @@ public class PDFAsTemplateCreator extends PDFTemplateCreator { ByteArrayOutputStream baos = new ByteArrayOutputStream(); template.save(baos); baos.close(); - in = new ByteArrayInputStream(baos.toByteArray()); + + SignatureProfileSettings signatureProfileSettings = + this.pdfBuilder.signatureProfileSettings; + + boolean requirePDFA3 = signatureProfileSettings.isPDFA3(); + + if(requirePDFA3) { + + //FileOutputStream fos = new FileOutputStream("/tmp/signature.pdf"); + //fos.write(baos.toByteArray()); + //fos.close(); + + PDDocument cidSetRemoved = PDDocument.load(baos.toByteArray()); + try { + this.pdfBuilder.removeCidSet(cidSetRemoved); + baos.reset(); + baos = new ByteArrayOutputStream(); + cidSetRemoved.save(baos); + baos.close(); + } finally { + cidSetRemoved.close(); + } + } + + in = new ByteArrayInputStream(baos.toByteArray()); logger.debug("stream returning started, size= " + in.available()); diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsVisualSignatureBuilder.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsVisualSignatureBuilder.java index a33a46e7..d283c3e3 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsVisualSignatureBuilder.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsVisualSignatureBuilder.java @@ -30,22 +30,15 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import at.gv.egiz.pdfas.common.settings.SignatureProfileSettings; import org.apache.commons.codec.binary.Hex; import org.apache.commons.io.IOUtils; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; -import org.apache.pdfbox.pdfparser.PDFParser; -import org.apache.pdfbox.pdfparser.PDFStreamParser; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.pdmodel.PDPage; -import org.apache.pdfbox.pdmodel.PDPageContentStream; -import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.*; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; @@ -59,6 +52,7 @@ import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleS 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.apache.pdfbox.pdmodel.font.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,15 +70,18 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder implements private PDFAsVisualSignatureProperties properties; private PDFAsVisualSignatureDesigner designer; private ISettings settings; + public SignatureProfileSettings signatureProfileSettings; private PDResources innerFormResources; private Map<String, ImageObject> images = new HashMap<String, ImageObject>(); public PDFAsVisualSignatureBuilder( PDFAsVisualSignatureProperties properties, ISettings settings, - PDFAsVisualSignatureDesigner designer) { + PDFAsVisualSignatureDesigner designer, + SignatureProfileSettings signatureProfileSettings) { this.properties = properties; this.settings = settings; this.designer = designer; + this.signatureProfileSettings = signatureProfileSettings; } @Override @@ -657,4 +654,33 @@ public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder implements this.getStructure().getTemplate().close(); } + public void removeCidSet(PDDocument document) throws IOException { + + PDDocumentCatalog catalog = document.getDocumentCatalog(); + + COSName cidSet = COSName.getPDFName("CIDSet"); + + Iterator<PDPage> pdPageIterator = catalog.getPages().iterator(); + while(pdPageIterator.hasNext()) { + + PDPage page = pdPageIterator.next(); + + Iterator<COSName> cosNameIterator = page.getResources().getFontNames().iterator(); + while (cosNameIterator.hasNext()) { + COSName fontName = cosNameIterator.next(); + PDFont pdFont = page.getResources().getFont(fontName); + + if (pdFont instanceof PDType0Font) { + PDType0Font typedFont = (PDType0Font) pdFont; + + if (typedFont.getDescendantFont() != null) { + if (typedFont.getDescendantFont().getFontDescriptor() != null) { + typedFont.getDescendantFont().getFontDescriptor().getCOSObject().removeItem(cidSet); + } + } + } + } + } + } + } diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsVisualSignatureProperties.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsVisualSignatureProperties.java index db96767a..adfd6694 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsVisualSignatureProperties.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFAsVisualSignatureProperties.java @@ -112,7 +112,7 @@ public class PDFAsVisualSignatureProperties extends PDVisibleSigProperties { @Override public void buildSignature() throws IOException { - PDFAsVisualSignatureBuilder builder = new PDFAsVisualSignatureBuilder(this, this.settings, designer); + PDFAsVisualSignatureBuilder builder = new PDFAsVisualSignatureBuilder(this, this.settings, designer, this.signatureProfileSettings); PDFAsTemplateCreator creator = new PDFAsTemplateCreator(builder); try { setVisibleSignature(creator.buildPDF(designer, this.origDoc)); diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFBoxFont.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFBoxFont.java index 8795907d..9c848ff9 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFBoxFont.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/PDFBoxFont.java @@ -24,8 +24,11 @@ package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox2; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import at.gv.egiz.pdfas.common.settings.SignatureProfileSettings; +import at.gv.egiz.pdfas.lib.impl.stamping.TableFactory; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.pdmodel.font.PDType1Font; @@ -158,6 +161,7 @@ public class PDFBoxFont { private PDFont generateTTF(String fonttype, PDFBOXObject pdfObject) throws IOException { + ttfFontDesc = fonttype; String fontName = fonttype.replaceFirst("TTF:", ""); String fontPath = this.settings.getWorkingDirectory() + File.separator @@ -165,6 +169,7 @@ public class PDFBoxFont { logger.debug("Font from: \"" + fontPath + "\"."); + PDFAsFontCache fontCache = pdfObject.getSigBlockFontCache(); if(fontCache.contains(fontPath)){ @@ -185,8 +190,14 @@ public class PDFBoxFont { // } logger.debug("Instantiating new font."); - - PDType0Font font = PDType0Font.load(pdfObject.getDocument(), new File(fontPath)); + +/* + SignatureProfileSettings signatureProfileSettings = TableFactory + .createProfile(pdfObject.getStatus().getRequestedSignature().getSignatureProfileID(), pdfObject.getStatus().getSettings()); + + boolean requirePDFA3 = signatureProfileSettings.isPDFA3(); +*/ + PDType0Font font = PDType0Font.load(pdfObject.getDocument(), new FileInputStream(fontPath)); fontCache.addFont(fontPath,font); return font; diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/TableDrawUtils.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/TableDrawUtils.java index 5162b287..df8d3e3b 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/TableDrawUtils.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox2/TableDrawUtils.java @@ -230,8 +230,10 @@ public class TableDrawUtils { drawDebugLineString(contentStream, tx, ty, maxWidth, textHeight, descent, settings); contentStream.beginText(); - - + + contentStream.setFont(textFont, fontSize); + contentStream.newLineAtOffset(tx, (ty - fontSize + (descent * (-1)))); + /* if (formResources.getFont(COSName.getPDFName(textFont.getName())) != null) { String fontID = getFontID(textFont, formResources); logger.debug("Using Font: " + fontID); @@ -246,11 +248,17 @@ public class TableDrawUtils { contentStream.moveTextPositionByAmount(tx, (ty - fontSize + (descent * (-1)))); contentStream.appendRawCommands(fontSize + " TL\n"); - + */ + + if(textFont.willBeSubset()) { + logger.debug("Font will be subset!"); + } + for (int k = 0; k < tlines.length; k++) { contentStream.showText(tlines[k]); if (k < tlines.length - 1) { - contentStream.appendRawCommands("T*\n"); + contentStream.newLineAtOffset(0, -1 * fontSize ); + //contentStream.appendRawCommands("T*\n"); } } |