From 6b07665badb08b36d61bede31f5d6b4ffc264bbf Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Wed, 22 Feb 2006 15:40:44 +0000 Subject: [PATCH] More work on PDF/A-1: ID entry is now generated in the trailer. More conformance checks especially for fonts. PDF/A Identification Schema for XMP added. Almost finished. Only color space checking is left to do, I think. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@379798 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/fo/extensions/xmp/XMPConstants.java | 3 +++ src/java/org/apache/fop/pdf/PDFCIDFont.java | 7 +++-- src/java/org/apache/fop/pdf/PDFDocument.java | 27 +++++++++++++++++++ src/java/org/apache/fop/pdf/PDFFont.java | 15 ++++++++++- .../org/apache/fop/pdf/PDFFontDescriptor.java | 7 ++++- .../org/apache/fop/pdf/PDFFontNonBase14.java | 16 ++++++++++- src/java/org/apache/fop/pdf/PDFMetadata.java | 19 +++++++++++++ src/java/org/apache/fop/pdf/PDFXObject.java | 6 ++++- 8 files changed, 94 insertions(+), 6 deletions(-) diff --git a/src/java/org/apache/fop/fo/extensions/xmp/XMPConstants.java b/src/java/org/apache/fop/fo/extensions/xmp/XMPConstants.java index ed189aa38..6edb1fa41 100644 --- a/src/java/org/apache/fop/fo/extensions/xmp/XMPConstants.java +++ b/src/java/org/apache/fop/fo/extensions/xmp/XMPConstants.java @@ -37,5 +37,8 @@ public interface XMPConstants { /** Namespace URI for the Adobe PDF Schema */ String ADOBE_PDF_NAMESPACE = "http://ns.adobe.com/pdf/1.3/"; + + /** Namespace URI for the PDF/A Identification Schema */ + String PDF_A_IDENTIFICATION = "http://www.aiim.org/pdfa/ns/id"; } diff --git a/src/java/org/apache/fop/pdf/PDFCIDFont.java b/src/java/org/apache/fop/pdf/PDFCIDFont.java index ef6188bc5..7aa3a0ae2 100644 --- a/src/java/org/apache/fop/pdf/PDFCIDFont.java +++ b/src/java/org/apache/fop/pdf/PDFCIDFont.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -202,9 +202,12 @@ public class PDFCIDFont extends PDFObject { p.append("<< /Type /Font"); p.append("\n/BaseFont /"); p.append(this.basefont); + p.append(" \n/CIDToGIDMap "); if (cidMap != null) { - p.append(" \n/CIDToGIDMap "); p.append(cidMap.referencePDF()); + } else { + p.append("/Identity"); + //This is the default. We still write it because PDF/A requires it. } p.append(" \n/Subtype /"); p.append(getPDFNameForCIDFontType(this.cidtype)); diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java index 779e7ff26..79b7e52e1 100644 --- a/src/java/org/apache/fop/pdf/PDFDocument.java +++ b/src/java/org/apache/fop/pdf/PDFDocument.java @@ -23,6 +23,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; @@ -882,6 +886,27 @@ public class PDFDocument { this.position += bin.length; } + /** @return the "ID" entry for the file trailer */ + protected String getIDEntry() { + try { + MessageDigest digest = MessageDigest.getInstance("MD5"); + DateFormat df = new SimpleDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS"); + digest.update(df.format(new Date()).getBytes()); + //Ignoring the filename here for simplicity even though it's recommended by the PDF spec + digest.update(String.valueOf(this.position).getBytes()); + digest.update(getInfo().toPDF()); + byte[] res = digest.digest(); + String s = PDFText.toHex(res); + return "/ID [" + s + " " + s + "]"; + } catch (NoSuchAlgorithmException e) { + if (getPDFAMode().isPDFA1LevelB()) { + throw new UnsupportedOperationException("MD5 not available: " + e.getMessage()); + } else { + return ""; //Entry is optional if PDF/A is not active + } + } + } + /** * write the trailer * @@ -920,6 +945,8 @@ public class PDFDocument { + "/Info " + this.info.referencePDF() + "\n" + + getIDEntry() + + "\n" + encryptEntry + ">>\n" + "startxref\n" diff --git a/src/java/org/apache/fop/pdf/PDFFont.java b/src/java/org/apache/fop/pdf/PDFFont.java index fd0f51a73..9b827ebf1 100644 --- a/src/java/org/apache/fop/pdf/PDFFont.java +++ b/src/java/org/apache/fop/pdf/PDFFont.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -189,10 +189,23 @@ public class PDFFont extends PDFObject { } } + /** + * Validates the PDF object prior to serialization. + */ + protected void validate() { + if (getDocumentSafely().getPDFAMode().isPDFA1LevelB()) { + if (this.getClass() == PDFFont.class) { + throw new PDFConformanceException("For PDF/A-1, all fonts, even the base 14" + + " fonts, have to be embedded!"); + } + } + } + /** * @see org.apache.fop.pdf.PDFObject#toPDFString() */ public String toPDFString() { + validate(); StringBuffer p = new StringBuffer(128); p.append(getObjectID()); p.append("<< /Type /Font\n/Subtype /" diff --git a/src/java/org/apache/fop/pdf/PDFFontDescriptor.java b/src/java/org/apache/fop/pdf/PDFFontDescriptor.java index 83492ffcf..24e0243f5 100644 --- a/src/java/org/apache/fop/pdf/PDFFontDescriptor.java +++ b/src/java/org/apache/fop/pdf/PDFFontDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -114,6 +114,11 @@ public class PDFFontDescriptor extends PDFObject { this.fontfile = fontfile; } + /** @return the FontFile or null if the font is not embedded */ + public AbstractPDFStream getFontFile() { + return this.fontfile; + } + // public void setCharSet(){}//for subset fonts /** diff --git a/src/java/org/apache/fop/pdf/PDFFontNonBase14.java b/src/java/org/apache/fop/pdf/PDFFontNonBase14.java index b18aa66f8..e32b11ce4 100644 --- a/src/java/org/apache/fop/pdf/PDFFontNonBase14.java +++ b/src/java/org/apache/fop/pdf/PDFFontNonBase14.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -88,6 +88,20 @@ public abstract class PDFFontNonBase14 extends PDFFont { this.descriptor = descriptor; } + /** @return the FontDescriptor or null if there is none */ + public PDFFontDescriptor getDescriptor() { + return this.descriptor; + } + + /** @see org.apache.fop.pdf.PDFFont#validate() */ + protected void validate() { + if (getDocumentSafely().getPDFAMode().isPDFA1LevelB()) { + if (this.getDescriptor().getFontFile() == null) { + throw new PDFConformanceException("For PDF/A-1, all fonts have to be embedded!"); + } + } + } + /** * @see org.apache.fop.pdf.PDFFont#fillInPDF(StringBuffer) */ diff --git a/src/java/org/apache/fop/pdf/PDFMetadata.java b/src/java/org/apache/fop/pdf/PDFMetadata.java index 9b21420eb..6aec41ca5 100644 --- a/src/java/org/apache/fop/pdf/PDFMetadata.java +++ b/src/java/org/apache/fop/pdf/PDFMetadata.java @@ -230,6 +230,25 @@ public class PDFMetadata extends PDFStream { desc.appendChild(el); el.appendChild(doc.createTextNode(pdfDoc.getPDFVersionString())); + //PDF/A identification + PDFAMode pdfaMode = pdfDoc.getPDFAMode(); + if (pdfaMode.isPDFA1LevelB()) { + desc = doc.createElementNS(XMPConstants.RDF_NAMESPACE, "rdf:Description"); + desc.setAttribute("about", ""); + desc.setAttributeNS(xmlns, "xmlns:pdfaid", XMPConstants.PDF_A_IDENTIFICATION); + rdf.appendChild(desc); + el = doc.createElementNS(XMPConstants.PDF_A_IDENTIFICATION, "pdfaid:part"); + desc.appendChild(el); + el.appendChild(doc.createTextNode("1")); //PDF/A-1 + el = doc.createElementNS(XMPConstants.PDF_A_IDENTIFICATION, "pdfaid:conformance"); + desc.appendChild(el); + if (pdfaMode == PDFAMode.PDFA_1A) { + el.appendChild(doc.createTextNode("A")); //PDF/A-1a + } else { + el.appendChild(doc.createTextNode("B")); //PDF/A-1b + } + } + return doc; } diff --git a/src/java/org/apache/fop/pdf/PDFXObject.java b/src/java/org/apache/fop/pdf/PDFXObject.java index 4d6e7f380..0607add55 100644 --- a/src/java/org/apache/fop/pdf/PDFXObject.java +++ b/src/java/org/apache/fop/pdf/PDFXObject.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -94,6 +94,10 @@ public class PDFXObject extends AbstractPDFStream { private String buildDictionaryFromPS(String lengthEntry, String dictEntries) { + if (getDocumentSafely().getPDFAMode().isPDFA1LevelB()) { + throw new PDFConformanceException("PostScript XObjects are prohibited when PDF/A" + + " is active. Convert EPS graphics to another format."); + } StringBuffer sb = new StringBuffer(128); sb.append(getObjectID()); sb.append("<