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-ffa450edef68tags/fop-0_92-beta
@@ -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"; | |||
} |
@@ -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)); |
@@ -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" |
@@ -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 /" |
@@ -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 | |||
/** |
@@ -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) | |||
*/ |
@@ -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; | |||
} | |||
@@ -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("<</Type /XObject\n"); |