import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.render.pdf.extensions.PDFPageElement;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener;
/** {@inheritDoc} */
public ExtensionAttachment getExtensionAttachment() {
- if (parent instanceof FObj) {
+ if (parent instanceof FObj || parent instanceof PDFPageElement) {
if (attachment == null) {
attachment = new XMPMetadata();
}
put("Tabs", value);
}
+ public void setMetadata(PDFMetadata meta) {
+ put("Metadata", meta.makeReference());
+ }
}
import org.apache.fop.accessibility.Accessibility;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.io.InternalResourceResolver;
+import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFArray;
assert extension instanceof PDFPageExtension;
if (((PDFPageExtension) extension).matchesPageNumber(currentPage.getPageIndex() + 1)) {
augmentDictionary(currentPage, extension);
+ renderExtension(currentPage, extension.getExtension());
}
} else if (type == PDFDictionaryType.Info) {
PDFInfo info = pdfDoc.getInfo();
}
}
+ private void renderExtension(PDFPage currentPage, ExtensionAttachment extension) {
+ if (extension instanceof XMPMetadata) {
+ XMPMetadata metadata = (XMPMetadata) extension;
+ Metadata docXMP = metadata.getMetadata();
+ PDFMetadata pdfMetadata = pdfDoc.getFactory().makeMetadata(docXMP, metadata.isReadOnly());
+ currentPage.setMetadata(pdfMetadata);
+ }
+ }
+
private PDFDictionary augmentDictionary(PDFDictionary dictionary, PDFDictionaryExtension extension) {
for (PDFCollectionEntryExtension entry : extension.getEntries()) {
if (entry instanceof PDFDictionaryExtension) {
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
+import org.apache.xmlgraphics.util.XMLizable;
+
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.util.GenerationHelperContentHandler;
for (PDFCollectionEntryExtension entry : dictionary.getEntries()) {
toSAX(handler, entry);
}
+ if (extension.getExtension() != null) {
+ ((XMLizable) extension.getExtension()).toSAX(handler);
+ }
handler.endElement(CATEGORY, ln, qn);
}
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.fo.extensions.xmp.XMPMetaElement;
// CSOFF: LineLengthCheck
} else if (child instanceof PDFCollectionEntryElement) {
PDFCollectionEntryExtension entry = ((PDFCollectionEntryElement) child).getExtension();
extension.addEntry(entry);
+ } else if (child instanceof XMPMetaElement) {
+ extension.setExtension(child.getExtensionAttachment());
}
}
import java.util.List;
import java.util.Map;
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+
// CSOFF: LineLengthCheck
public class PDFDictionaryExtension extends PDFCollectionExtension {
private PDFDictionaryType dictionaryType;
private Map<String, String> properties;
private List<PDFCollectionEntryExtension> entries;
+ private ExtensionAttachment extension;
PDFDictionaryExtension() {
this(PDFDictionaryType.Dictionary);
return entries;
}
+ public void setExtension(ExtensionAttachment entry) {
+ extension = entry;
+ }
+
+ public ExtensionAttachment getExtension() {
+ return extension;
+ }
+
public PDFCollectionEntryExtension findEntry(String key) {
for (PDFCollectionEntryExtension entry : entries) {
String entryKey = entry.getKey();
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.xmp.XMPConstants;
+import org.apache.xmlgraphics.xmp.XMPHandler;
+
+import org.apache.fop.fo.extensions.xmp.XMPContentHandlerFactory;
+import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener;
private Stack<PDFCollectionExtension> collections = new Stack<PDFCollectionExtension>();
private boolean captureContent;
private StringBuffer characters;
+ private XMPHandler xmpHandler;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
} else {
throw new SAXException("Unhandled element " + localName + " in namespace: " + uri);
}
+ } else if (XMPConstants.XMP_NAMESPACE.equals(uri) || xmpHandler != null) {
+ if (xmpHandler == null) {
+ xmpHandler = (XMPHandler) new XMPContentHandlerFactory().createContentHandler();
+ }
+ xmpHandler.startElement(uri, localName, qName, attributes);
} else {
log.warn("Unhandled element " + localName + " in namespace: " + uri);
}
}
characters.append(data, start, length);
}
+ if (xmpHandler != null) {
+ xmpHandler.characters(data, start, length);
+ }
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (PDFExtensionAttachment.CATEGORY.equals(uri)) {
+ setExtension();
if (PDFEmbeddedFileAttachment.ELEMENT.equals(localName)) {
String name = lastAttributes.getValue("filename");
String src = lastAttributes.getValue("src");
}
}
}
+ if (xmpHandler != null) {
+ xmpHandler.endElement(uri, localName, qName);
+ }
captureContent = false;
}
+ private void setExtension() {
+ if (xmpHandler != null) {
+ PDFPageExtension pdfPageExtension = (PDFPageExtension) collections.peek();
+ XMPMetadata wrapper = new XMPMetadata(xmpHandler.getMetadata());
+ pdfPageExtension.setExtension(wrapper);
+ xmpHandler = null;
+ }
+ }
+
@Override
public void endDocument() throws SAXException {
if (listener != null) {
--- /dev/null
+/*
+ * 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.
+ */
+
+/* $Id$ */
+package org.apache.fop.pdf;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.apps.Fop;
+import org.apache.fop.apps.FopFactory;
+import org.apache.fop.apps.MimeConstants;
+import org.apache.fop.render.intermediate.IFContext;
+import org.apache.fop.render.intermediate.IFDocumentHandler;
+import org.apache.fop.render.intermediate.IFParser;
+import org.apache.fop.render.intermediate.IFSerializer;
+import org.apache.fop.render.intermediate.IFUtil;
+
+public class PDFPageXMPTestCase {
+ private static final String XMP = "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n"
+ + "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n"
+ + "<rdf:Description xmlns:abc=\"http://www.abc.de/abc/\" abc:def=\"val\" rdf:about=\"\"/>\n"
+ + "<rdf:Description xmlns:pdfaExtension=\"http://www.aiim.org/pdfa/ns/extension/\" rdf:about=\"\">\n"
+ + "<pdfaExtension:schemas>\n"
+ + "<rdf:Bag>\n"
+ + "<rdf:li rdf:parseType=\"Resource\">\n"
+ + "<pdfaSchema:property xmlns:pdfaSchema=\"http://www.aiim.org/pdfa/ns/schema#\">\n"
+ + "<rdf:Seq>\n"
+ + "<rdf:li rdf:parseType=\"Resource\">\n"
+ + "<pdfaProperty:name xmlns:pdfaProperty=\"http://www.aiim.org/pdfa/ns/property#\">split</pdfaProperty:name>\n"
+ + "</rdf:li>\n"
+ + "</rdf:Seq>\n"
+ + "</pdfaSchema:property>\n"
+ + "</rdf:li>\n"
+ + "</rdf:Bag>\n"
+ + "</pdfaExtension:schemas>\n"
+ + "</rdf:Description>\n"
+ + "</rdf:RDF>\n"
+ + "</x:xmpmeta>";
+
+ @Test
+ public void textFO() throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ foToOutput(out, MimeConstants.MIME_PDF);
+ Assert.assertTrue(out.toString().replace("\r", "").contains(XMP));
+ }
+
+ @Test
+ public void textIF() throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ foToOutput(out, MimeConstants.MIME_FOP_IF);
+ out = iFToPDF(new ByteArrayInputStream(out.toByteArray()));
+ Assert.assertTrue(out.toString().replace("\r", "").contains(XMP));
+ }
+
+ private ByteArrayOutputStream iFToPDF(InputStream is) throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ FOUserAgent userAgent = getFopFactory().newFOUserAgent();
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ Source src = new StreamSource(is);
+ IFDocumentHandler documentHandler
+ = userAgent.getRendererFactory().createDocumentHandler(userAgent, MimeConstants.MIME_PDF);
+ documentHandler.setResult(new StreamResult(out));
+ IFUtil.setupFonts(documentHandler);
+ IFParser parser = new IFParser();
+ Result res = new SAXResult(parser.getContentHandler(documentHandler, userAgent));
+ transformer.transform(src, res);
+ return out;
+ }
+
+ private void foToOutput(ByteArrayOutputStream out, String mimeFopIf) throws Exception {
+ FopFactory fopFactory = getFopFactory();
+ FOUserAgent userAgent = fopFactory.newFOUserAgent();
+ if (mimeFopIf.equals(MimeConstants.MIME_FOP_IF)) {
+ IFSerializer serializer = new IFSerializer(new IFContext(userAgent));
+ IFDocumentHandler targetHandler
+ = userAgent.getRendererFactory().createDocumentHandler(userAgent, MimeConstants.MIME_PDF);
+ serializer.mimicDocumentHandler(targetHandler);
+ userAgent.setDocumentHandlerOverride(serializer);
+ }
+ Fop fop = fopFactory.newFop(mimeFopIf, userAgent, out);
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ Source src = new StreamSource(PDFPageXMPTestCase.class.getResource("PDFPageXMP.fo").openStream());
+ Result res = new SAXResult(fop.getDefaultHandler());
+ transformer.transform(src, res);
+ }
+
+ private FopFactory getFopFactory() {
+ return FopFactory.newInstance(new File(".").toURI());
+ }
+}
--- /dev/null
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="simple">
+ <fo:region-body/>
+ <fo:region-before/>
+ <fo:region-after/>
+ <pdf:page page-numbers="*">
+ <x:xmpmeta xmlns:x="adobe:ns:meta/">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:abc="http://www.abc.de/abc/">
+ <rdf:Description rdf:about="" abc:def="val"/>
+ <rdf:Description rdf:about="" xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/"
+ xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#"
+ xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">
+ <pdfaExtension:schemas>
+ <rdf:Bag>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaSchema:property>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaProperty:name>split</pdfaProperty:name>
+ </rdf:li>
+ </rdf:Seq>
+ </pdfaSchema:property>
+ </rdf:li>
+ </rdf:Bag>
+ </pdfaExtension:schemas>
+ </rdf:Description>
+ </rdf:RDF>
+ </x:xmpmeta>
+ </pdf:page>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="simple">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>SLIDE 1</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!-- $Id$ -->
+<testcase>
+ <info>
+ <p>
+ This test checks the PDF dictionary extensions.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="simple">
+ <fo:region-body/>
+ <fo:region-before/>
+ <fo:region-after/>
+ <pdf:page page-numbers="*">
+ <x:xmpmeta xmlns:x="adobe:ns:meta/">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:abc="http://www.abc.de/abc/">
+ <rdf:Description rdf:about="" abc:def="val"/>
+ <rdf:Description rdf:about="" xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/"
+ xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#"
+ xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">
+ <pdfaExtension:schemas>
+ <rdf:Bag>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaSchema:property>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaProperty:name>split</pdfaProperty:name>
+ </rdf:li>
+ </rdf:Seq>
+ </pdfaSchema:property>
+ </rdf:li>
+ </rdf:Bag>
+ </pdfaExtension:schemas>
+ </rdf:Description>
+ </rdf:RDF>
+ </x:xmpmeta>
+ </pdf:page>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="simple">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>SLIDE 1</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate" xmlns:pdf="apache:fop:extensions:pdf"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:abc="http://www.abc.de/abc/">
+ <eval expected="val" xpath="//if:page[@name=1]/if:page-header/pdf:page//rdf:Description[1]/@abc:def"/>
+ </if-checks>
+</testcase>