prepare document as late as possible
This commit is contained in:
30
History.md
30
History.md
@@ -1,22 +1,26 @@
|
|||||||
1.5.0
|
1.5.0
|
||||||
=====
|
=====
|
||||||
<date>
|
2017-11-30
|
||||||
Now using factory. Export is now also possible on OutputStream.
|
|
||||||
Further dev improvements: no more need to call PDFattachZugferdFile(null) or exporter close();
|
|
||||||
toecount now has options to combine documents and upgrade xml file from ZF1 to ZF2
|
|
||||||
More unit tests, e.g. for custom xml export, PDF/A Schema extensions.
|
|
||||||
Toecount is now integrated and the main class so "java -jar mustang-1.5.0.jar" should suffice
|
|
||||||
|
|
||||||
|
Support for ZUGFeRD 2.0 "public review" part 1.
|
||||||
|
Now using factories to create/configure ZUGFeRDExporter.
|
||||||
|
Export is now also possible on OutputStream.
|
||||||
|
Removed need to call PDFattachZugferdFile(null) or exporter close();
|
||||||
|
More unit tests, e.g. for custom xml export, PDF/A Schema extensions.
|
||||||
|
The command line utility "toecount" is now integrated and the main class so "java -jar mustang-1.5.0.jar" should suffice.
|
||||||
|
It now also features options to combine PDF with XML and upgrade XML files from ZF1 to ZF2.
|
||||||
|
|
||||||
|
First attempts be able to start with a PDF/A-3 in the first place and better error messages for non-PDF/A-conformance.
|
||||||
|
|
||||||
Further changes:
|
Further changes:
|
||||||
|
|
||||||
be able to specify profile #50
|
* be able to specify profile #50
|
||||||
close pdf files automatically after export #49
|
* close pdf files automatically after export #49
|
||||||
ZUGFeRDimporter does not close #48
|
* ZUGFeRDimporter does not close #48
|
||||||
command line option -e does not work on all-in-one jar #47
|
* command line option -e does not work on all-in-one jar #47
|
||||||
invoices have wrong namespaces #45
|
* invoices have wrong namespaces #45
|
||||||
invalid a3 #44
|
* invalid a3 #44
|
||||||
warn on export #39
|
* warn on export #39
|
||||||
|
|
||||||
|
|
||||||
1.4.0
|
1.4.0
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,6 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.xmpbox.XMPMetadata;
|
import org.apache.xmpbox.XMPMetadata;
|
||||||
|
|
||||||
public interface IExporterFactory {
|
public interface IExporterFactory {
|
||||||
@@ -25,8 +24,6 @@ public interface IExporterFactory {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public ZUGFeRDExporter load(InputStream pdfSource) throws IOException;
|
public ZUGFeRDExporter load(InputStream pdfSource) throws IOException;
|
||||||
public void prepareDocument(PDDocument doc) throws IOException;
|
|
||||||
public void addXMP(XMPMetadata metadata);
|
|
||||||
|
|
||||||
public IExporterFactory setCreator(String creator);
|
public IExporterFactory setCreator(String creator);
|
||||||
public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel);
|
public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel);
|
||||||
@@ -34,6 +31,5 @@ public interface IExporterFactory {
|
|||||||
public IExporterFactory setZUGFeRDVersion(int version);
|
public IExporterFactory setZUGFeRDVersion(int version);
|
||||||
public IExporterFactory ignorePDFAErrors();
|
public IExporterFactory ignorePDFAErrors();
|
||||||
public IExporterFactory setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zugferdConformanceLevel);
|
public IExporterFactory setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zugferdConformanceLevel);
|
||||||
public IExporterFactory setAttachZUGFeRDHeaders(final boolean attachZugferdHeaders);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,18 +16,29 @@ import org.apache.pdfbox.cos.COSDictionary;
|
|||||||
import org.apache.pdfbox.cos.COSName;
|
import org.apache.pdfbox.cos.COSName;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
||||||
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||||
|
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||||
|
import org.apache.xmpbox.XMPMetadata;
|
||||||
|
import org.apache.xmpbox.schema.AdobePDFSchema;
|
||||||
|
import org.apache.xmpbox.schema.DublinCoreSchema;
|
||||||
|
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
|
||||||
|
import org.apache.xmpbox.schema.XMPBasicSchema;
|
||||||
|
import org.apache.xmpbox.type.BadFieldValueException;
|
||||||
|
import org.apache.xmpbox.xml.XmpSerializer;
|
||||||
|
|
||||||
import javax.xml.transform.TransformerException;
|
import javax.xml.transform.TransformerException;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -59,7 +70,7 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
|
|
||||||
// BASIC, COMFORT etc - may be set from outside.
|
// BASIC, COMFORT etc - may be set from outside.
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private ZUGFeRDConformanceLevel zUGFeRDConformanceLevel = ZUGFeRDConformanceLevel.EXTENDED;
|
private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EXTENDED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally set,
|
* Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally set,
|
||||||
@@ -68,14 +79,22 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
* IZUGFeRDExportableTransaction for the XML to be populated.
|
* IZUGFeRDExportableTransaction for the XML to be populated.
|
||||||
*/
|
*/
|
||||||
IXMLProvider xmlProvider;
|
IXMLProvider xmlProvider;
|
||||||
|
protected PDMetadata metadata = null;
|
||||||
|
protected PDFAIdentificationSchema pdfaid = null;
|
||||||
|
protected XMPMetadata xmp = null;
|
||||||
|
protected String producer = "mustangproject";
|
||||||
|
protected String creator = "mustangproject";
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private boolean ignoreA1Errors;
|
private boolean ignoreA1Errors;
|
||||||
|
protected boolean ensurePDFisUpgraded = true;
|
||||||
private PDDocument doc;
|
private PDDocument doc;
|
||||||
int ZFVersion;
|
int ZFVersion;
|
||||||
|
|
||||||
private boolean disableAutoClose;
|
private boolean disableAutoClose;
|
||||||
|
|
||||||
private boolean fileAttached=false;
|
private boolean fileAttached = false;
|
||||||
|
protected boolean attachZUGFeRDHeaders = true;
|
||||||
|
|
||||||
public ZUGFeRDExporter() {
|
public ZUGFeRDExporter() {
|
||||||
init();
|
init();
|
||||||
@@ -116,7 +135,7 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setZUGFeRDVersion(int ver) {
|
public void setZUGFeRDVersion(int ver) {
|
||||||
if (ver == 1) {
|
if (ver == 1) {
|
||||||
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
|
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
|
||||||
@@ -129,7 +148,7 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
}
|
}
|
||||||
ZFVersion = ver;
|
ZFVersion = ver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IXMLProvider getProvider() {
|
public IXMLProvider getProvider() {
|
||||||
return xmlProvider;
|
return xmlProvider;
|
||||||
}
|
}
|
||||||
@@ -233,8 +252,7 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
public PDDocumentCatalog PDFmakeA3compliant(String filename, String producer, String creator,
|
public PDDocumentCatalog PDFmakeA3compliant(String filename, String producer, String creator,
|
||||||
boolean attachZugferdHeaders) throws IOException, TransformerException {
|
boolean attachZugferdHeaders) throws IOException, TransformerException {
|
||||||
|
|
||||||
doc = createPDFA1Factory().setProducer(producer).setCreator(creator)
|
doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(filename).doc;
|
||||||
.setAttachZUGFeRDHeaders(attachZugferdHeaders).load(filename).doc;
|
|
||||||
|
|
||||||
return doc.getDocumentCatalog();
|
return doc.getDocumentCatalog();
|
||||||
}
|
}
|
||||||
@@ -246,8 +264,7 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
public PDDocumentCatalog PDFmakeA3compliant(InputStream file, String producer, String creator,
|
public PDDocumentCatalog PDFmakeA3compliant(InputStream file, String producer, String creator,
|
||||||
boolean attachZugferdHeaders) throws IOException, TransformerException {
|
boolean attachZugferdHeaders) throws IOException, TransformerException {
|
||||||
|
|
||||||
doc = createPDFA1Factory().setProducer(producer).setCreator(creator)
|
doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(file).doc;
|
||||||
.setAttachZUGFeRDHeaders(attachZugferdHeaders).load(file).doc;
|
|
||||||
|
|
||||||
return doc.getDocumentCatalog();
|
return doc.getDocumentCatalog();
|
||||||
}
|
}
|
||||||
@@ -257,7 +274,7 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
if (ignoreA1Errors) {
|
if (ignoreA1Errors) {
|
||||||
factory.ignorePDFAErrors();
|
factory.ignorePDFAErrors();
|
||||||
}
|
}
|
||||||
return factory.setZUGFeRDConformanceLevel(zUGFeRDConformanceLevel).setConformanceLevel(conformanceLevel);
|
return factory.setZUGFeRDConformanceLevel(profile).setConformanceLevel(conformanceLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -277,6 +294,8 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
|
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
|
||||||
*/
|
*/
|
||||||
public void PDFattachZugferdFile(IZUGFeRDExportableTransaction trans) throws IOException {
|
public void PDFattachZugferdFile(IZUGFeRDExportableTransaction trans) throws IOException {
|
||||||
|
prepareDocument(doc);
|
||||||
|
|
||||||
xmlProvider.generateXML(trans);
|
xmlProvider.generateXML(trans);
|
||||||
String filename = getFilenameForVersion(ZFVersion);
|
String filename = getFilenameForVersion(ZFVersion);
|
||||||
PDFAttachGenericFile(doc, filename, "Alternative",
|
PDFAttachGenericFile(doc, filename, "Alternative",
|
||||||
@@ -286,7 +305,8 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
|
|
||||||
public void export(String ZUGFeRDfilename) throws IOException {
|
public void export(String ZUGFeRDfilename) throws IOException {
|
||||||
if (!fileAttached) {
|
if (!fileAttached) {
|
||||||
throw new IOException("File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
|
throw new IOException(
|
||||||
|
"File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
|
||||||
}
|
}
|
||||||
doc.save(ZUGFeRDfilename);
|
doc.save(ZUGFeRDfilename);
|
||||||
if (!disableAutoClose) {
|
if (!disableAutoClose) {
|
||||||
@@ -296,15 +316,15 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
|
|
||||||
public void export(OutputStream output) throws IOException {
|
public void export(OutputStream output) throws IOException {
|
||||||
if (!fileAttached) {
|
if (!fileAttached) {
|
||||||
throw new IOException("File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
|
throw new IOException(
|
||||||
|
"File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
|
||||||
}
|
}
|
||||||
doc.save(output);
|
doc.save(output);
|
||||||
if (!disableAutoClose) {
|
if (!disableAutoClose) {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Embeds an external file (generic - any type allowed) in the PDF.
|
* Embeds an external file (generic - any type allowed) in the PDF.
|
||||||
*
|
*
|
||||||
@@ -324,7 +344,7 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
*/
|
*/
|
||||||
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
|
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
|
||||||
String subType, byte[] data) throws IOException {
|
String subType, byte[] data) throws IOException {
|
||||||
fileAttached=true;
|
fileAttached = true;
|
||||||
|
|
||||||
PDComplexFileSpecification fs = new PDComplexFileSpecification();
|
PDComplexFileSpecification fs = new PDComplexFileSpecification();
|
||||||
fs.setFile(filename);
|
fs.setFile(filename);
|
||||||
@@ -412,7 +432,7 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
if (zUGFeRDConformanceLevel == null) {
|
if (zUGFeRDConformanceLevel == null) {
|
||||||
throw new NullPointerException("ZUGFeRD conformance level");
|
throw new NullPointerException("ZUGFeRD conformance level");
|
||||||
}
|
}
|
||||||
this.zUGFeRDConformanceLevel = zUGFeRDConformanceLevel;
|
this.profile = zUGFeRDConformanceLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -425,7 +445,7 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setZUGFeRDConformanceLevel(String zUGFeRDConformanceLevel) {
|
public void setZUGFeRDConformanceLevel(String zUGFeRDConformanceLevel) {
|
||||||
this.zUGFeRDConformanceLevel = ZUGFeRDConformanceLevel.valueOf(zUGFeRDConformanceLevel);
|
this.profile = ZUGFeRDConformanceLevel.valueOf(zUGFeRDConformanceLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
@@ -437,6 +457,107 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will add both the RDF-indication which embedded file is Zugferd and the
|
||||||
|
* neccessary PDF/A schema extension description to be able to add this
|
||||||
|
* information to RDF
|
||||||
|
*
|
||||||
|
* @param metadata
|
||||||
|
*/
|
||||||
|
protected void addXMP(XMPMetadata metadata) {
|
||||||
|
|
||||||
|
if (attachZUGFeRDHeaders) {
|
||||||
|
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, profile,
|
||||||
|
ZUGFeRDExporter.getNamespaceForVersion(ZFVersion), ZUGFeRDExporter.getPrefixForVersion(ZFVersion),
|
||||||
|
ZUGFeRDExporter.getFilenameForVersion(ZFVersion));
|
||||||
|
|
||||||
|
metadata.addSchema(zf);
|
||||||
|
}
|
||||||
|
|
||||||
|
XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata, ZFVersion, attachZUGFeRDHeaders);
|
||||||
|
pdfaex.setZUGFeRDVersion(ZFVersion);
|
||||||
|
metadata.addSchema(pdfaex);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
|
||||||
|
XmpSerializer serializer = new XmpSerializer();
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
String prefix = "<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
|
||||||
|
String suffix = "<?xpacket end=\"w\"?>";
|
||||||
|
|
||||||
|
try {
|
||||||
|
buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44
|
||||||
|
serializer.serialize(xmpMetadata, buffer, false);
|
||||||
|
buffer.write(suffix.getBytes("UTF-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void prepareDocument(PDDocument doc) throws IOException {
|
||||||
|
String fullProducer = producer + " (via mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + ")";
|
||||||
|
|
||||||
|
PDDocumentCatalog cat = doc.getDocumentCatalog();
|
||||||
|
metadata = new PDMetadata(doc);
|
||||||
|
cat.setMetadata(metadata);
|
||||||
|
|
||||||
|
xmp = XMPMetadata.createXMPMetadata();
|
||||||
|
|
||||||
|
pdfaid = new PDFAIdentificationSchema(xmp);
|
||||||
|
|
||||||
|
xmp.addSchema(pdfaid);
|
||||||
|
|
||||||
|
DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema();
|
||||||
|
|
||||||
|
dc.addCreator(creator);
|
||||||
|
|
||||||
|
XMPBasicSchema xsb = xmp.createAndAddXMPBasicSchema();
|
||||||
|
|
||||||
|
xsb.setCreatorTool(creator);
|
||||||
|
xsb.setCreateDate(GregorianCalendar.getInstance());
|
||||||
|
// PDDocumentInformation pdi=doc.getDocumentInformation();
|
||||||
|
PDDocumentInformation pdi = new PDDocumentInformation();
|
||||||
|
pdi.setProducer(fullProducer);
|
||||||
|
pdi.setAuthor(creator);
|
||||||
|
doc.setDocumentInformation(pdi);
|
||||||
|
|
||||||
|
AdobePDFSchema pdf = xmp.createAndAddAdobePDFSchema();
|
||||||
|
pdf.setProducer(fullProducer);
|
||||||
|
if (ensurePDFisUpgraded) {
|
||||||
|
try {
|
||||||
|
pdfaid.setConformance(conformanceLevel.getLetter());// $NON-NLS-1$ //$NON-NLS-1$
|
||||||
|
} catch (BadFieldValueException ex) {
|
||||||
|
// This should be impossible, because it would occur only if an illegal
|
||||||
|
// conformance level is supplied,
|
||||||
|
// however the enum enforces that the conformance level is valid.
|
||||||
|
throw new Error(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfaid.setPart(3);
|
||||||
|
}
|
||||||
|
if (attachZUGFeRDHeaders) {
|
||||||
|
addXMP(xmp); /*
|
||||||
|
* this is the only line where we do something Zugferd-specific, i.e. add PDF
|
||||||
|
* metadata specifically for Zugferd, not generically for a embedded file
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
metadata.importXMPMetadata(serializeXmpMetadata(xmp));
|
||||||
|
|
||||||
|
} catch (TransformerException e) {
|
||||||
|
throw new ZUGFeRDExportException("Could not export XmpMetadata", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAutoCloseDisabled() {
|
public boolean isAutoCloseDisabled() {
|
||||||
return disableAutoClose;
|
return disableAutoClose;
|
||||||
}
|
}
|
||||||
@@ -445,4 +566,22 @@ public class ZUGFeRDExporter implements Closeable {
|
|||||||
this.disableAutoClose = disableAutoClose;
|
this.disableAutoClose = disableAutoClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void setCreator(String creator) {
|
||||||
|
this.creator = creator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void setProducer(String producer) {
|
||||||
|
this.producer = producer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPDFA3(boolean ensurePDFisUpgraded) {
|
||||||
|
this.ensurePDFisUpgraded = ensurePDFisUpgraded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachZUGFeRDHeaders(boolean attachZUGFeRDHeaders) {
|
||||||
|
this.attachZUGFeRDHeaders=attachZUGFeRDHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,10 @@
|
|||||||
package org.mustangproject.ZUGFeRD;
|
package org.mustangproject.ZUGFeRD;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.xmpbox.type.BadFieldValueException;
|
|
||||||
|
|
||||||
public class ZUGFeRDExporterFromA1Factory extends ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
public class ZUGFeRDExporterFromA1Factory extends ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
||||||
|
public ZUGFeRDExporterFromA1Factory() {
|
||||||
/**
|
ensurePDFisUpgraded=true;
|
||||||
* Make a PDF A/3 from the PDF A/1
|
|
||||||
*/
|
|
||||||
public void prepareDocument(PDDocument doc) throws IOException {
|
|
||||||
super.prepareDocument(doc);
|
|
||||||
/*
|
|
||||||
* // Mandatory: PDF/A3-a is tagged PDF which has to be expressed using a //
|
|
||||||
* MarkInfo dictionary (PDF A/3 Standard sec. 6.7.2.2) PDMarkInfo markinfo = new
|
|
||||||
* PDMarkInfo(); markinfo.setMarked(true);
|
|
||||||
* doc.getDocumentCatalog().setMarkInfo(markinfo);
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* To be on the safe side, we use level B without Markinfo because we can not
|
|
||||||
* guarantee that the user correctly tagged the templates for the PDF.
|
|
||||||
*/
|
|
||||||
try {
|
|
||||||
pdfaid.setConformance(conformanceLevel.getLetter());// $NON-NLS-1$ //$NON-NLS-1$
|
|
||||||
} catch (BadFieldValueException ex) {
|
|
||||||
// This should be impossible, because it would occur only if an illegal
|
|
||||||
// conformance level is supplied,
|
|
||||||
// however the enum enforces that the conformance level is valid.
|
|
||||||
throw new Error(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfaid.setPart(3);
|
|
||||||
|
|
||||||
if (attachZugferdHeaders) {
|
|
||||||
addXMP(xmp); /*
|
|
||||||
* this is the only line where we do something Zugferd-specific, i.e. add PDF
|
|
||||||
* metadata specifically for Zugferd, not generically for a embedded file
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
metadata.importXMPMetadata(serializeXmpMetadata(xmp));
|
|
||||||
|
|
||||||
} catch (TransformerException e) {
|
|
||||||
throw new ZUGFeRDExportException("Could not export XmpMetadata", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,31 +2,19 @@ package org.mustangproject.ZUGFeRD;
|
|||||||
|
|
||||||
import org.apache.pdfbox.io.IOUtils;
|
import org.apache.pdfbox.io.IOUtils;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
|
||||||
import org.apache.pdfbox.preflight.PreflightDocument;
|
import org.apache.pdfbox.preflight.PreflightDocument;
|
||||||
import org.apache.pdfbox.preflight.exception.ValidationException;
|
import org.apache.pdfbox.preflight.exception.ValidationException;
|
||||||
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
||||||
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
|
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
|
||||||
import org.apache.xmpbox.XMPMetadata;
|
|
||||||
import org.apache.xmpbox.schema.AdobePDFSchema;
|
|
||||||
import org.apache.xmpbox.schema.DublinCoreSchema;
|
|
||||||
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
|
|
||||||
import org.apache.xmpbox.schema.XMPBasicSchema;
|
|
||||||
import org.apache.xmpbox.xml.XmpSerializer;
|
|
||||||
|
|
||||||
import javax.activation.DataSource;
|
import javax.activation.DataSource;
|
||||||
import javax.activation.FileDataSource;
|
import javax.activation.FileDataSource;
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.zip.ZipFile;
|
|
||||||
|
|
||||||
public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
||||||
protected boolean ignorePDFAErrors = false;
|
protected boolean ignorePDFAErrors = false;
|
||||||
@@ -34,13 +22,10 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
|||||||
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
||||||
protected String producer = "mustangproject";
|
protected String producer = "mustangproject";
|
||||||
protected String creator = "mustangproject";
|
protected String creator = "mustangproject";
|
||||||
protected boolean attachZugferdHeaders = true;
|
|
||||||
|
|
||||||
|
|
||||||
protected PDMetadata metadata = null;
|
|
||||||
protected PDFAIdentificationSchema pdfaid = null;
|
|
||||||
protected XMPMetadata xmp = null;
|
|
||||||
protected int ZFVersion=ZUGFeRDExporter.DefaultZUGFeRDVersion;
|
protected int ZFVersion=ZUGFeRDExporter.DefaultZUGFeRDVersion;
|
||||||
|
protected boolean ensurePDFisUpgraded=false;
|
||||||
|
private boolean attachZUGFeRDHeaders=true;
|
||||||
/**
|
/**
|
||||||
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
|
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
|
||||||
* metadata level, this will not e.g. convert graphics to JPG-2000)
|
* metadata level, this will not e.g. convert graphics to JPG-2000)
|
||||||
@@ -53,46 +38,18 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
|||||||
ensurePDFIsValidPDFA(new FileDataSource(pdfFilename));
|
ensurePDFIsValidPDFA(new FileDataSource(pdfFilename));
|
||||||
ZUGFeRDExporter zugFeRDExporter;
|
ZUGFeRDExporter zugFeRDExporter;
|
||||||
PDDocument doc = PDDocument.load(new File(pdfFilename));
|
PDDocument doc = PDDocument.load(new File(pdfFilename));
|
||||||
prepareDocument(doc);
|
|
||||||
zugFeRDExporter = new ZUGFeRDExporter(doc);
|
zugFeRDExporter = new ZUGFeRDExporter(doc);
|
||||||
zugFeRDExporter.setZUGFeRDVersion(ZFVersion);
|
zugFeRDExporter.setZUGFeRDVersion(ZFVersion);
|
||||||
zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel);
|
zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel);
|
||||||
|
zugFeRDExporter.setCreator(creator);
|
||||||
|
zugFeRDExporter.setProducer(producer);
|
||||||
|
zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders);
|
||||||
|
zugFeRDExporter.setPDFA3(ensurePDFisUpgraded);
|
||||||
|
|
||||||
return zugFeRDExporter;
|
return zugFeRDExporter;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void prepareDocument(PDDocument doc) throws IOException {
|
|
||||||
String fullProducer = producer + " (via mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + ")";
|
|
||||||
|
|
||||||
PDDocumentCatalog cat = doc.getDocumentCatalog();
|
|
||||||
metadata = new PDMetadata(doc);
|
|
||||||
cat.setMetadata(metadata);
|
|
||||||
|
|
||||||
xmp = XMPMetadata.createXMPMetadata();
|
|
||||||
|
|
||||||
pdfaid = new PDFAIdentificationSchema(xmp);
|
|
||||||
|
|
||||||
xmp.addSchema(pdfaid);
|
|
||||||
|
|
||||||
DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema();
|
|
||||||
|
|
||||||
dc.addCreator(creator);
|
|
||||||
|
|
||||||
XMPBasicSchema xsb = xmp.createAndAddXMPBasicSchema();
|
|
||||||
|
|
||||||
xsb.setCreatorTool(creator);
|
|
||||||
xsb.setCreateDate(GregorianCalendar.getInstance());
|
|
||||||
// PDDocumentInformation pdi=doc.getDocumentInformation();
|
|
||||||
PDDocumentInformation pdi = new PDDocumentInformation();
|
|
||||||
pdi.setProducer(fullProducer);
|
|
||||||
pdi.setAuthor(creator);
|
|
||||||
doc.setDocumentInformation(pdi);
|
|
||||||
|
|
||||||
AdobePDFSchema pdf = xmp.createAndAddAdobePDFSchema();
|
|
||||||
pdf.setProducer(fullProducer);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,12 +63,21 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
|||||||
ensurePDFIsValidPDFA(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
|
ensurePDFIsValidPDFA(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
|
||||||
ZUGFeRDExporter zugFeRDExporter;
|
ZUGFeRDExporter zugFeRDExporter;
|
||||||
PDDocument doc = PDDocument.load(pdfBinary);
|
PDDocument doc = PDDocument.load(pdfBinary);
|
||||||
prepareDocument(doc);
|
|
||||||
zugFeRDExporter = new ZUGFeRDExporter(doc);
|
zugFeRDExporter = new ZUGFeRDExporter(doc);
|
||||||
zugFeRDExporter.setZUGFeRDVersion(ZFVersion);
|
zugFeRDExporter.setZUGFeRDVersion(ZFVersion);
|
||||||
zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel);
|
zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel);
|
||||||
|
zugFeRDExporter.setCreator(creator);
|
||||||
|
zugFeRDExporter.setProducer(producer);
|
||||||
|
zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders);
|
||||||
|
zugFeRDExporter.setPDFA3(ensurePDFisUpgraded);
|
||||||
|
|
||||||
return zugFeRDExporter;
|
return zugFeRDExporter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ZUGFeRDExporterFromA3Factory () {
|
||||||
|
|
||||||
|
ensurePDFisUpgraded=false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
|
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
|
||||||
@@ -135,53 +101,10 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
|||||||
IOUtils.copy(in, buffer);
|
IOUtils.copy(in, buffer);
|
||||||
return buffer.toByteArray();
|
return buffer.toByteArray();
|
||||||
}
|
}
|
||||||
|
private static boolean isValidA1(DataSource dataSource) throws IOException {
|
||||||
public byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
|
|
||||||
XmpSerializer serializer = new XmpSerializer();
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
String prefix="<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
|
|
||||||
String suffix="<?xpacket end=\"w\"?>";
|
|
||||||
|
|
||||||
try {
|
|
||||||
buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44
|
|
||||||
serializer.serialize(xmpMetadata, buffer, false);
|
|
||||||
buffer.write(suffix.getBytes("UTF-8"));
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return buffer.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isValidA1(DataSource dataSource) throws IOException {
|
|
||||||
return getPDFAParserValidationResult(new PreflightParser(dataSource));
|
return getPDFAParserValidationResult(new PreflightParser(dataSource));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This will add both the RDF-indication which embedded file is Zugferd and the
|
|
||||||
* neccessary PDF/A schema extension description to be able to add this
|
|
||||||
* information to RDF
|
|
||||||
*
|
|
||||||
* @param metadata
|
|
||||||
*/
|
|
||||||
public void addXMP(XMPMetadata metadata) {
|
|
||||||
|
|
||||||
if (attachZugferdHeaders) {
|
|
||||||
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, zugferdConformanceLevel, ZUGFeRDExporter.getNamespaceForVersion(ZFVersion), ZUGFeRDExporter.getPrefixForVersion(ZFVersion), ZUGFeRDExporter.getFilenameForVersion(ZFVersion) );
|
|
||||||
|
|
||||||
metadata.addSchema(zf);
|
|
||||||
}
|
|
||||||
|
|
||||||
XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata, ZFVersion, attachZugferdHeaders);
|
|
||||||
pdfaex.setZUGFeRDVersion(ZFVersion);
|
|
||||||
metadata.addSchema(pdfaex);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the ZUGFeRD conformance level (override).
|
* Sets the ZUGFeRD conformance level (override).
|
||||||
*
|
*
|
||||||
@@ -246,10 +169,6 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExporterFactory setAttachZUGFeRDHeaders(final boolean attachZugferdHeaders) {
|
|
||||||
this.attachZugferdHeaders = attachZugferdHeaders;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IExporterFactory setCreator(String creator) {
|
public IExporterFactory setCreator(String creator) {
|
||||||
this.creator = creator;
|
this.creator = creator;
|
||||||
@@ -260,6 +179,10 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
|||||||
this.producer = producer;
|
this.producer = producer;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public IExporterFactory setAttachZUGFeRDHeaders(boolean attachHeaders) {
|
||||||
|
this.attachZUGFeRDHeaders = attachHeaders;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user