commit 6e07f2e280dfd1310989b513b33c357bb8edcc39 Author: Thomas Chojecki Date: Tue Apr 8 01:01:39 2014 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b6f65cc6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target +/.project +/.classpath +/.settings +/PDFA*.pdf diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..fbc624a2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,43 @@ + + 4.0.0 + com.github.rayman2200 + pdfa3 + 0.0.1-SNAPSHOT + + + + apache-snapshot + http://repository.apache.org/content/groups/snapshots + + + + + + org.apache.pdfbox + pdfbox + 2.0.0-SNAPSHOT + compile + + + junit + junit + 4.8 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + + + \ No newline at end of file diff --git a/src/main/java/pdfbox/PDFA3File.java b/src/main/java/pdfbox/PDFA3File.java new file mode 100644 index 00000000..2900be4c --- /dev/null +++ b/src/main/java/pdfbox/PDFA3File.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package pdfbox; + +import java.io.IOException; +import java.io.InputStream; +import java.util.GregorianCalendar; + +import javax.xml.transform.TransformerException; + +import org.apache.jempbox.xmp.XMPMetadata; +import org.apache.jempbox.xmp.XMPSchemaBasic; +import org.apache.jempbox.xmp.XMPSchemaDublinCore; +import org.apache.jempbox.xmp.XMPSchemaPDF; +import org.apache.jempbox.xmp.pdfa.XMPSchemaPDFAId; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentCatalog; +import org.apache.pdfbox.pdmodel.PDDocumentInformation; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDMetadata; +import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo; +import org.apache.pdfbox.pdmodel.edit.PDPageContentStream; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont; +import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent; + +/** + * This is an example that creates a simple PDF/A document. + * + */ +public class PDFA3File +{ + + /** + * Create a simple PDF/A-3 document. + * + * This example is based on HelloWorld example. + * + * As it is a simple case, to conform the PDF/A norm, are added : - the font + * used in the document - the sRGB color profile - a light xmp block with only + * PDF identification schema (the only mandatory) - an output intent To + * conform to A/3 - the mandatory MarkInfo dictionary displays tagged PDF + * support - and optional producer and - optional creator info is added + * + * + * @param file + * The file to write the PDF to. + * @param message + * The message to write in the file. + * + * @throws Exception + * If something bad occurs + */ + public void doIt(String file, String message) throws Exception + { + // the document + PDDocument doc = null; + try { + doc = new PDDocument(); + + // now create the page and add content + PDPage page = new PDPage(); + + doc.addPage(page); + + InputStream fontStream = PDFA3File.class.getResourceAsStream("/Ubuntu-R.ttf"); + PDFont font = PDTrueTypeFont.loadTTF(doc, fontStream); + + // create a page with the message where needed + PDPageContentStream contentStream = new PDPageContentStream(doc, page); + contentStream.beginText(); + contentStream.setFont(font, 12); + contentStream.moveTextPositionByAmount(100, 700); + contentStream.drawString(message); + contentStream.endText(); + contentStream.saveGraphicsState(); + contentStream.close(); + + PDDocumentCatalog cat = makeA3compliant(doc); + + InputStream colorProfile = PDFA3File.class.getResourceAsStream("/sRGB Color Space Profile.icm"); + + // create output intent + 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"); + cat.addOutputIntent(oi); + + doc.save(file); + + } finally { + if (doc != null) { + doc.close(); + } + } + } + + /** + * 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) + * */ + private PDDocumentCatalog makeA3compliant(PDDocument doc) throws IOException, TransformerException + { + PDDocumentCatalog cat = doc.getDocumentCatalog(); + PDMetadata metadata = new PDMetadata(doc); + cat.setMetadata(metadata); + // jempbox version + XMPMetadata xmp = new XMPMetadata(); + XMPSchemaPDFAId pdfaid = new XMPSchemaPDFAId(xmp); + xmp.addSchema(pdfaid); + + XMPSchemaDublinCore dc = xmp.addDublinCoreSchema(); + String creator = System.getProperty("user.name"); + String producer = "PDFBOX"; + dc.addCreator(creator); + dc.setAbout(""); + + XMPSchemaBasic xsb = xmp.addBasicSchema(); + xsb.setAbout(""); + + xsb.setCreatorTool(creator); + xsb.setCreateDate(GregorianCalendar.getInstance()); + // PDDocumentInformation pdi=doc.getDocumentInformation(); + PDDocumentInformation pdi = new PDDocumentInformation(); + pdi.setProducer(producer); + pdi.setAuthor(creator); + doc.setDocumentInformation(pdi); + + XMPSchemaPDF pdf = xmp.addPDFSchema(); + pdf.setProducer(producer); + pdf.setAbout(""); + + // Mandatory: PDF-A3 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); + + pdfaid.setPart(3); + pdfaid.setConformance("A");/* + * All files are PDF/A-3, setConformance refers + * to the level conformance, e.g. PDF/A-3-B where + * B means only visually preservable, U means + * visually and unicode preservable and A -like + * in this case- means full compliance, i.e. + * visually, unicode and structurally preservable + */ + pdfaid.setAbout(""); + metadata.importXMPMetadata(xmp); + return cat; + } + + /** + * This will create a hello world PDF/A document.
+ * see usage() for commandline + * + * @param args + * Command line arguments. + */ + public static void main(String[] args) + { + PDFA3File app = new PDFA3File(); + try { + if (args.length != 2) { + app.usage(); + } else { + app.doIt(args[0], args[1]); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * This will print out a message telling how to use this example. + */ + private void usage() + { + System.err.println("usage: " + this.getClass().getName() + " "); + } +} \ No newline at end of file diff --git a/src/main/java/pdfbox/PDFA3FileAttachment.java b/src/main/java/pdfbox/PDFA3FileAttachment.java new file mode 100644 index 00000000..22443a70 --- /dev/null +++ b/src/main/java/pdfbox/PDFA3FileAttachment.java @@ -0,0 +1,270 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package pdfbox; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.transform.TransformerException; + +import org.apache.jempbox.xmp.XMPMetadata; +import org.apache.jempbox.xmp.XMPSchemaBasic; +import org.apache.jempbox.xmp.XMPSchemaDublinCore; +import org.apache.jempbox.xmp.XMPSchemaPDF; +import org.apache.jempbox.xmp.pdfa.XMPSchemaPDFAId; +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentCatalog; +import org.apache.pdfbox.pdmodel.PDDocumentInformation; +import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary; +import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDMetadata; +import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification; +import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; +import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo; +import org.apache.pdfbox.pdmodel.edit.PDPageContentStream; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont; +import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent; + +/** + * This is an example that creates a simple PDF/A document. + * + */ +public class PDFA3FileAttachment +{ + /** + * Constructor. + */ + public PDFA3FileAttachment() + { + super(); + } + + private void attachSampleFile(PDDocument doc) throws IOException + { + PDEmbeddedFilesNameTreeNode efTree = new PDEmbeddedFilesNameTreeNode(); + + // first create the file specification, which holds the embedded file + + PDComplexFileSpecification fs = new PDComplexFileSpecification(); + fs.setFile("Test.txt"); + COSDictionary dict = fs.getCOSDictionary(); + // Relation "Source" for linking with eg. catalog + dict.setName("AFRelationship", "Source"); + + dict.setString("UF", "Test.txt"); + // fs.put(new PdfName("AFRelationship"), new PdfName("Source")); + + String payload = "This is a test"; + + InputStream is = new ByteArrayInputStream(payload.getBytes()); + + PDEmbeddedFile ef = new PDEmbeddedFile(doc, is); + // set some of the attributes of the embedded file + + ef.setSubtype("text/plain"); + ef.setFile(fs); + + ef.setModDate(GregorianCalendar.getInstance()); + + // PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(writer, + // src.getAbsolutePath(), src.getName(), null, false, "image/jpeg", + // fileParameter); + + // fs.put(new PdfName("AFRelationship"), new PdfName("Source")); + + ef.setSize(payload.length()); + ef.setCreationDate(new GregorianCalendar()); + fs.setEmbeddedFile(ef); + + // now add the entry to the embedded file tree and set in the document. + Map efMap = new HashMap(); + efMap.put("My first attachment", fs); + efTree.setNames(efMap); + + /** + * Validating file "RE-20131206_22.pdf" for conformance level pdfa-3a The + * key UF is required but missing. The key AFRelationship is required but + * missing. File specification 'Test.txt' not associated with an object. + * + * */ + // attachments are stored as part of the "names" dictionary in the document + // catalog + PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog()); + names.setEmbeddedFiles(efTree); + + doc.getDocumentCatalog().setNames(names); + + } + + /** + * Create a simple PDF/A-3 document. + * + * This example is based on HelloWorld example. + * + * As it is a simple case, to conform the PDF/A norm, are added : - the font + * used in the document - the sRGB color profile - a light xmp block with only + * PDF identification schema (the only mandatory) - an output intent To + * conform to A/3 - the mandatory MarkInfo dictionary displays tagged PDF + * support - and optional producer and - optional creator info is added + * + * + * @param file + * The file to write the PDF to. + * @param message + * The message to write in the file. + * + * @throws Exception + * If something bad occurs + */ + public void doIt(String file, String message) throws Exception + { + // the document + PDDocument doc = null; + try { + doc = new PDDocument(); + + // now create the page and add content + PDPage page = new PDPage(); + + doc.addPage(page); + + InputStream fontStream = PDFA3FileAttachment.class.getResourceAsStream("/Ubuntu-R.ttf"); + PDFont font = PDTrueTypeFont.loadTTF(doc, fontStream); + + // create a page with the message where needed + PDPageContentStream contentStream = new PDPageContentStream(doc, page); + contentStream.beginText(); + contentStream.setFont(font, 12); + contentStream.moveTextPositionByAmount(100, 700); + contentStream.drawString(message); + contentStream.endText(); + contentStream.saveGraphicsState(); + contentStream.close(); + + PDDocumentCatalog cat = makeA3compliant(doc); + attachSampleFile(doc); + + InputStream colorProfile = PDFA3FileAttachment.class.getResourceAsStream("/sRGB Color Space Profile.icm"); + // create output intent + 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"); + cat.addOutputIntent(oi); + + doc.save(file); + + } finally { + if (doc != null) { + doc.close(); + } + } + } + + /** + * 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) + * */ + private PDDocumentCatalog makeA3compliant(PDDocument doc) throws IOException, TransformerException + { + PDDocumentCatalog cat = doc.getDocumentCatalog(); + PDMetadata metadata = new PDMetadata(doc); + cat.setMetadata(metadata); + // jempbox version + XMPMetadata xmp = new XMPMetadata(); + XMPSchemaPDFAId pdfaid = new XMPSchemaPDFAId(xmp); + xmp.addSchema(pdfaid); + + XMPSchemaDublinCore dc = xmp.addDublinCoreSchema(); + String creator = System.getProperty("user.name"); + String producer = "PDFBOX"; + dc.addCreator(creator); + dc.setAbout(""); + + XMPSchemaBasic xsb = xmp.addBasicSchema(); + xsb.setAbout(""); + + xsb.setCreatorTool(creator); + xsb.setCreateDate(GregorianCalendar.getInstance()); + // PDDocumentInformation pdi=doc.getDocumentInformation(); + PDDocumentInformation pdi = new PDDocumentInformation(); + pdi.setProducer(producer); + pdi.setAuthor(creator); + doc.setDocumentInformation(pdi); + + XMPSchemaPDF pdf = xmp.addPDFSchema(); + pdf.setProducer(producer); + pdf.setAbout(""); + + // Mandatory: PDF-A3 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); + + pdfaid.setPart(3); + pdfaid.setConformance("A");/* + * All files are PDF/A-3, setConformance refers + * to the level conformance, e.g. PDF/A-3-B where + * B means only visually preservable, U means + * visually and unicode preservable and A -like + * in this case- means full compliance, i.e. + * visually, unicode and structurally preservable + */ + pdfaid.setAbout(""); + metadata.importXMPMetadata(xmp); + return cat; + } + + /** + * This will create a hello world PDF/A document.
+ * see usage() for commandline + * + * @param args + * Command line arguments. + */ + public static void main(String[] args) + { + PDFA3FileAttachment app = new PDFA3FileAttachment(); + try { + if (args.length != 2) { + app.usage(); + } else { + app.doIt(args[0], args[1]); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * This will print out a message telling how to use this example. + */ + private void usage() + { + System.err.println("usage: " + this.getClass().getName() + " "); + } +} \ No newline at end of file diff --git a/src/main/java/pdfbox/PDFAFile.java b/src/main/java/pdfbox/PDFAFile.java new file mode 100644 index 00000000..acd29cb7 --- /dev/null +++ b/src/main/java/pdfbox/PDFAFile.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package pdfbox; + +import java.io.InputStream; + +import org.apache.jempbox.xmp.XMPMetadata; +import org.apache.jempbox.xmp.pdfa.XMPSchemaPDFAId; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentCatalog; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.common.PDMetadata; +import org.apache.pdfbox.pdmodel.edit.PDPageContentStream; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont; +import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent; + +/** + * This is an example that creates a simple PDF/A document. + * + */ +public class PDFAFile +{ + /** + * Constructor. + */ + public PDFAFile() + { + super(); + } + + /** + * Create a simple PDF/A document. + * + * This example is based on HelloWorld example. + * + * As it is a simple case, to conform the PDF/A norm, are added : - the font + * used in the document - a light xmp block with only PDF identification + * schema (the only mandatory) - an output intent + * + * @param file + * The file to write the PDF to. + * @param message + * The message to write in the file. + * + * @throws Exception + * If something bad occurs + */ + public void doIt(String file, String message) throws Exception + { + // the document + PDDocument doc = null; + try { + doc = new PDDocument(); + + PDPage page = new PDPage(); + doc.addPage(page); + + InputStream fontStream = PDFA3File.class.getResourceAsStream("/Ubuntu-R.ttf"); + PDFont font = PDTrueTypeFont.loadTTF(doc, fontStream); + + // create a page with the message where needed + PDPageContentStream contentStream = new PDPageContentStream(doc, page); + contentStream.beginText(); + contentStream.setFont(font, 12); + contentStream.moveTextPositionByAmount(100, 700); + contentStream.drawString(message); + contentStream.endText(); + contentStream.saveGraphicsState(); + contentStream.close(); + + PDDocumentCatalog cat = doc.getDocumentCatalog(); + PDMetadata metadata = new PDMetadata(doc); + cat.setMetadata(metadata); + + // jempbox version + XMPMetadata xmp = new XMPMetadata(); + XMPSchemaPDFAId pdfaid = new XMPSchemaPDFAId(xmp); + xmp.addSchema(pdfaid); + pdfaid.setConformance("B"); + pdfaid.setPart(1); + pdfaid.setAbout(""); + metadata.importXMPMetadata(xmp); + + InputStream colorProfile = PDFA3File.class.getResourceAsStream("/sRGB Color Space Profile.icm"); + // create output intent + 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"); + cat.addOutputIntent(oi); + + doc.save(file); + + } finally { + if (doc != null) { + doc.close(); + } + } + } + + /** + * This will create a hello world PDF/A document.
+ * see usage() for commandline + * + * @param args + * Command line arguments. + */ + public static void main(String[] args) + { + PDFAFile app = new PDFAFile(); + try { + if (args.length != 2) { + app.usage(); + } else { + app.doIt(args[0], args[1]); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * This will print out a message telling how to use this example. + */ + private void usage() + { + System.err.println("usage: " + this.getClass().getName() + " "); + } +} \ No newline at end of file diff --git a/src/main/resources/Ubuntu-R.ttf b/src/main/resources/Ubuntu-R.ttf new file mode 100644 index 00000000..45a038ba Binary files /dev/null and b/src/main/resources/Ubuntu-R.ttf differ diff --git a/src/main/resources/sRGB Color Space Profile.icm b/src/main/resources/sRGB Color Space Profile.icm new file mode 100644 index 00000000..7f9d18d0 Binary files /dev/null and b/src/main/resources/sRGB Color Space Profile.icm differ diff --git a/src/test/java/pdfa3/TestPDFA3.java b/src/test/java/pdfa3/TestPDFA3.java new file mode 100644 index 00000000..dde56a2f --- /dev/null +++ b/src/test/java/pdfa3/TestPDFA3.java @@ -0,0 +1,30 @@ +package pdfa3; + +import org.junit.Test; + +import pdfbox.PDFA3File; +import pdfbox.PDFA3FileAttachment; +import pdfbox.PDFAFile; + +public class TestPDFA3 +{ + + @Test + public void testPDFA3File() + { + PDFA3File.main(new String[] { "PDFA3File.pdf", "Messsage" }); + } + + @Test + public void testPDFA3FileAttachment() + { + PDFA3FileAttachment.main(new String[] { "PDFA3FileAttachment.pdf", "Messsage" }); + } + + @Test + public void testPDFAFile() + { + PDFAFile.main(new String[] { "PDFAFile.pdf", "Messsage" }); + } + +}