This adds a new intermediate format to FOP. Please see the documentation for details. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@746664 13f79535-47bb-0310-9956-ffa450edef68pull/37/head
@@ -592,11 +592,7 @@ list of possible build targets. | |||
<include name="org/apache/fop/area/AreaTreeControl*"/> | |||
<include name="org/apache/fop/svg/**"/> | |||
<include name="org/apache/fop/fonts/**"/> | |||
<include name="org/apache/fop/image/FopImag*.class"/> | |||
<include name="org/apache/fop/image/Jpeg*"/> | |||
<include name="org/apache/fop/image/EPS*"/> | |||
<include name="org/apache/fop/image/Abstract*"/> | |||
<include name="org/apache/fop/image/analyser/*.class"/> | |||
<include name="org/apache/fop/image/loader/batik/BatikImageFlavors*.class"/> | |||
<include name="org/apache/fop/util/CMYKColorSpace*.class"/> | |||
<include name="org/apache/fop/util/Color*.class"/> | |||
<include name="org/apache/fop/util/ASCII*.class"/> | |||
@@ -604,12 +600,14 @@ list of possible build targets. | |||
<include name="org/apache/fop/util/SubInputStream.class"/> | |||
<include name="org/apache/fop/util/Finalizable.class"/> | |||
<include name="org/apache/fop/util/CharUtilities.class"/> | |||
<include name="org/apache/fop/util/DecimalFormatCache*.class"/> | |||
</patternset> | |||
<!-- PDF transcoder --> | |||
<patternset> | |||
<include name="org/apache/fop/render/pdf/**"/> | |||
<exclude name="org/apache/fop/render/pdf/PDFRenderer.class"/> | |||
<exclude name="org/apache/fop/render/pdf/PDFXMLHandler*"/> | |||
<include name="org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.class"/> | |||
<include name="org/apache/fop/render/*RendererConfigurator**"/> | |||
<include name="org/apache/fop/util/AbstractPaintingState**"/> | |||
<include name="org/apache/fop/pdf/**"/> | |||
@@ -897,25 +895,44 @@ list of possible build targets. | |||
<test name="org.apache.fop.fotreetest.FOTreeTestSuite" todir="${junit.reports.dir}" outfile="TEST-FO-tree"/> | |||
</junit> | |||
</target> | |||
<target name="junit-intermediate-format" depends="junit-compile, junit-layout" description="Runs FOP's intermediate format JUnit tests" if="xmlunit.present"> | |||
<echo message="Running intermediate format tests"/> | |||
<junit dir="${basedir}" haltonfailure="${junit.haltonfailure}" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure"> | |||
<sysproperty key="basedir" value="${basedir}"/> | |||
<sysproperty key="jawa.awt.headless" value="true"/> | |||
<sysproperty key="fop.layoutengine.disabled" value="${layoutengine.disabled}"/> | |||
<sysproperty key="fop.layoutengine.testset" value="standard"/> | |||
<formatter type="brief" usefile="false"/> | |||
<formatter type="plain" usefile="true"/> | |||
<formatter type="xml" usefile="true"/> | |||
<classpath> | |||
<pathelement location="${build.dir}/test-classes"/> | |||
<path refid="libs-build-tools-classpath"/> | |||
<fileset dir="build"> | |||
<include name="fop.jar"/> | |||
</fileset> | |||
</classpath> | |||
<test name="org.apache.fop.intermediate.IntermediateFormatTestSuite" todir="${junit.reports.dir}" outfile="TEST-intermediate-format"/> | |||
</junit> | |||
<macrodef name="junit-run"> | |||
<attribute name="title"/> | |||
<element name="tests"/> | |||
<sequential> | |||
<echo message="Running @{title} tests..."/> | |||
<junit dir="${basedir}" haltonfailure="${junit.haltonfailure}" fork="${junit.fork}" errorproperty="fop.junit.error" failureproperty="fop.junit.failure"> | |||
<sysproperty key="basedir" value="${basedir}"/> | |||
<sysproperty key="jawa.awt.headless" value="true"/> | |||
<sysproperty key="fop.layoutengine.disabled" value="${layoutengine.disabled}"/> | |||
<formatter type="brief" usefile="false"/> | |||
<formatter type="plain" usefile="true"/> | |||
<formatter type="xml" usefile="true"/> | |||
<classpath> | |||
<pathelement location="${build.dir}/test-classes"/> | |||
<path refid="libs-build-tools-classpath"/> | |||
<fileset dir="build"> | |||
<include name="fop.jar"/> | |||
</fileset> | |||
</classpath> | |||
<tests/> | |||
</junit> | |||
</sequential> | |||
</macrodef> | |||
<target name="junit-area-tree-xml-format" depends="junit-compile" description="Runs FOP's area tree XML format JUnit tests" if="xmlunit.present"> | |||
<junit-run title="area tree XML format"> | |||
<tests> | |||
<sysproperty key="fop.layoutengine.testset" value="standard"/> | |||
<test name="org.apache.fop.intermediate.AreaTreeXMLFormatTestSuite" todir="${junit.reports.dir}" outfile="TEST-area-tree-xml-format"/> | |||
</tests> | |||
</junit-run> | |||
</target> | |||
<target name="junit-intermediate-format" depends="junit-compile" description="Runs FOP's intermediate format JUnit tests" if="xmlunit.present"> | |||
<junit-run title="intermediate format"> | |||
<tests> | |||
<sysproperty key="fop.layoutengine.testset" value="standard"/> | |||
<test name="org.apache.fop.intermediate.IntermediateFormatTestSuite" todir="${junit.reports.dir}" outfile="TEST-intermediate-format"/> | |||
</tests> | |||
</junit-run> | |||
</target> | |||
<target name="junit-text-linebreak" depends="junit-compile" description="Runs FOP's JUnit unicode linebreak tests" if="junit.present"> | |||
<echo message="Running tests for Unicode UAX#14 support"/> | |||
@@ -936,7 +953,7 @@ list of possible build targets. | |||
</junit> | |||
</target> | |||
<target name="junit-reduced" depends="junit-userconfig, junit-basic, junit-transcoder, junit-text-linebreak, junit-fotree"/> | |||
<target name="junit-full" depends="junit-reduced, junit-layout, junit-intermediate-format"/> | |||
<target name="junit-full" depends="junit-reduced, junit-layout, junit-area-tree-xml-format, junit-intermediate-format"/> | |||
<target name="junit" depends="junit-full" description="Runs all of FOP's JUnit tests" if="junit.present"> | |||
<fail><condition><or><isset property="fop.junit.error"/><isset property="fop.junit.failure"/><not><isset property="hyphenation.present"/></not></or></condition> | |||
NOTE: |
@@ -0,0 +1,219 @@ | |||
/* | |||
* 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 embedding.atxml; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.xml.sax.SAXException; | |||
import org.apache.fop.apps.FOPException; | |||
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.area.AreaTreeModel; | |||
import org.apache.fop.area.AreaTreeParser; | |||
import org.apache.fop.area.RenderPagesModel; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.render.Renderer; | |||
import org.apache.fop.render.xml.XMLRenderer; | |||
import embedding.ExampleObj2XML; | |||
import embedding.model.ProjectMember; | |||
import embedding.model.ProjectTeam; | |||
/** | |||
* Example for the area tree XML format that demonstrates the concatenation of two documents | |||
* rendered to the area tree XML format. A single PDF file is generated from the two area tree | |||
* files. | |||
*/ | |||
public class ExampleConcat { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
/** | |||
* Creates a sample ProjectTeam instance for this demo. | |||
* @return ProjectTeam the newly created ProjectTeam instance | |||
*/ | |||
public static ProjectTeam createAnotherProjectTeam() { | |||
ProjectTeam team = new ProjectTeam(); | |||
team.setProjectName("The Dynamic Duo"); | |||
team.addMember(new ProjectMember( | |||
"Batman", "lead", "batman@heroes.org")); | |||
team.addMember(new ProjectMember( | |||
"Robin", "aid", "robin@heroes.org")); | |||
return team; | |||
} | |||
/** | |||
* Converts an XSL-FO document to an area tree XML file. | |||
* @param src the source file | |||
* @param xslt the stylesheet file | |||
* @param areaTreeFile the target area tree XML file | |||
* @throws IOException In case of an I/O problem | |||
* @throws FOPException In case of a FOP problem | |||
* @throws TransformerException In case of a XSL transformation problem | |||
*/ | |||
public void convertToAreaTreeXML(Source src, Source xslt, File areaTreeFile) | |||
throws IOException, FOPException, TransformerException { | |||
//Create a user agent | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//Create an instance of the target renderer so the XMLRenderer can use its font setup | |||
Renderer targetRenderer = userAgent.getRendererFactory().createRenderer( | |||
userAgent, MimeConstants.MIME_PDF); | |||
//Create the XMLRenderer to create the area tree XML | |||
XMLRenderer xmlRenderer = new XMLRenderer(); | |||
xmlRenderer.setUserAgent(userAgent); | |||
//Tell the XMLRenderer to mimic the target renderer | |||
xmlRenderer.mimicRenderer(targetRenderer); | |||
//Make sure the prepared XMLRenderer is used | |||
userAgent.setRendererOverride(xmlRenderer); | |||
// Setup output | |||
OutputStream out = new java.io.FileOutputStream(areaTreeFile); | |||
out = new java.io.BufferedOutputStream(out); | |||
try { | |||
// Construct fop (the MIME type here is unimportant due to the override | |||
// on the user agent) | |||
Fop fop = fopFactory.newFop(null, userAgent, out); | |||
// Setup XSLT | |||
TransformerFactory factory = TransformerFactory.newInstance(); | |||
Transformer transformer; | |||
if (xslt != null) { | |||
transformer = factory.newTransformer(xslt); | |||
} else { | |||
transformer = factory.newTransformer(); | |||
} | |||
// Resulting SAX events (the generated FO) must be piped through to FOP | |||
Result res = new SAXResult(fop.getDefaultHandler()); | |||
// Start XSLT transformation and FOP processing | |||
transformer.transform(src, res); | |||
} finally { | |||
out.close(); | |||
} | |||
} | |||
/** | |||
* Concatenates an array of area tree XML files to a single PDF file. | |||
* @param files the array of area tree XML files | |||
* @param pdffile the target PDF file | |||
* @throws IOException In case of an I/O problem | |||
* @throws TransformerException In case of a XSL transformation problem | |||
* @throws SAXException In case of an XML-related problem | |||
*/ | |||
public void concatToPDF(File[] files, File pdffile) | |||
throws IOException, TransformerException, SAXException { | |||
// Setup output | |||
OutputStream out = new java.io.FileOutputStream(pdffile); | |||
out = new java.io.BufferedOutputStream(out); | |||
try { | |||
//Setup fonts and user agent | |||
FontInfo fontInfo = new FontInfo(); | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//Construct the AreaTreeModel that will received the individual pages | |||
AreaTreeModel treeModel = new RenderPagesModel(userAgent, | |||
MimeConstants.MIME_PDF, fontInfo, out); | |||
//Iterate over all area tree files | |||
AreaTreeParser parser = new AreaTreeParser(); | |||
for (int i = 0; i < files.length; i++) { | |||
Source src = new StreamSource(files[i]); | |||
parser.parse(src, treeModel, userAgent); | |||
} | |||
//Signal the end of the processing. The renderer can finalize the target document. | |||
treeModel.endDocument(); | |||
} finally { | |||
out.close(); | |||
} | |||
} | |||
/** | |||
* Main method. | |||
* @param args command-line arguments | |||
*/ | |||
public static void main(String[] args) { | |||
try { | |||
System.out.println("FOP ExampleConcat\n"); | |||
//Setup directories | |||
File baseDir = new File("."); | |||
File outDir = new File(baseDir, "out"); | |||
outDir.mkdirs(); | |||
//Setup output file | |||
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl"); | |||
File[] files = new File[] { | |||
new File(outDir, "team1.at.xml"), | |||
new File(outDir, "team2.at.xml")}; | |||
File pdffile = new File(outDir, "ResultConcat.pdf"); | |||
for (int i = 0; i < files.length; i++) { | |||
System.out.println("Area Tree XML file " + (i + 1) + ": " | |||
+ files[i].getCanonicalPath()); | |||
} | |||
System.out.println("PDF Output File: " + pdffile.getCanonicalPath()); | |||
System.out.println(); | |||
ProjectTeam team1 = ExampleObj2XML.createSampleProjectTeam(); | |||
ProjectTeam team2 = createAnotherProjectTeam(); | |||
ExampleConcat app = new ExampleConcat(); | |||
//Create area tree XML files | |||
app.convertToAreaTreeXML( | |||
team1.getSourceForProjectTeam(), | |||
new StreamSource(xsltfile), files[0]); | |||
app.convertToAreaTreeXML( | |||
team2.getSourceForProjectTeam(), | |||
new StreamSource(xsltfile), files[1]); | |||
//Concatenate the individual area tree files to one document | |||
app.concatToPDF(files, pdffile); | |||
System.out.println("Success!"); | |||
} catch (Exception e) { | |||
e.printStackTrace(System.err); | |||
System.exit(-1); | |||
} | |||
} | |||
} |
@@ -0,0 +1,143 @@ | |||
/* | |||
* 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 embedding.atxml; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.xml.sax.SAXException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.area.AreaTreeModel; | |||
import org.apache.fop.area.AreaTreeParser; | |||
import org.apache.fop.area.RenderPagesModel; | |||
import org.apache.fop.fonts.FontInfo; | |||
import embedding.ExampleObj2XML; | |||
import embedding.model.ProjectTeam; | |||
/** | |||
* Example for the area tree XML format that demonstrates the stamping of a document with some | |||
* kind of watermark. The resulting document is then rendered to a PDF file. | |||
*/ | |||
public class ExampleStamp { | |||
// configure fopFactory as desired | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
/** | |||
* Stamps an area tree XML file and renders it to a PDF file. | |||
* @param atfile the area tree XML file | |||
* @param stampSheet the stylesheet that does the stamping | |||
* @param pdffile the target PDF file | |||
* @throws IOException In case of an I/O problem | |||
* @throws TransformerException In case of a XSL transformation problem | |||
* @throws SAXException In case of an XML-related problem | |||
*/ | |||
public void stampToPDF(File atfile, File stampSheet, File pdffile) | |||
throws IOException, TransformerException, SAXException { | |||
// Setup output | |||
OutputStream out = new java.io.FileOutputStream(pdffile); | |||
out = new java.io.BufferedOutputStream(out); | |||
try { | |||
//Setup fonts and user agent | |||
FontInfo fontInfo = new FontInfo(); | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//Construct the AreaTreeModel that will received the individual pages | |||
AreaTreeModel treeModel = new RenderPagesModel(userAgent, | |||
MimeConstants.MIME_PDF, fontInfo, out); | |||
//Iterate over all area tree files | |||
AreaTreeParser parser = new AreaTreeParser(); | |||
Source src = new StreamSource(atfile); | |||
Source xslt = new StreamSource(stampSheet); | |||
//Setup Transformer for XSLT processing | |||
TransformerFactory tFactory = TransformerFactory.newInstance(); | |||
Transformer transformer = tFactory.newTransformer(xslt); | |||
//Send XSLT result to AreaTreeParser | |||
SAXResult res = new SAXResult(parser.getContentHandler(treeModel, userAgent)); | |||
//Start XSLT transformation and area tree parsing | |||
transformer.transform(src, res); | |||
//Signal the end of the processing. The renderer can finalize the target document. | |||
treeModel.endDocument(); | |||
} finally { | |||
out.close(); | |||
} | |||
} | |||
/** | |||
* Main method. | |||
* @param args command-line arguments | |||
*/ | |||
public static void main(String[] args) { | |||
try { | |||
System.out.println("FOP ExampleConcat\n"); | |||
//Setup directories | |||
File baseDir = new File("."); | |||
File outDir = new File(baseDir, "out"); | |||
outDir.mkdirs(); | |||
//Setup output file | |||
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl"); | |||
File atfile = new File(outDir, "team.at.xml"); | |||
File stampxsltfile = new File(baseDir, "xml/xslt/atstamp.xsl"); | |||
File pdffile = new File(outDir, "ResultStamped.pdf"); | |||
System.out.println("Area Tree XML file : " + atfile.getCanonicalPath()); | |||
System.out.println("Stamp XSLT: " + stampxsltfile.getCanonicalPath()); | |||
System.out.println("PDF Output File: " + pdffile.getCanonicalPath()); | |||
System.out.println(); | |||
ProjectTeam team1 = ExampleObj2XML.createSampleProjectTeam(); | |||
//Create area tree XML file | |||
ExampleConcat concatapp = new ExampleConcat(); | |||
concatapp.convertToAreaTreeXML( | |||
team1.getSourceForProjectTeam(), | |||
new StreamSource(xsltfile), atfile); | |||
//Stamp document and produce a PDF from the area tree XML format | |||
ExampleStamp app = new ExampleStamp(); | |||
app.stampToPDF(atfile, stampxsltfile, pdffile); | |||
System.out.println("Success!"); | |||
} catch (Exception e) { | |||
e.printStackTrace(System.err); | |||
System.exit(-1); | |||
} | |||
} | |||
} |
@@ -29,20 +29,22 @@ import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
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.xml.sax.SAXException; | |||
import org.apache.fop.apps.FOPException; | |||
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.area.AreaTreeModel; | |||
import org.apache.fop.area.AreaTreeParser; | |||
import org.apache.fop.area.RenderPagesModel; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.render.Renderer; | |||
import org.apache.fop.render.xml.XMLRenderer; | |||
import org.xml.sax.SAXException; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFException; | |||
import org.apache.fop.render.intermediate.IFSerializer; | |||
import org.apache.fop.render.intermediate.IFUtil; | |||
import org.apache.fop.render.intermediate.util.IFConcatenator; | |||
import embedding.ExampleObj2XML; | |||
import embedding.model.ProjectMember; | |||
@@ -50,7 +52,7 @@ import embedding.model.ProjectTeam; | |||
/** | |||
* Example for the intermediate format that demonstrates the concatenation of two documents | |||
* renderered to the intermediate format. A single PDF file is generated from the two intermediate | |||
* rendered to the intermediate format. A single PDF file is generated from the two intermediate | |||
* files. | |||
*/ | |||
public class ExampleConcat { | |||
@@ -76,7 +78,7 @@ public class ExampleConcat { | |||
* Converts an XSL-FO document to an intermediate file. | |||
* @param src the source file | |||
* @param xslt the stylesheet file | |||
* @param intermediate the target intermediate file (area tree XML) | |||
* @param intermediate the target intermediate file | |||
* @throws IOException In case of an I/O problem | |||
* @throws FOPException In case of a FOP problem | |||
* @throws TransformerException In case of a XSL transformation problem | |||
@@ -87,25 +89,26 @@ public class ExampleConcat { | |||
//Create a user agent | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//Create an instance of the target renderer so the XMLRenderer can use its font setup | |||
Renderer targetRenderer = userAgent.getRendererFactory().createRenderer( | |||
userAgent, MimeConstants.MIME_PDF); | |||
//Create an instance of the target document handler so the IFSerializer | |||
//can use its font setup | |||
IFDocumentHandler targetHandler = userAgent.getRendererFactory().createDocumentHandler( | |||
userAgent, MimeConstants.MIME_PDF + ";mode=painter"); | |||
//Create the XMLRenderer to create the intermediate format (area tree XML) | |||
XMLRenderer xmlRenderer = new XMLRenderer(); | |||
xmlRenderer.setUserAgent(userAgent); | |||
//Create the IFSerializer to write the intermediate format | |||
IFSerializer ifSerializer = new IFSerializer(); | |||
ifSerializer.setContext(new IFContext(userAgent)); | |||
//Tell the XMLRenderer to mimic the target renderer | |||
xmlRenderer.mimicRenderer(targetRenderer); | |||
//Tell the IFSerializer to mimic the target format | |||
ifSerializer.mimicDocumentHandler(targetHandler); | |||
//Make sure the prepared XMLRenderer is used | |||
userAgent.setRendererOverride(xmlRenderer); | |||
//Make sure the prepared document handler is used | |||
userAgent.setDocumentHandlerOverride(ifSerializer); | |||
// Setup output | |||
OutputStream out = new java.io.FileOutputStream(intermediate); | |||
out = new java.io.BufferedOutputStream(out); | |||
try { | |||
// Construct fop (the MIME type here is unimportant due to the override | |||
// Construct FOP (the MIME type here is unimportant due to the override | |||
// on the user agent) | |||
Fop fop = fopFactory.newFop(null, userAgent, out); | |||
@@ -130,35 +133,41 @@ public class ExampleConcat { | |||
/** | |||
* Concatenates an array of intermediate files to a single PDF file. | |||
* @param files the array of intermediate files (area tree XML) | |||
* @param files the array of intermediate files | |||
* @param pdffile the target PDF file | |||
* @throws IOException In case of an I/O problem | |||
* @throws TransformerException In case of a XSL transformation problem | |||
* @throws SAXException In case of an XML-related problem | |||
* @throws IFException if there was an IF-related error while creating the output file | |||
*/ | |||
public void concatToPDF(File[] files, File pdffile) | |||
throws IOException, TransformerException, SAXException { | |||
throws IOException, TransformerException, SAXException, IFException { | |||
// Setup output | |||
OutputStream out = new java.io.FileOutputStream(pdffile); | |||
out = new java.io.BufferedOutputStream(out); | |||
try { | |||
//Setup fonts and user agent | |||
FontInfo fontInfo = new FontInfo(); | |||
//Setup user agent | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//Construct the AreaTreeModel that will received the individual pages | |||
AreaTreeModel treeModel = new RenderPagesModel(userAgent, | |||
MimeConstants.MIME_PDF, fontInfo, out); | |||
//Setup target handler | |||
String mime = MimeConstants.MIME_PDF + ";mode=painter"; | |||
IFDocumentHandler targetHandler = fopFactory.getRendererFactory().createDocumentHandler( | |||
userAgent, mime); | |||
//Setup fonts | |||
IFUtil.setupFonts(targetHandler); | |||
targetHandler.setResult(new StreamResult(pdffile)); | |||
IFConcatenator concatenator = new IFConcatenator(targetHandler, null); | |||
//Iterate over all intermediate files | |||
AreaTreeParser parser = new AreaTreeParser(); | |||
for (int i = 0; i < files.length; i++) { | |||
Source src = new StreamSource(files[i]); | |||
parser.parse(src, treeModel, userAgent); | |||
concatenator.appendDocument(src); | |||
} | |||
//Signal the end of the processing. The renderer can finalize the target document. | |||
treeModel.endDocument(); | |||
//Signal the end of the processing so the target file can be finalized properly. | |||
concatenator.finish(); | |||
} finally { | |||
out.close(); | |||
} | |||
@@ -170,7 +179,7 @@ public class ExampleConcat { | |||
*/ | |||
public static void main(String[] args) { | |||
try { | |||
System.out.println("FOP ExampleConcat\n"); | |||
System.out.println("FOP ExampleConcat (for the Intermediate Format)\n"); | |||
//Setup directories | |||
File baseDir = new File("."); | |||
@@ -180,9 +189,9 @@ public class ExampleConcat { | |||
//Setup output file | |||
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl"); | |||
File[] files = new File[] { | |||
new File(outDir, "team1.at.xml"), | |||
new File(outDir, "team2.at.xml")}; | |||
File pdffile = new File(outDir, "ResultConcat.pdf"); | |||
new File(outDir, "team1.if.xml"), | |||
new File(outDir, "team2.if.xml")}; | |||
File pdffile = new File(outDir, "ResultIFConcat.pdf"); | |||
for (int i = 0; i < files.length; i++) { | |||
System.out.println("Intermediate file " + (i + 1) + ": " | |||
+ files[i].getCanonicalPath()); |
@@ -28,16 +28,18 @@ import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
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.xml.sax.SAXException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.area.AreaTreeModel; | |||
import org.apache.fop.area.AreaTreeParser; | |||
import org.apache.fop.area.RenderPagesModel; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.xml.sax.SAXException; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFException; | |||
import org.apache.fop.render.intermediate.IFParser; | |||
import org.apache.fop.render.intermediate.IFUtil; | |||
import embedding.ExampleObj2XML; | |||
import embedding.model.ProjectTeam; | |||
@@ -53,30 +55,35 @@ public class ExampleStamp { | |||
/** | |||
* Stamps an intermediate file and renders it to a PDF file. | |||
* @param atfile the intermediate file (area tree XML) | |||
* @param iffile the intermediate file (area tree XML) | |||
* @param stampSheet the stylesheet that does the stamping | |||
* @param pdffile the target PDF file | |||
* @throws IOException In case of an I/O problem | |||
* @throws TransformerException In case of a XSL transformation problem | |||
* @throws SAXException In case of an XML-related problem | |||
* @throws IFException if there was an IF-related error while creating the output file | |||
*/ | |||
public void stampToPDF(File atfile, File stampSheet, File pdffile) | |||
throws IOException, TransformerException, SAXException { | |||
public void stampToPDF(File iffile, File stampSheet, File pdffile) | |||
throws IOException, TransformerException, SAXException, IFException { | |||
// Setup output | |||
OutputStream out = new java.io.FileOutputStream(pdffile); | |||
out = new java.io.BufferedOutputStream(out); | |||
try { | |||
//Setup fonts and user agent | |||
FontInfo fontInfo = new FontInfo(); | |||
//user agent | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//Construct the AreaTreeModel that will received the individual pages | |||
AreaTreeModel treeModel = new RenderPagesModel(userAgent, | |||
MimeConstants.MIME_PDF, fontInfo, out); | |||
//Setup target handler | |||
String mime = MimeConstants.MIME_PDF + ";mode=painter"; | |||
IFDocumentHandler targetHandler = fopFactory.getRendererFactory().createDocumentHandler( | |||
userAgent, mime); | |||
//Iterate over all intermediate files | |||
AreaTreeParser parser = new AreaTreeParser(); | |||
Source src = new StreamSource(atfile); | |||
//Setup fonts | |||
IFUtil.setupFonts(targetHandler); | |||
targetHandler.setResult(new StreamResult(pdffile)); | |||
IFParser parser = new IFParser(); | |||
Source src = new StreamSource(iffile); | |||
Source xslt = new StreamSource(stampSheet); | |||
//Setup Transformer for XSLT processing | |||
@@ -84,13 +91,10 @@ public class ExampleStamp { | |||
Transformer transformer = tFactory.newTransformer(xslt); | |||
//Send XSLT result to AreaTreeParser | |||
SAXResult res = new SAXResult(parser.getContentHandler(treeModel, userAgent)); | |||
SAXResult res = new SAXResult(parser.getContentHandler(targetHandler, userAgent)); | |||
//Start XSLT transformation and area tree parsing | |||
transformer.transform(src, res); | |||
//Signal the end of the processing. The renderer can finalize the target document. | |||
treeModel.endDocument(); | |||
} finally { | |||
out.close(); | |||
} | |||
@@ -102,7 +106,7 @@ public class ExampleStamp { | |||
*/ | |||
public static void main(String[] args) { | |||
try { | |||
System.out.println("FOP ExampleConcat\n"); | |||
System.out.println("FOP ExampleConcat (for the Intermediate Format)\n"); | |||
//Setup directories | |||
File baseDir = new File("."); | |||
@@ -111,10 +115,10 @@ public class ExampleStamp { | |||
//Setup output file | |||
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl"); | |||
File atfile = new File(outDir, "team.at.xml"); | |||
File stampxsltfile = new File(baseDir, "xml/xslt/atstamp.xsl"); | |||
File pdffile = new File(outDir, "ResultStamped.pdf"); | |||
System.out.println("Intermediate file : " + atfile.getCanonicalPath()); | |||
File iffile = new File(outDir, "team.if.xml"); | |||
File stampxsltfile = new File(baseDir, "xml/xslt/ifstamp.xsl"); | |||
File pdffile = new File(outDir, "ResultIFStamped.pdf"); | |||
System.out.println("Intermediate file : " + iffile.getCanonicalPath()); | |||
System.out.println("Stamp XSLT: " + stampxsltfile.getCanonicalPath()); | |||
System.out.println("PDF Output File: " + pdffile.getCanonicalPath()); | |||
System.out.println(); | |||
@@ -125,11 +129,11 @@ public class ExampleStamp { | |||
ExampleConcat concatapp = new ExampleConcat(); | |||
concatapp.convertToIntermediate( | |||
team1.getSourceForProjectTeam(), | |||
new StreamSource(xsltfile), atfile); | |||
new StreamSource(xsltfile), iffile); | |||
//Stamp document and produce a PDF from the intermediate format | |||
ExampleStamp app = new ExampleStamp(); | |||
app.stampToPDF(atfile, stampxsltfile, pdffile); | |||
app.stampToPDF(iffile, stampxsltfile, pdffile); | |||
System.out.println("Success!"); | |||
@@ -0,0 +1,49 @@ | |||
<?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$ --> | |||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | |||
xmlns:if="http://xmlgraphics.apache.org/fop/intermediate"> | |||
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/> | |||
<!-- ========================= --> | |||
<!-- stamping... --> | |||
<!-- ========================= --> | |||
<xsl:template match="if:content"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*"/> | |||
<!-- Stamp a big "SPECIMEN" text over the whole page using an area tree fragment inserted at the right place... --> | |||
<if:g transform="translate(100000, 750000) rotate(-55)"> | |||
<if:font family="sans-serif" style="normal" weight="400" variant="normal" size="160000" | |||
color="#dfdfdf"/> | |||
<if:text xml:space="preserve" x="0" y="0">SPECIMEN</if:text> | |||
</if:g> | |||
<!-- Note: The free transformation above will not work with AFP output. In such a case, | |||
using an embedded SVG graphic is better. --> | |||
<xsl:apply-templates select="child::*"/> | |||
</xsl:copy> | |||
</xsl:template> | |||
<!-- ========================= --> | |||
<!-- identity transformation --> | |||
<!-- ========================= --> | |||
<xsl:template match="@*|node()"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*|node()"/> | |||
</xsl:copy> | |||
</xsl:template> | |||
</xsl:stylesheet> |
@@ -22,6 +22,7 @@ package org.apache.fop.plan; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import javax.xml.transform.ErrorListener; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
@@ -43,6 +44,7 @@ import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; | |||
import org.apache.xmlgraphics.image.loader.util.ImageUtil; | |||
import org.apache.fop.util.DefaultErrorListener; | |||
import org.apache.fop.util.UnclosableInputStream; | |||
/** | |||
@@ -71,21 +73,16 @@ public class PreloaderPlan extends AbstractImagePreloader { | |||
InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src)); | |||
try { | |||
TransformerFactory tFactory = TransformerFactory.newInstance(); | |||
Transformer transformer = tFactory.newTransformer(); | |||
Source source = new StreamSource(in); | |||
DOMResult res = new DOMResult(); | |||
transformer.transform(source, res); | |||
//Have to render the plan to know its size | |||
PlanRenderer pr = new PlanRenderer(); | |||
Document planDoc = (Document)res.getNode(); | |||
Document planDoc = getDocument(in); | |||
Element rootEl = planDoc.getDocumentElement(); | |||
if (!PlanElementMapping.NAMESPACE.equals(rootEl.getNamespaceURI())) { | |||
if (!PlanElementMapping.NAMESPACE.equals( | |||
rootEl.getNamespaceURI())) { | |||
in.reset(); | |||
return null; | |||
} | |||
//Have to render the plan to know its size | |||
PlanRenderer pr = new PlanRenderer(); | |||
Document svgDoc = pr.createSVGDocument(planDoc); | |||
float width = pr.getWidth(); | |||
float height = pr.getHeight(); | |||
@@ -119,4 +116,19 @@ public class PreloaderPlan extends AbstractImagePreloader { | |||
} | |||
} | |||
private Document getDocument(InputStream in) throws TransformerException { | |||
TransformerFactory tFactory = TransformerFactory.newInstance(); | |||
//Custom error listener to minimize output to console | |||
ErrorListener errorListener = new DefaultErrorListener(log); | |||
tFactory.setErrorListener(errorListener); | |||
Transformer transformer = tFactory.newTransformer(); | |||
transformer.setErrorListener(errorListener); | |||
Source source = new StreamSource(in); | |||
DOMResult res = new DOMResult(); | |||
transformer.transform(source, res); | |||
Document doc = (Document)res.getNode(); | |||
return doc; | |||
} | |||
} |
@@ -29,6 +29,7 @@ import org.w3c.dom.Document; | |||
import org.w3c.dom.Element; | |||
import org.apache.batik.dom.svg.SVGDOMImplementation; | |||
import org.apache.fop.svg.SVGUtilities; | |||
/** | |||
@@ -83,13 +84,15 @@ public class SimplePlanDrawer implements PlanDrawer { | |||
String title = ""; | |||
DOMImplementation impl = | |||
SVGDOMImplementation.getDOMImplementation(); | |||
DOMImplementation impl | |||
= SVGDOMImplementation.getDOMImplementation(); | |||
Document doc = impl.createDocument(SVG_NAMESPACE, "svg", null); | |||
Element svgRoot = doc.getDocumentElement(); | |||
svgRoot.setAttributeNS(null, "width", "" + width); | |||
svgRoot.setAttributeNS(null, "height", "" + height); | |||
svgRoot.setAttributeNS(null, "width", Float.toString(width)); | |||
svgRoot.setAttributeNS(null, "height", Float.toString(height)); | |||
svgRoot.setAttributeNS(null, "viewBox", | |||
"0 0 " + Float.toString(width) + " " + Float.toString(height)); | |||
svgRoot.setAttributeNS(null, "style", | |||
"font-size:" + 8 | |||
+ ";font-family:" | |||
@@ -99,8 +102,8 @@ public class SimplePlanDrawer implements PlanDrawer { | |||
java.awt.Font.PLAIN, (int)fontSize); | |||
if (bord) { | |||
Element border = | |||
SVGUtilities.createRect(doc, 0, 0, width, height); | |||
Element border | |||
= SVGUtilities.createRect(doc, 0, 0, width, height); | |||
border.setAttributeNS(null, "style", "stroke:black;fill:none"); | |||
svgRoot.appendChild(border); | |||
} |
@@ -24,16 +24,25 @@ | |||
</header> | |||
<body> | |||
<note> | |||
Please note that the intermediate format is an <strong>advanced feature</strong> and can be ignored by most | |||
users of Apache FOP. | |||
Please note that the intermediate formats described here are | |||
<strong>advanced features</strong> and can be ignored by most users of Apache FOP. | |||
</note> | |||
<section id="introduction"> | |||
<title>Introduction</title> | |||
<p> | |||
The intermediate format (IF) is a proprietary XML format that represents the area tree | |||
generated by the layout engine. The area tree is conceptually defined in the | |||
Apache FOP now provides two different so-called intermediate formats. The first one | |||
(let's call it the area tree XML format) is basically a 1:1 XML representation of FOP's | |||
area tree as generated by the layout engine. The area tree is conceptually defined in the | |||
<a href="http://www.w3.org/TR/2001/REC-xsl-20011015/slice1.html#section-N742-Formatting">XSL-FO specification in chapter 1.1.2</a>. | |||
The IF can be generated through the area tree XML Renderer (the XMLRenderer). | |||
Even though the area tree is mentioned in the XSL-FO specification, this part is not | |||
standardized. Therefore, the area tree XML format is a FOP-proprietary XML file format. | |||
The area tree XML can be generated through the area tree XML Renderer (the XMLRenderer). | |||
</p> | |||
<p> | |||
The second intermediate format (which we shall name exactly like this: the intermediate | |||
format) | |||
is a recent addition which tries to meet a slightly different set of goals. It is highly | |||
optimized for speed. | |||
</p> | |||
<p> | |||
The intermediate format can be used to generate intermediate documents that are modified | |||
@@ -43,31 +52,74 @@ | |||
to a single output file. | |||
</p> | |||
</section> | |||
<section id="which-if"> | |||
<title>Which Intermediate Format to choose?</title> | |||
<p> | |||
Both formats have their use cases, so the choice you will make will depend on your | |||
particular situation. Here is a list of strengths and use cases for both formats: | |||
</p> | |||
<section id="strengths-at"> | |||
<title>Area Tree XML (AT XML)</title> | |||
<ul> | |||
<li>1:1 representation of FOP's area tree in XML.</li> | |||
<li>Contains more structure information than the new intermediate format.</li> | |||
<li>Used in FOP's layout engine test suite for regression testing.</li> | |||
</ul> | |||
</section> | |||
<section id="strengths-if"> | |||
<title>Intermediate Format (IF)</title> | |||
<ul> | |||
<li>Highly optimized for speed.</li> | |||
<li>Smaller XML files.</li> | |||
<li>Easier to post-process.</li> | |||
<li>XML Schema is available.</li> | |||
<li> | |||
Recommended for use cases where documents are formatted concurrently and later | |||
concatenated to a single print job. | |||
</li> | |||
</ul> | |||
</section> | |||
<p> | |||
More technical information about the two formats can be found on the | |||
<a href="http://wiki.apache.org/xmlgraphics-fop/AreaTreeIntermediateXml/NewDesign">FOP Wiki</a>. | |||
</p> | |||
</section> | |||
<section id="architecture"> | |||
<title>Architectural Overview</title> | |||
<figure src="images/if-architecture-overview.png" | |||
alt="Diagram with an architectural overview over the intermediate formats"/> | |||
</section> | |||
<section id="usage"> | |||
<title>Usage of the Intermediate Format</title> | |||
<title>Usage of the Area Tree XML format (AT XML)</title> | |||
<p> | |||
As already mentioned, the area tree XML format is generated by using the | |||
<strong>XMLRenderer</strong> (MIME type: <strong>application/X-fop-areatree</strong>). | |||
So, you basically set the right MIME type for the output format and process your FO files | |||
as if you would create a PDF file. | |||
</p> | |||
<p> | |||
As already mentioned, the IF is generated by using the <strong>XMLRenderer</strong> (MIME type: | |||
<strong>application/X-fop-areatree</strong>). So, you basically set the right MIME type for | |||
the output format and process your FO files as if you would create a PDF file. However, there | |||
is an important detail to consider: The various Renderers don't all use the same font sources. | |||
To be able to create the right area tree for the ultimate output file, you need to create | |||
the IF file using the right font setup. This is achieved by telling the XMLRenderer to mimic | |||
another renderer. This is done by calling the XMLRenderer's mimicRenderer() method with an | |||
instance of the ultimate target renderer as the single parameter. This has a consequence: An | |||
IF file rendered with the Java2DRenderer may not look as expected when it was actually generated | |||
for the PDF renderer. For renderers that use the same font setup, this restriction does not | |||
apply (PDF and PS, for example). Generating the intermediate format file is the first step. | |||
However, there is an important detail to consider: The | |||
various Renderers don't all use the same font sources. To be able to create the right | |||
area tree for the ultimate output format, you need to create the area tree XML file using | |||
the right font setup. This is achieved by telling the XMLRenderer to mimic another | |||
renderer. This is done by calling the XMLRenderer's mimicRenderer() method with an | |||
instance of the ultimate target renderer as the single parameter. This has a consequence: | |||
An area tree XML file rendered with the Java2DRenderer may not look as expected when it | |||
was actually generated for the PDF renderer. For renderers that use the same font setup, | |||
this restriction does not apply (PDF and PS, for example). Generating the area tree XML | |||
format file is the first step. | |||
</p> | |||
<p> | |||
The second step is to reparse the IF file using the <strong>AreaTreeParser</strong> which is | |||
found in the org.apache.fop.area package. The pages retrieved from the IF file are added to an | |||
AreaTreeModel instance from where they are normally rendered using one of the available Renderer | |||
implementations. You can find examples for the IF processing in the | |||
<a href="http://svn.apache.org/viewcvs.cgi/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/"><code>examples/embedding</code></a> | |||
directory in the FOP distribution | |||
The second step is to reparse the file using the <strong>AreaTreeParser</strong> which is | |||
found in the org.apache.fop.area package. The pages retrieved from the area tree XML file | |||
are added to an AreaTreeModel instance from where they are normally rendered using one of | |||
the available Renderer implementations. You can find examples for the area tree XML | |||
processing in the | |||
<a href="http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/"><code>examples/embedding</code></a> | |||
directory in the FOP distribution. | |||
</p> | |||
<p> | |||
The basic pattern to parse the IF format looks like this: | |||
The basic pattern to parse the area tree XML format looks like this: | |||
</p> | |||
<source><![CDATA[ | |||
FopFactory fopFactory = FopFactory.newInstance(); | |||
@@ -84,7 +136,7 @@ try { | |||
AreaTreeModel treeModel = new RenderPagesModel(userAgent, | |||
MimeConstants.MIME_PDF, fontInfo, out); | |||
//Parse the IF file into the area tree | |||
//Parse the area tree file into the area tree | |||
AreaTreeParser parser = new AreaTreeParser(); | |||
Source src = new StreamSource(myIFFile); | |||
parser.parse(src, treeModel, userAgent); | |||
@@ -95,7 +147,7 @@ try { | |||
out.close(); | |||
}]]></source> | |||
<p> | |||
This example simply reads an IF file and renders it to a PDF file. Please note, that in normal | |||
This example simply reads an area tree file and renders it to a PDF file. Please note, that in normal | |||
FOP operation you're shielded from having to instantiate the FontInfo object yourself. This | |||
is normally a task of the AreaTreeHandler which is not present in this scenario. The same | |||
applies to the AreaTreeModel instance, in this case an instance of a subclass called | |||
@@ -105,7 +157,7 @@ try { | |||
is now finished. | |||
</p> | |||
<p> | |||
The intermediate format can also be used from the <a href="running.html#standalone-start">command-line</a> | |||
The area tree XML format can also be used from the <a href="running.html#standalone-start">command-line</a> | |||
by using the "-atin" parameter for specifying the area tree XML as input file. You can also | |||
specify a "mimic renderer" by inserting a MIME type between "-at" and the output file. | |||
</p> | |||
@@ -113,8 +165,8 @@ try { | |||
<title>Concatenating Documents</title> | |||
<p> | |||
This initial example is obviously not very useful. It would be faster to create the PDF file | |||
directly. As the <a href="http://svn.apache.org/repos/asf/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/ExampleConcat.java">ExampleConcat.java</a> | |||
example shows you can easily parse multiple IF files in a row and add the parsed pages to the | |||
directly. As the <a href="http://svn.apache.org/repos/asf/xmlgraphics/fop/trunk/examples/embedding/java/embedding/atxml/ExampleConcat.java">ExampleConcat.java</a> | |||
example shows you can easily parse multiple area tree files in a row and add the parsed pages to the | |||
same AreaTreeModel instance which essentially concatenates all the input document to one single | |||
output document. | |||
</p> | |||
@@ -122,18 +174,22 @@ try { | |||
<section id="modifying"> | |||
<title>Modifying Documents</title> | |||
<p> | |||
One of the most important use cases for the intermediate format is obviously modifying the area | |||
One of the most important use cases for this format is obviously modifying the area | |||
tree XML before finally rendering it to the target format. You can easily use XSLT to process | |||
the IF file according to your needs. Please note, that we will currently not formally describe | |||
the intermediate format. You need to have a good understanding its structure so you don't | |||
the AT XML file according to your needs. Please note, that we will currently not formally describe | |||
the area tree XML format. You need to have a good understanding its structure so you don't | |||
create any non-parseable files. We may add an XML Schema and more detailed documentation at a | |||
later time. You're invited to help us with that. | |||
</p> | |||
<note> | |||
The area tree XML format is sensitive to changes in whitespace. If you're not careful, | |||
the modified file may not render correctly. | |||
</note> | |||
</section> | |||
<section id="advanced"> | |||
<title>Advanced Use</title> | |||
<p> | |||
The generation of the intermediate format as well as it parsing process has been designed to allow | |||
The generation of the area tree format as well as it parsing process has been designed to allow | |||
for maximum flexibility and optimization. Please note that you can call <code>setTransformerHandler()</code> on | |||
XMLRenderer to give the XMLRenderer your own TransformerHandler instance in case you would like to | |||
do custom serialization (to a W3C DOM, for example) and/or to directly modify the area tree using | |||
@@ -142,5 +198,134 @@ try { | |||
</p> | |||
</section> | |||
</section> | |||
<section id="usage-if"> | |||
<title>Usage of the Intermediate Format (IF)</title> | |||
<p> | |||
The Intermediate Format (IF) is generated by the <strong>IFSerializer</strong> | |||
(MIME type: <strong>application/X-fop-intermediate-format</strong>). | |||
So, you basically set the right MIME type for the output format and process your FO files | |||
as if you would create a PDF file. | |||
</p> | |||
<p> | |||
The IFSerializer is an implementation of the <strong>IFDocumentHandler</strong> and | |||
<strong>IFPainter</strong> interfaces. The <strong>IFRenderer</strong> class is responsible | |||
for converting FOP's area tree into calls against these two interfaces. | |||
</p> | |||
<ul> | |||
<li> | |||
IFDocumentHandler: This interface is used on the document-level and defines the | |||
overall structure of the Intermediate Format. | |||
</li> | |||
<li> | |||
IFPainter: This interface is used to generate graphical page content like text, images | |||
and borders. | |||
</li> | |||
</ul> | |||
<p> | |||
As with the AT XML, there is an important detail to consider: The various output | |||
implementations don't all use the same font sources. To be able | |||
to create the right IF for the ultimate output file, you need to create the IF file using | |||
the right font setup. This is achieved by telling the IFRenderer (responsible for | |||
converting the area tree into calls to the IFDocumentHandler and IFPainter interfaces) | |||
to mimic another renderer. This is done by calling the IFSerializer's | |||
mimicDocumentHandler() method with an instance of the ultimate target document handler | |||
as the single parameter. This has a consequence: An IF file rendered with the | |||
Java2DDocumentHandler may not look as expected when it was actually generated for the PDF | |||
implementation. For implementations that use the same font setup, | |||
this restriction does not apply (PDF and PS, for example). Generating the Intermediate | |||
Format file is the first step. | |||
</p> | |||
<p> | |||
The second step is to reparse the file using the <strong>IFParser</strong> which is | |||
found in the org.apache.fop.render.intermediate package. The IFParser simply takes an | |||
IFDocumentHandler instance against which it generates the appropriate calls. The IFParser | |||
is implemented as a SAX ContentHandler so you're free to choose the method for | |||
post-processing the IF file(s). You can use XSLT or write SAX- or DOM-based code to | |||
manipulate the contents. You can find examples for the Intermediate Format | |||
processing in the | |||
<a href="http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/"><code>examples/embedding</code></a> | |||
directory in the FOP distribution. | |||
</p> | |||
<p> | |||
The basic pattern to parse the intermediate format looks like this: | |||
</p> | |||
<source><![CDATA[ | |||
FopFactory fopFactory = FopFactory.newInstance(); | |||
// Setup output | |||
OutputStream out = new java.io.FileOutputStream(pdffile); | |||
out = new java.io.BufferedOutputStream(out); | |||
try { | |||
//Setup user agent | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
//Create IFDocumentHandler instance | |||
IFDocumentHandler targetHandler; | |||
String mime = MimeConstants.MIME_PDF; | |||
targetHandler = fopFactory.getRendererFactory().createDocumentHandler( | |||
userAgent, mime); | |||
//Setup fonts | |||
IFUtil.setupFonts(targetHandler); | |||
//Tell the target handler where to write the PDF to | |||
targetHandler.setResult(new StreamResult(pdffile)); | |||
//Parse the IF file | |||
IFParser parser = new IFParser(); | |||
Source src = new StreamSource(myIFFile); | |||
parser.parse(src, targetHandler, userAgent); | |||
} finally { | |||
out.close(); | |||
}]]></source> | |||
<p> | |||
This example simply reads an intermediate file and renders it to a PDF file. Here | |||
IFParser.parse() is used, but you can also just get a SAX ContentHandler by using the | |||
IFParser.getContentHandler() method. | |||
</p> | |||
<section id="concat-if"> | |||
<title>Concatenating Documents</title> | |||
<p> | |||
This initial example is obviously not very useful. It would be faster to create the PDF file | |||
directly (without the intermediate step). As the | |||
<a href="http://svn.apache.org/repos/asf/xmlgraphics/fop/trunk/examples/embedding/java/embedding/intermediate/ExampleConcat.java">ExampleConcat.java</a> | |||
example shows you can easily parse multiple intermediate files in a row and use the | |||
IFConcatenator class to concatenate page sequences from multiple source files to a single | |||
output file. This particular example does the concatenation on the level of the | |||
IFDocumentHandler interface. You could also do this in XSLT or using SAX on the XML level. | |||
Whatever suits your process best. | |||
</p> | |||
</section> | |||
<section id="modifying-if"> | |||
<title>Modifying Documents</title> | |||
<p> | |||
One of the most important use cases for this format is obviously modifying the | |||
intermediate format before finally rendering it to the target format. You can easily use | |||
XSLT to process the IF file according to your needs. | |||
</p> | |||
<p> | |||
There is an XML Schema (located under | |||
<a href="http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/documentation/intermediate-format-ng/">src/documentation/intermediate-format-ng</a>) | |||
that helps you verify that your modified content is correct. | |||
</p> | |||
<p> | |||
For certain output formats there's a caveat: Formats like AFP and PCL do not support | |||
arbitrary transformations on the IF's "viewport" and "g" elements. Possible are | |||
only rotations in 90 degree steps and translations. | |||
</p> | |||
</section> | |||
<section id="advanced-if"> | |||
<title>Advanced Use</title> | |||
<p> | |||
The generation of the intermediate format as well as it parsing process has been | |||
designed to allow for maximum flexibility and optimization. So rather than just passing | |||
in a StreamResult to IFSerializer's setResult() method, you can also use a SAXResult | |||
or a DOMResult. And as you've already seen , the IFParser on the other side allows you | |||
to retrieve a ContentHandler instance where you can manually send SAX events to | |||
start the parsing process (see <code>getContentHandler()</code>). | |||
</p> | |||
</section> | |||
</section> | |||
</body> | |||
</document> |
@@ -19,7 +19,8 @@ | |||
<document xmlns="http://xmlgraphics.apache.org/fop/intermediate" | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://xmlgraphics.apache.org/fop/intermediate fop-intermediate-format-ng.xsd" | |||
xmlns:xlink="http://www.w3.org/1999/xlink"> | |||
xmlns:xlink="http://www.w3.org/1999/xlink" | |||
xmlns:nav="http://xmlgraphics.apache.org/fop/intermediate/document-navigation"> | |||
<header> | |||
<x:xmpmeta xmlns:x="adobe:ns:meta/"> | |||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> | |||
@@ -44,7 +45,7 @@ | |||
</header> | |||
<page-sequence id="ps1"> | |||
<page index="1" name="1"> | |||
<page index="0" name="1" width="595275" height="841889"> | |||
<page-header> | |||
<ps:ps-setup-code xmlns:ps="apache:fop:extensions:postscript">%FOPTestPSSetupCode: General | |||
setup code here!</ps:ps-setup-code> | |||
@@ -52,20 +53,21 @@ | |||
<content> | |||
<!-- Note: this is not actual content that is supposed to make any sense. | |||
It is merely to give you an idea what the content can look like. --> | |||
<box transform="translate(5000, 6000)" width="18000" height="10000"> | |||
<viewport transform="translate(5000, 6000)" width="18000" height="10000"> | |||
<font family="Helvetica" style="normal" weight="400" variant="normal" size="12000" | |||
color="black"/> | |||
<text x="1233 1241 1247 1253 1264" y="803">Hello</text> | |||
<draw-rect x="1233" y="1200" width="20000" height="20000" fill="yellow" stroke="none"/> | |||
<box transform="translate(1233, 1200)" width="20000" height="20000" clip="true"> | |||
<text x="1233" y="803">Hello</text> | |||
<rect x="1233" y="1200" width="20000" height="20000" fill="yellow"/> | |||
<viewport transform="translate(1233, 1200)" width="20000" height="20000" clip-rect="0 0 20000 20000"> | |||
<image xlink:href="myimage.svg" x="0" y="0" width="20000" height="20000"/> | |||
</box> | |||
</box> | |||
</viewport> | |||
</viewport> | |||
</content> | |||
<page-trailer> | |||
<target x="1233" y="803" name="toc"/> | |||
<target x="1233" y="1200" name="chapter1"/> | |||
<nav:goto-xy id="toc" page-index="0" x="1233" y="803"/> | |||
<nav:goto-xy id="chapter1" page-index="0" x="1233" y="1200"/> | |||
</page-trailer> | |||
</page> | |||
</page-sequence> | |||
<trailer/> | |||
</document> |
@@ -20,15 +20,26 @@ | |||
targetNamespace="http://xmlgraphics.apache.org/fop/intermediate" | |||
xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate"> | |||
<xs:include schemaLocation="fop-intermediate-format-ng-datatypes.xsd"/> | |||
<xs:import namespace="http://www.w3.org/XML/1998/namespace" | |||
schemaLocation="http://www.w3.org/2001/xml.xsd"/> | |||
<xs:complexType name="contentType"> | |||
<xs:choice maxOccurs="unbounded" minOccurs="0"> | |||
<xs:element name="box"> | |||
<xs:element name="viewport"> | |||
<xs:complexType> | |||
<xs:complexContent> | |||
<xs:extension base="mf:contentType"> | |||
<xs:attribute name="transform" type="xs:string"/> | |||
<xs:attributeGroup ref="mf:sizeAtts"/> | |||
<xs:attribute name="clip" type="xs:boolean" default="false"/> | |||
<xs:attribute name="clip-rect" type="mf:rectangleType"/> | |||
</xs:extension> | |||
</xs:complexContent> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="g"> | |||
<xs:complexType> | |||
<xs:complexContent> | |||
<xs:extension base="mf:contentType"> | |||
<xs:attribute name="transform" type="xs:string"/> | |||
</xs:extension> | |||
</xs:complexContent> | |||
</xs:complexType> | |||
@@ -40,7 +51,7 @@ | |||
<xs:attribute name="variant" type="mf:fontVariantType"/> | |||
<xs:attribute name="weight" type="mf:fontWeightType"/> | |||
<xs:attribute name="stretch" type="mf:fontStretchType"/> | |||
<xs:attribute name="size" type="xs:positiveInteger"/> | |||
<xs:attribute name="size" type="mf:lengthType"/> | |||
<xs:attribute name="color" type="mf:colorType"/> | |||
</xs:complexType> | |||
</xs:element> | |||
@@ -48,50 +59,49 @@ | |||
<xs:complexType> | |||
<xs:simpleContent> | |||
<xs:extension base="xs:string"> | |||
<xs:attribute name="x" use="required"> | |||
<xs:simpleType> | |||
<xs:list itemType="xs:integer"/> | |||
</xs:simpleType> | |||
</xs:attribute> | |||
<xs:attribute name="y" use="required"> | |||
<xs:attribute name="x" use="required" type="mf:lengthType"/> | |||
<xs:attribute name="y" use="required" type="mf:lengthType"/> | |||
<xs:attribute name="letter-spacing" type="mf:lengthType"/> | |||
<xs:attribute name="word-spacing" type="mf:lengthType"/> | |||
<xs:attribute name="dx"> | |||
<xs:simpleType> | |||
<xs:list itemType="xs:integer"/> | |||
<xs:list itemType="mf:lengthType"/> | |||
</xs:simpleType> | |||
</xs:attribute> | |||
<xs:attribute ref="xml:space"/> | |||
</xs:extension> | |||
</xs:simpleContent> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="clip-path"> | |||
<xs:complexType> | |||
<xs:attribute name="d" type="mf:pathDataType" use="required"/> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="draw-path"> | |||
<xs:element name="clip-rect"> | |||
<xs:complexType> | |||
<xs:attribute name="d" type="mf:pathDataType" use="required"/> | |||
<xs:attributeGroup ref="mf:fillStrokeAtts"/> | |||
<xs:attributeGroup ref="mf:rectAtts"/> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="clip-rect"> | |||
<xs:element name="rect"> | |||
<xs:complexType> | |||
<xs:attributeGroup ref="mf:rectAtts"/> | |||
<xs:attributeGroup ref="mf:fillAtts"/> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="draw-rect"> | |||
<xs:element name="line"> | |||
<xs:complexType> | |||
<xs:attributeGroup ref="mf:rectAtts"/> | |||
<xs:attributeGroup ref="mf:fillStrokeAtts"/> | |||
<xs:attribute name="x1" use="required" type="mf:lengthType"/> | |||
<xs:attribute name="y1" use="required" type="mf:lengthType"/> | |||
<xs:attribute name="x2" use="required" type="mf:lengthType"/> | |||
<xs:attribute name="y2" use="required" type="mf:lengthType"/> | |||
<xs:attribute name="color" use="required" type="mf:colorType"/> | |||
<xs:attribute name="stroke-width" use="required" type="mf:lengthType"/> | |||
<xs:attribute name="style" use="required" type="mf:ruleStyle"/> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="draw-border-line"> | |||
<xs:element name="border-rect"> | |||
<xs:complexType> | |||
<xs:attribute name="x1" type="xs:integer" use="required"/> | |||
<xs:attribute name="y1" type="xs:integer" use="required"/> | |||
<xs:attribute name="x2" type="xs:integer" use="required"/> | |||
<xs:attribute name="y2" type="xs:integer" use="required"/> | |||
<xs:attribute name="width" type="xs:integer" use="required"/> | |||
<xs:attribute name="style" type="mf:borderStyle" default="solid"/> | |||
<xs:attributeGroup ref="mf:rectAtts"/> | |||
<xs:attribute name="start" type="mf:borderDef"/> | |||
<xs:attribute name="end" type="mf:borderDef"/> | |||
<xs:attribute name="before" type="mf:borderDef"/> | |||
<xs:attribute name="after" type="mf:borderDef"/> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="image"> | |||
@@ -100,7 +110,7 @@ | |||
<xs:extension base="xs:anyType"> | |||
<!-- Either use element content with any namespace or xlink:href --> | |||
<xs:attributeGroup ref="mf:rectAtts"/> | |||
<xs:anyAttribute namespace="http://www.w3.org/1999/xlink" processContents="skip"/> | |||
<xs:attributeGroup ref="mf:foreignAtts"/> | |||
</xs:extension> | |||
</xs:complexContent> | |||
</xs:complexType> | |||
@@ -108,16 +118,25 @@ | |||
</xs:choice> | |||
</xs:complexType> | |||
<xs:attributeGroup name="sizeAtts"> | |||
<xs:attribute name="width" type="xs:positiveInteger" use="required"/> | |||
<xs:attribute name="height" type="xs:positiveInteger" use="required"/> | |||
<xs:attribute name="width" type="mf:lengthType" use="required"/> | |||
<xs:attribute name="height" type="mf:lengthType" use="required"/> | |||
</xs:attributeGroup> | |||
<xs:attributeGroup name="posAtts"> | |||
<xs:attribute name="x" type="mf:lengthType" default="0"/> | |||
<xs:attribute name="y" type="mf:lengthType" default="0"/> | |||
</xs:attributeGroup> | |||
<xs:attributeGroup name="rectAtts"> | |||
<xs:attribute name="x" type="xs:integer" default="0"/> | |||
<xs:attribute name="y" type="xs:integer" default="0"/> | |||
<xs:attributeGroup ref="mf:posAtts"/> | |||
<xs:attributeGroup ref="mf:sizeAtts"/> | |||
</xs:attributeGroup> | |||
<xs:attributeGroup name="fillStrokeAtts"> | |||
<xs:attributeGroup name="fillAtts"> | |||
<xs:attribute name="fill" type="xs:string" default="none"/> | |||
</xs:attributeGroup> | |||
<!--xs:attributeGroup name="fillStrokeAtts"> | |||
<xs:attribute name="fill" type="xs:string" default="none"/> | |||
<xs:attribute name="stroke" type="xs:string" default="none"/> | |||
</xs:attributeGroup--> | |||
<xs:attributeGroup name="foreignAtts"> | |||
<xs:anyAttribute namespace="##other" processContents="lax"/> | |||
</xs:attributeGroup> | |||
</xs:schema> |
@@ -22,8 +22,8 @@ | |||
<xs:simpleType name="colorType"> | |||
<xs:restriction base="xs:string"/> | |||
</xs:simpleType> | |||
<xs:simpleType name="pathDataType"> | |||
<xs:restriction base="xs:string"/> | |||
<xs:simpleType name="lengthType"> | |||
<xs:restriction base="xs:int"/> | |||
</xs:simpleType> | |||
<xs:simpleType name="fontStyleType"> | |||
<xs:restriction base="xs:string"> | |||
@@ -77,4 +77,30 @@ | |||
<xs:enumeration value="outset"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
<xs:simpleType name="ruleStyle"> | |||
<xs:restriction base="xs:string"> | |||
<xs:enumeration value="solid"/> | |||
<xs:enumeration value="dotted"/> | |||
<xs:enumeration value="dashed"/> | |||
<xs:enumeration value="double"/> | |||
<xs:enumeration value="groove"/> | |||
<xs:enumeration value="ridge"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
<xs:simpleType name="borderDef"> | |||
<xs:restriction base="xs:string"> | |||
<!-- TODO refine me: \w+ will not be good enough for CMYK color, for example | |||
<xs:pattern value="\((solid|dotted|dashed|double|groove|ridge|inset|outset),\w+,\d+(,collapse-(inner|outer))?"/> | |||
--> | |||
<xs:pattern value="\((solid|dotted|dashed|double|groove|ridge|inset|outset),.+)"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
<xs:simpleType name="lengthListType"> | |||
<xs:list itemType="mf:lengthType"/> | |||
</xs:simpleType> | |||
<xs:simpleType name="rectangleType"> | |||
<xs:restriction base="mf:lengthListType"> | |||
<xs:length value="4"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
</xs:schema> |
@@ -0,0 +1,124 @@ | |||
<?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$ --> | |||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" | |||
elementFormDefault="qualified" | |||
targetNamespace="http://xmlgraphics.apache.org/fop/intermediate/document-navigation" | |||
xmlns:nav="http://xmlgraphics.apache.org/fop/intermediate/document-navigation" | |||
xmlns:if="http://xmlgraphics.apache.org/fop/intermediate"> | |||
<xs:import schemaLocation="fop-intermediate-format-ng-datatypes.xsd" | |||
namespace="http://xmlgraphics.apache.org/fop/intermediate"/> | |||
<xs:element name="bookmark-tree"> | |||
<xs:complexType> | |||
<xs:sequence minOccurs="1" maxOccurs="unbounded"> | |||
<xs:element ref="nav:bookmark"/> | |||
</xs:sequence> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="bookmark"> | |||
<xs:complexType> | |||
<xs:complexContent> | |||
<xs:extension base="nav:actionType"> | |||
<xs:sequence> | |||
<xs:element ref="nav:bookmark" maxOccurs="unbounded" minOccurs="0"/> | |||
</xs:sequence> | |||
<xs:attribute name="title" type="xs:string"/> | |||
<xs:attribute name="starting-state"> | |||
<xs:simpleType> | |||
<xs:restriction base="xs:string"> | |||
<xs:enumeration value="show"/> | |||
<xs:enumeration value="hide"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
</xs:attribute> | |||
<!-- Not yet implemented: | |||
<xs:attribute name="color" type="if:colorType"/> | |||
<xs:attribute name="font-style"> | |||
<xs:simpleType> | |||
<xs:restriction base="xs:string"> | |||
<xs:enumeration value="normal"/> | |||
<xs:enumeration value="italic"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
</xs:attribute> | |||
<xs:attribute name="font-weight"> | |||
<xs:simpleType> | |||
<xs:restriction base="xs:string"> | |||
<xs:enumeration value="normal"/> | |||
<xs:enumeration value="bold"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
</xs:attribute> | |||
--> | |||
</xs:extension> | |||
</xs:complexContent> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="link"> | |||
<xs:complexType> | |||
<xs:complexContent> | |||
<xs:extension base="nav:actionType"> | |||
<xs:attribute name="rect" type="if:rectangleType"/> | |||
</xs:extension> | |||
</xs:complexContent> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:complexType name="actionType"> | |||
<xs:choice> | |||
<xs:element ref="nav:goto-uri"/> | |||
<xs:element ref="nav:goto-xy"/> | |||
</xs:choice> | |||
</xs:complexType> | |||
<xs:element name="goto-uri"> | |||
<xs:complexType> | |||
<xs:attributeGroup ref="nav:idAtts"/> | |||
<xs:attribute name="uri" type="xs:anyURI" use="required"/> | |||
<xs:attribute name="show-destination" use="optional" default="replace"> | |||
<xs:simpleType> | |||
<xs:restriction base="xs:string"> | |||
<xs:enumeration value="new"/> | |||
<xs:enumeration value="replace"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
</xs:attribute> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="goto-xy"> | |||
<xs:complexType> | |||
<xs:attributeGroup ref="nav:refDef"/> | |||
<xs:attribute name="page-index" type="xs:int"/> | |||
<xs:attributeGroup ref="nav:posAtts"/> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:attributeGroup name="posAtts"> | |||
<xs:attribute name="x" type="if:lengthType" default="0"/> | |||
<xs:attribute name="y" type="if:lengthType" default="0"/> | |||
</xs:attributeGroup> | |||
<xs:attributeGroup name="idAtts"> | |||
<xs:attribute name="id" type="xs:NCName"/> | |||
</xs:attributeGroup> | |||
<xs:attributeGroup name="refDef"> | |||
<xs:attributeGroup ref="nav:idAtts"/> | |||
<xs:attribute name="idref" type="xs:NCName"/> | |||
</xs:attributeGroup> | |||
</xs:schema> |
@@ -18,111 +18,73 @@ | |||
<!-- $Id$ --> | |||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" | |||
targetNamespace="http://xmlgraphics.apache.org/fop/intermediate" | |||
xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate"> | |||
xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate" | |||
xmlns:nav="http://xmlgraphics.apache.org/fop/intermediate/document-navigation"> | |||
<xs:import namespace="http://xmlgraphics.apache.org/fop/intermediate/document-navigation" | |||
schemaLocation="fop-intermediate-format-ng-nav.xsd"/> | |||
<xs:import namespace="adobe:ns:meta/" schemaLocation="xmp-metadata.xsd"/> | |||
<xs:import namespace="http://xmlgraphics.apache.org/fop/intermediate/document-navigation" | |||
schemaLocation="fop-intermediate-format-ng-nav.xsd"/> | |||
<xs:include schemaLocation="fop-intermediate-format-ng-datatypes.xsd"/> | |||
<xs:include schemaLocation="fop-intermediate-format-ng-content.xsd"/> | |||
<xs:element name="document"> | |||
<xs:complexType> | |||
<xs:sequence> | |||
<xs:element ref="mf:header"/> | |||
<xs:element ref="mf:page-sequence"/> | |||
<xs:element ref="mf:page-sequence" minOccurs="1" maxOccurs="unbounded"/> | |||
<xs:element ref="mf:trailer"/> | |||
</xs:sequence> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="header"> | |||
<xs:complexType> | |||
<xs:choice minOccurs="0" maxOccurs="unbounded"> | |||
<xs:element ref="x:xmpmeta" xmlns:x="adobe:ns:meta/"/> | |||
<xs:element ref="mf:bookmark-tree"/> | |||
<!--xs:element ref="x:xmpmeta" xmlns:x="adobe:ns:meta/"/--> | |||
<xs:any namespace="##other" processContents="lax"/> | |||
</xs:choice> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="bookmark-tree"> | |||
<xs:element name="trailer"> | |||
<xs:complexType> | |||
<xs:sequence minOccurs="1" maxOccurs="unbounded"> | |||
<xs:element ref="mf:bookmark"/> | |||
</xs:sequence> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="bookmark"> | |||
<xs:complexType> | |||
<xs:sequence minOccurs="1" maxOccurs="1"> | |||
<xs:element name="bookmark-title"> | |||
<xs:complexType> | |||
<xs:simpleContent> | |||
<xs:extension base="xs:string"> | |||
<xs:attribute name="color" type="mf:colorType"/> | |||
<xs:attribute name="font-style"> | |||
<xs:simpleType> | |||
<xs:restriction base="xs:string"> | |||
<xs:enumeration value="normal"/> | |||
<xs:enumeration value="italic"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
</xs:attribute> | |||
<xs:attribute name="font-weight"> | |||
<xs:simpleType> | |||
<xs:restriction base="xs:string"> | |||
<xs:enumeration value="normal"/> | |||
<xs:enumeration value="bold"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
</xs:attribute> | |||
</xs:extension> | |||
</xs:simpleContent> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element ref="mf:bookmark" maxOccurs="unbounded" minOccurs="0"/> | |||
</xs:sequence> | |||
<xs:attribute name="external-destination" type="xs:anyURI"/> | |||
<xs:attribute name="internal-destination" type="xs:NCName"> | |||
</xs:attribute> | |||
<xs:attribute name="starting-state"> | |||
<xs:simpleType> | |||
<xs:restriction base="xs:string"> | |||
<xs:enumeration value="show"/> | |||
<xs:enumeration value="hide"/> | |||
</xs:restriction> | |||
</xs:simpleType> | |||
</xs:attribute> | |||
<xs:choice minOccurs="0" maxOccurs="unbounded"> | |||
<!--xs:element ref="nav:bookmark-tree"/--> | |||
<xs:any namespace="##other" processContents="lax"/> | |||
</xs:choice> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="page-sequence"> | |||
<xs:complexType> | |||
<xs:sequence> | |||
<xs:element ref="mf:page"/> | |||
<xs:element ref="mf:page" minOccurs="1" maxOccurs="unbounded"/> | |||
</xs:sequence> | |||
<xs:attribute name="id" type="xs:ID"/> | |||
<xs:attributeGroup ref="mf:foreignAtts"/> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="page"> | |||
<xs:complexType> | |||
<xs:sequence> | |||
<xs:element name="page-header"> | |||
<xs:complexType> | |||
<xs:choice minOccurs="1" maxOccurs="unbounded"> | |||
<xs:any processContents="skip"/> | |||
</xs:choice> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:element name="page-header" type="mf:anyContent"/> | |||
<xs:element name="content" type="mf:contentType"/> | |||
<xs:element name="page-trailer" minOccurs="0"> | |||
<xs:complexType> | |||
<xs:sequence> | |||
<xs:element name="target" minOccurs="0" maxOccurs="unbounded"> | |||
<xs:complexType> | |||
<xs:attribute name="x" use="required" type="xs:integer"/> | |||
<xs:attribute name="y" use="required" type="xs:integer"/> | |||
<xs:attribute name="name" use="required" type="xs:ID"/> | |||
</xs:complexType> | |||
</xs:element> | |||
</xs:sequence> | |||
<xs:choice minOccurs="0" maxOccurs="unbounded"> | |||
<xs:element ref="nav:link"/> | |||
<xs:element ref="nav:goto-xy"/> | |||
</xs:choice> | |||
</xs:complexType> | |||
</xs:element> | |||
</xs:sequence> | |||
<xs:attribute name="index" type="xs:nonNegativeInteger" use="required"/> | |||
<xs:attribute name="name" type="xs:string"/> | |||
<xs:attribute name="page-master-name" type="xs:string"/> | |||
<xs:attributeGroup ref="mf:sizeAtts"/> | |||
<xs:attributeGroup ref="mf:foreignAtts"/> | |||
</xs:complexType> | |||
</xs:element> | |||
<xs:complexType name="anyContent"> | |||
<xs:choice minOccurs="0" maxOccurs="unbounded"> | |||
<xs:any namespace="##other" processContents="lax"/> | |||
</xs:choice> | |||
</xs:complexType> | |||
</xs:schema> |
@@ -0,0 +1,973 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- | |||
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$ --> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="210mm" | |||
height="297mm" | |||
id="svg2" | |||
sodipodi:version="0.32" | |||
inkscape:version="0.46" | |||
sodipodi:docbase="C:\Dev\FOP\main\docs" | |||
sodipodi:docname="if-architecture-overview.svg" | |||
inkscape:output_extension="org.inkscape.output.svg.inkscape" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new.png" | |||
inkscape:export-xdpi="96" | |||
inkscape:export-ydpi="96"> | |||
<defs | |||
id="defs4"> | |||
<inkscape:perspective | |||
sodipodi:type="inkscape:persp3d" | |||
inkscape:vp_x="0 : 526.18109 : 1" | |||
inkscape:vp_y="0 : 1000 : 0" | |||
inkscape:vp_z="744.09448 : 526.18109 : 1" | |||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1" | |||
id="perspective129" /> | |||
<marker | |||
inkscape:stockid="Arrow2Lend" | |||
orient="auto" | |||
refY="0.0" | |||
refX="0.0" | |||
id="Arrow2Lend" | |||
style="overflow:visible;"> | |||
<path | |||
id="path3213" | |||
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" | |||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z " | |||
transform="scale(1.1) rotate(180) translate(1,0)" /> | |||
</marker> | |||
</defs> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="1.5311603" | |||
inkscape:cx="520.07452" | |||
inkscape:cy="881.552" | |||
inkscape:document-units="mm" | |||
inkscape:current-layer="layer1" | |||
showgrid="false" | |||
grid_units="mm" | |||
gridtolerance="10000" | |||
guidetolerance="10000" | |||
showguides="true" | |||
inkscape:guide-bbox="true" | |||
inkscape:grid-points="true" | |||
inkscape:window-width="1280" | |||
inkscape:window-height="975" | |||
inkscape:window-x="1280" | |||
inkscape:window-y="22"> | |||
<inkscape:grid | |||
id="GridFromPre046Settings" | |||
type="xygrid" | |||
originx="0px" | |||
originy="0px" | |||
spacingx="1mm" | |||
spacingy="1mm" | |||
color="#0000ff" | |||
empcolor="#0000ff" | |||
opacity="0.2" | |||
empopacity="0.4" | |||
empspacing="2" /> | |||
</sodipodi:namedview> | |||
<metadata | |||
id="metadata7"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
inkscape:label="Ebene 1" | |||
inkscape:groupmode="layer" | |||
id="layer1"> | |||
<g | |||
id="g2901" | |||
transform="translate(85.03936,43.01968)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<rect | |||
ry="0" | |||
y="95.664871" | |||
x="177.66095" | |||
height="20.883432" | |||
width="49.615047" | |||
id="rect1872" | |||
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:0.99119538;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text1874" | |||
y="110.58022" | |||
x="202.47726" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans" | |||
y="110.58022" | |||
x="202.47726" | |||
id="tspan1876" | |||
sodipodi:role="line">fo:root</tspan></text> | |||
<rect | |||
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:1.59498918;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect1878" | |||
width="133.05069" | |||
height="20.164854" | |||
x="254.84074" | |||
y="81.793541" | |||
ry="0" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
x="321.37488" | |||
y="95.186516" | |||
id="text1880"><tspan | |||
sodipodi:role="line" | |||
id="tspan1882" | |||
x="321.37488" | |||
y="95.186516" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans">fo:layout-master-set</tspan></text> | |||
<rect | |||
ry="0" | |||
y="110.14" | |||
x="254.84074" | |||
height="20.164854" | |||
width="133.05069" | |||
id="rect1884" | |||
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:1.59498918;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
id="text1886" | |||
y="123.53297" | |||
x="321.37488" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve" | |||
sodipodi:linespacing="125%"><tspan | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans" | |||
y="123.53297" | |||
x="321.37488" | |||
id="tspan1888" | |||
sodipodi:role="line">fo:page-sequence</tspan></text> | |||
<path | |||
inkscape:connection-end="#rect1878" | |||
inkscape:connection-start="#rect1872" | |||
inkscape:connector-type="polyline" | |||
id="path1890" | |||
d="M 227.7716,103.0781 L 254.04326,99.933702" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<path | |||
inkscape:connection-end="#rect1884" | |||
inkscape:connection-start="#rect1872" | |||
inkscape:connector-type="polyline" | |||
id="path1892" | |||
d="M 227.7716,109.11064 L 254.04326,112.22968" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<rect | |||
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:0.74172068;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect2889" | |||
width="27.604736" | |||
height="21.018122" | |||
x="425.56772" | |||
y="88.953514" | |||
ry="0" /> | |||
<rect | |||
ry="0" | |||
y="116.79997" | |||
x="425.56772" | |||
height="21.018122" | |||
width="27.604736" | |||
id="rect2891" | |||
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:0.74172068;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<rect | |||
style="fill:#9cbaf1;fill-opacity:1;stroke:black;stroke-width:0.74172068;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect2893" | |||
width="27.604736" | |||
height="21.018122" | |||
x="425.56772" | |||
y="145.14642" | |||
ry="0" /> | |||
<path | |||
inkscape:connection-end="#rect2889" | |||
inkscape:connection-start="#rect1884" | |||
inkscape:connector-type="polyline" | |||
id="path2895" | |||
d="M 383.21018,109.3425 L 425.19686,101.956" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<path | |||
inkscape:connection-end="#rect2891" | |||
inkscape:connection-start="#rect1884" | |||
inkscape:connector-type="polyline" | |||
id="path2897" | |||
d="M 388.68893,124.26543 L 425.19686,126.45787" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<path | |||
inkscape:connection-end="#rect2893" | |||
inkscape:connection-start="#rect1884" | |||
inkscape:connector-type="polyline" | |||
id="path2899" | |||
d="M 357.59989,131.10235 L 425.19686,151.39969" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
</g> | |||
<g | |||
id="g2998" | |||
transform="translate(219.685,121.0872)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<g | |||
id="g2843"> | |||
<rect | |||
ry="0" | |||
y="195.09483" | |||
x="128.27205" | |||
height="20.448639" | |||
width="104.87323" | |||
id="rect1911" | |||
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:1.42598891;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text1913" | |||
y="208.6297" | |||
x="181.22136" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans" | |||
y="208.6297" | |||
x="181.22136" | |||
id="tspan1915" | |||
sodipodi:role="line">AreaTreeModel</tspan></text> | |||
</g> | |||
<g | |||
transform="translate(-21.25984,4.782451e-6)" | |||
id="g2848"> | |||
<rect | |||
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:1.42598891;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect2831" | |||
width="104.87322" | |||
height="20.448639" | |||
x="270.00433" | |||
y="194.98007" | |||
ry="0" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
x="322.17142" | |||
y="208.40947" | |||
id="text2833" | |||
sodipodi:linespacing="125%"><tspan | |||
sodipodi:role="line" | |||
id="tspan2835" | |||
x="322.17142" | |||
y="208.40947" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans">PageSequence</tspan></text> | |||
</g> | |||
<g | |||
id="g2943"> | |||
<rect | |||
ry="0" | |||
y="194.72183" | |||
x="368.95871" | |||
height="20.965132" | |||
width="41.610195" | |||
id="rect2837" | |||
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:0.909495;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text2839" | |||
y="208.33037" | |||
x="389.49426" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans" | |||
y="208.33037" | |||
x="389.49426" | |||
id="tspan2841" | |||
sodipodi:role="line">Page</tspan></text> | |||
</g> | |||
<path | |||
inkscape:connection-end="#g2848" | |||
inkscape:connection-start="#g2843" | |||
inkscape:connector-type="polyline" | |||
id="path2858" | |||
d="M 233.85827,205.26852 L 248.0315,205.25502" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<path | |||
inkscape:connection-start="#g2848" | |||
inkscape:connector-type="polyline" | |||
id="path2860" | |||
d="M 354.33071,205.2044 L 368.50396,205.2044" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<rect | |||
ry="0" | |||
y="187.55232" | |||
x="439.74191" | |||
height="21.130945" | |||
width="27.602772" | |||
id="rect2937" | |||
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:0.74368227;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<rect | |||
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:0.74368227;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect2939" | |||
width="27.602772" | |||
height="21.130945" | |||
x="439.74191" | |||
y="215.89877" | |||
ry="0" /> | |||
<rect | |||
ry="0" | |||
y="244.24522" | |||
x="439.74191" | |||
height="21.130945" | |||
width="27.602772" | |||
id="rect2941" | |||
style="fill:#9cf1cd;fill-opacity:1;stroke:black;stroke-width:0.74368227;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<path | |||
inkscape:connection-end="#rect2937" | |||
inkscape:connection-start="#g2943" | |||
inkscape:connector-type="polyline" | |||
id="path2948" | |||
d="M 411.02365,202.8422 L 439.37007,199.6926" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<path | |||
inkscape:connection-end="#rect2939" | |||
inkscape:connection-start="#g2943" | |||
inkscape:connector-type="polyline" | |||
id="path2950" | |||
d="M 411.02365,212.29102 L 439.37007,221.73983" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
<path | |||
inkscape:connection-end="#rect2941" | |||
inkscape:connection-start="#g2943" | |||
inkscape:connector-type="polyline" | |||
id="path2952" | |||
d="M 403.82606,216.14171 L 439.48105,243.87338" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> | |||
</g> | |||
<g | |||
id="g3253" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<rect | |||
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.24847627;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect2996" | |||
width="132.39719" | |||
height="40.27121" | |||
x="50.730537" | |||
y="68.447052" | |||
ry="0" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3020" | |||
y="93.801895" | |||
x="116.34612" | |||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
y="93.801895" | |||
x="116.34612" | |||
id="tspan3022" | |||
sodipodi:role="line">FOTreeBuilder</tspan></text> | |||
</g> | |||
<g | |||
id="g3247" | |||
transform="translate(141.7323,12.20033)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<rect | |||
ry="0" | |||
y="217.29221" | |||
x="50.756805" | |||
height="42.191582" | |||
width="132.34465" | |||
id="rect3031" | |||
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
x="116.88812" | |||
y="233.50031" | |||
id="text3033" | |||
sodipodi:linespacing="125%"><tspan | |||
sodipodi:role="line" | |||
id="tspan3035" | |||
x="116.88812" | |||
y="233.50031">AreaTreeHandler</tspan><tspan | |||
id="tspan3040" | |||
sodipodi:role="line" | |||
x="116.88812" | |||
y="251.00031">(Layout Engine)</tspan></text> | |||
</g> | |||
<rect | |||
style="fill:#ae9cf1;fill-opacity:1;stroke:black;stroke-width:1.77165354;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect3045" | |||
width="110.05285" | |||
height="20.705212" | |||
x="262.48203" | |||
y="39.253674" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3047" | |||
y="53.974442" | |||
x="317.62564" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"><tspan | |||
y="53.974442" | |||
x="317.62564" | |||
id="tspan3049" | |||
sodipodi:role="line">SAX Stream</tspan></text> | |||
<path | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow2Lend)" | |||
d="M 248.0315,53.149584 L 191.33858,74.409427" | |||
id="path3059" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<path | |||
id="path3241" | |||
d="M 191.43839,109.27294 L 255.09931,138.99007" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
sodipodi:nodetypes="cc" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<path | |||
id="path3243" | |||
d="M 261.55988,166.75554 L 245.20176,224.44681" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
sodipodi:nodetypes="cc" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
d="M 250.3891,277.42379 L 338.12078,314.94766" | |||
id="path3245" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
d="M 255.46357,165.63116 L 168.19427,225.27411" | |||
id="path3258" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
x="257.95044" | |||
y="195.39291" | |||
id="text3260" | |||
sodipodi:linespacing="125%" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"><tspan | |||
sodipodi:role="line" | |||
id="tspan3262" | |||
x="257.95044" | |||
y="195.39291">Interface:</tspan><tspan | |||
sodipodi:role="line" | |||
x="257.95044" | |||
y="207.89291" | |||
id="tspan3264">FOEventHandler</tspan></text> | |||
<g | |||
id="g3282" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<rect | |||
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect3268" | |||
width="132.34465" | |||
height="42.191582" | |||
x="50.756802" | |||
y="229.49254" | |||
ry="0" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3270" | |||
y="255.80757" | |||
x="116.24895" | |||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
y="255.80757" | |||
x="116.24895" | |||
sodipodi:role="line" | |||
id="tspan3274">RTFHandler</tspan></text> | |||
</g> | |||
<g | |||
id="g3294" | |||
transform="translate(14.40538,-35.26891)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<path | |||
sodipodi:nodetypes="ccccc" | |||
id="rect3287" | |||
d="M 63.383779,357.70983 L 127.3269,357.70983 L 127.3269,421.65409 C 118.19217,394.73019 81.653243,418.2886 63.383779,401.46117 L 63.383779,357.70983 z " | |||
style="fill:#f8ffb7;fill-opacity:1;stroke:black;stroke-width:0.98149604;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
id="text3290" | |||
y="382.34586" | |||
x="83.824089" | |||
style="font-size:12px;font-style:normal;font-weight:normal;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
y="382.34586" | |||
x="83.824089" | |||
id="tspan3292" | |||
sodipodi:role="line">RTF</tspan></text> | |||
</g> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
d="M 113.38583,279.92124 L 113.38583,315.35431" | |||
id="path3299" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<g | |||
id="g3390" | |||
transform="translate(89.82496,0)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<rect | |||
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect3303" | |||
width="132.34465" | |||
height="42.191582" | |||
x="242.0954" | |||
y="427.91769" | |||
ry="0" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3305" | |||
y="454.23273" | |||
x="308.06607" | |||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
y="454.23273" | |||
x="308.06607" | |||
sodipodi:role="line" | |||
id="tspan3309">XMLRenderer</tspan></text> | |||
</g> | |||
<g | |||
id="g3395" | |||
transform="translate(89.82496,0)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<rect | |||
ry="0" | |||
y="428.74014" | |||
x="389.76379" | |||
height="42.191582" | |||
width="132.34465" | |||
id="rect3317" | |||
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
x="455.73447" | |||
y="455.05518" | |||
id="text3319" | |||
sodipodi:linespacing="125%"><tspan | |||
id="tspan3321" | |||
sodipodi:role="line" | |||
x="455.73447" | |||
y="455.05518">IFRenderer</tspan></text> | |||
</g> | |||
<path | |||
id="path3331" | |||
d="M 545.66929,478.34643 L 481.88976,627.16533" | |||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
sodipodi:nodetypes="cc" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<path | |||
id="path3333" | |||
d="M 418.11024,343.70077 L 503.14961,421.65352" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
sodipodi:nodetypes="cc" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
d="M 396.85039,343.70077 L 389.76378,421.65352" | |||
id="path3335" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<g | |||
id="g3371" | |||
transform="translate(89.82496,0)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<path | |||
sodipodi:nodetypes="ccccc" | |||
id="path3339" | |||
d="M 276.8687,520.21064 L 340.81182,520.21064 L 340.81182,584.1549 C 331.67709,557.231 295.13816,580.78941 276.8687,563.96198 L 276.8687,520.21064 z " | |||
style="fill:#f8ffb7;fill-opacity:1;stroke:black;stroke-width:0.98149604;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3341" | |||
y="542.12598" | |||
x="310.29745" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
y="542.12598" | |||
x="310.29745" | |||
id="tspan3343" | |||
sodipodi:role="line">Area Tree</tspan><tspan | |||
y="557.12598" | |||
x="310.29745" | |||
sodipodi:role="line" | |||
id="tspan3345">XML</tspan></text> | |||
</g> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
d="M 394.54937,478.34643 L 394.54937,513.7795" | |||
id="path3369" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<g | |||
id="g3385" | |||
transform="translate(89.82496,0)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<rect | |||
ry="0" | |||
y="428.74014" | |||
x="80.253777" | |||
height="42.191582" | |||
width="132.34465" | |||
id="rect3379" | |||
style="fill:#f1de9c;fill-opacity:1;stroke:black;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
x="146.22444" | |||
y="455.05518" | |||
id="text3381" | |||
sodipodi:linespacing="125%"><tspan | |||
id="tspan3383" | |||
sodipodi:role="line" | |||
x="146.22444" | |||
y="455.05518">AreaTreeParser</tspan></text> | |||
</g> | |||
<path | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
d="M 394.54937,577.55903 C 394.54937,655.51179 233.85827,612.9921 233.85827,478.34643" | |||
id="path3402" | |||
sodipodi:nodetypes="cc" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
id="path3404" | |||
d="M 233.85827,421.65352 C 233.85827,357.87399 276.37795,329.52754 340.15748,329.52754" | |||
style="fill:none;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3406" | |||
y="379.13385" | |||
x="474.80316" | |||
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:black;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"><tspan | |||
y="379.13385" | |||
x="474.80316" | |||
id="tspan3408" | |||
sodipodi:role="line">Interface:</tspan><tspan | |||
id="tspan3410" | |||
y="391.63385" | |||
x="474.80316" | |||
sodipodi:role="line">Renderer</tspan></text> | |||
<g | |||
id="g3498" | |||
transform="translate(-89.635853,104.63778)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<path | |||
sodipodi:nodetypes="ccccc" | |||
id="path3483" | |||
d="M 651.31418,542.61673 L 715.2573,542.61673 L 715.2573,606.56099 C 706.12257,579.63709 669.58364,603.1955 651.31418,586.36807 L 651.31418,542.61673 z" | |||
style="fill:#f8ffb7;fill-opacity:1;stroke:#000000;stroke-width:0.98149604;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3485" | |||
y="572.13385" | |||
x="683.05139" | |||
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
y="572.13385" | |||
x="683.05139" | |||
id="tspan3487" | |||
sodipodi:role="line">IF</tspan></text> | |||
</g> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
x="602.36218" | |||
y="627.16534" | |||
id="text3489" | |||
sodipodi:linespacing="125%" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"><tspan | |||
sodipodi:role="line" | |||
id="tspan3491" | |||
x="602.36218" | |||
y="627.16534">Interface:</tspan><tspan | |||
sodipodi:role="line" | |||
x="602.36218" | |||
y="639.66534" | |||
id="tspan3493">ContentHandler (SAX)</tspan></text> | |||
<g | |||
id="g2555"> | |||
<rect | |||
style="fill:#f1de9c;fill-opacity:1;stroke:#000000;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect3505" | |||
width="132.34465" | |||
height="42.191582" | |||
x="552.75592" | |||
y="740.55115" | |||
ry="0" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3507" | |||
y="766.86621" | |||
x="618.24805" | |||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
y="766.86621" | |||
x="618.24805" | |||
sodipodi:role="line" | |||
id="tspan3509">IFParser</tspan></text> | |||
</g> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3520" | |||
y="522.43549" | |||
x="590.3725" | |||
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"><tspan | |||
y="522.43549" | |||
x="590.3725" | |||
id="tspan3522" | |||
sodipodi:role="line">Interfaces:</tspan><tspan | |||
id="tspan3524" | |||
y="534.93549" | |||
x="590.3725" | |||
sodipodi:role="line">IFDocumentHandler/</tspan><tspan | |||
y="547.43549" | |||
x="590.3725" | |||
sodipodi:role="line" | |||
id="tspan2551">IFPainter</tspan></text> | |||
<g | |||
id="g2536"> | |||
<g | |||
id="g3323" | |||
transform="translate(353.51182,368.6681)"> | |||
<path | |||
sodipodi:nodetypes="ccccc" | |||
id="path3325" | |||
d="M 63.383779,357.70983 L 127.3269,357.70983 L 127.3269,421.65409 C 118.19217,394.73019 81.653243,418.2886 63.383779,401.46117 L 63.383779,357.70983 z" | |||
style="fill:#f8ffb7;fill-opacity:1;stroke:#000000;stroke-width:0.98149604;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
id="text3327" | |||
y="382.34586" | |||
x="83.824089" | |||
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
y="382.34586" | |||
x="83.824089" | |||
id="tspan3329" | |||
sodipodi:role="line">PDF</tspan></text> | |||
</g> | |||
<g | |||
id="g2530"> | |||
<rect | |||
style="fill:#f1de9c;fill-opacity:1;stroke:#000000;stroke-width:2.58850002;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" | |||
id="rect3514" | |||
width="168.63074" | |||
height="41.904087" | |||
x="364.55179" | |||
y="635.05115" | |||
ry="0" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3516" | |||
y="652.47241" | |||
x="448.18698" | |||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve"><tspan | |||
y="652.47241" | |||
x="448.18698" | |||
sodipodi:role="line" | |||
id="tspan3518">PDFDocumentHandler/</tspan><tspan | |||
y="669.97241" | |||
x="448.18698" | |||
sodipodi:role="line" | |||
id="tspan2528">PDFPainter</tspan></text> | |||
</g> | |||
<path | |||
id="path3526" | |||
d="M 448.84954,684.51367 L 448.84954,719.94674" | |||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
sodipodi:nodetypes="cc" /> | |||
</g> | |||
<path | |||
id="path3528" | |||
d="M 595.27559,620.07872 L 595.27559,641.33856" | |||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
sodipodi:nodetypes="cc" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<path | |||
sodipodi:nodetypes="czszc" | |||
id="path3530" | |||
d="M 595.27559,790.15746 C 595.27559,811.4173 680.31495,811.4173 701.5748,790.15746 C 722.83465,768.89762 722.83465,708.6614 722.83465,641.33856 C 722.83465,566.92911 722.83465,520.86612 701.5748,499.60628 C 680.31496,478.34643 616.53543,471.25982 588.18898,513.77951" | |||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<g | |||
id="g3317" | |||
transform="translate(-11.872214,-169.75063)" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"> | |||
<rect | |||
ry="0" | |||
y="740.55115" | |||
x="566.92914" | |||
height="42.191582" | |||
width="132.34465" | |||
id="rect3308" | |||
style="fill:#f1de9c;fill-opacity:1;stroke:#000000;stroke-width:2.30100584;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
x="632.42126" | |||
y="766.86621" | |||
id="text3310" | |||
sodipodi:linespacing="125%"><tspan | |||
id="tspan3312" | |||
sodipodi:role="line" | |||
x="632.42126" | |||
y="766.86621">IFSerializer</tspan></text> | |||
</g> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
d="M 545.66929,478.34643 L 595.27559,563.3858" | |||
id="path3322" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<path | |||
sodipodi:nodetypes="cc" | |||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow2Lend);stroke-opacity:1" | |||
d="M 595.27559,705.11809 L 595.27559,733.46454" | |||
id="path3324" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008" /> | |||
<text | |||
sodipodi:linespacing="125%" | |||
id="text3326" | |||
y="719.29132" | |||
x="602.36218" | |||
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
xml:space="preserve" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"><tspan | |||
y="719.29132" | |||
x="602.36218" | |||
id="tspan3328" | |||
sodipodi:role="line">Interface:</tspan><tspan | |||
id="tspan3330" | |||
y="731.79132" | |||
x="602.36218" | |||
sodipodi:role="line">ContentHandler (SAX)</tspan></text> | |||
<text | |||
xml:space="preserve" | |||
style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" | |||
x="560.98297" | |||
y="812.41168" | |||
id="text3332" | |||
sodipodi:linespacing="125%" | |||
inkscape:export-filename="C:\Dev\FOP\main\docs\renderer-design-new-v2.png" | |||
inkscape:export-xdpi="95.985008" | |||
inkscape:export-ydpi="95.985008"><tspan | |||
sodipodi:role="line" | |||
id="tspan3334" | |||
x="560.98297" | |||
y="812.41168">Interfaces:</tspan><tspan | |||
sodipodi:role="line" | |||
x="560.98297" | |||
y="824.91168" | |||
id="tspan3336">IFDocumentHandler/</tspan><tspan | |||
sodipodi:role="line" | |||
x="560.98297" | |||
y="824.91168" | |||
id="tspan2553">IFPainter</tspan></text> | |||
</g> | |||
</svg> |
@@ -0,0 +1,20 @@ | |||
org.apache.fop.render.pdf.PDFImageHandlerGraphics2D | |||
org.apache.fop.render.pdf.PDFImageHandlerRenderedImage | |||
org.apache.fop.render.pdf.PDFImageHandlerRawJPEG | |||
org.apache.fop.render.pdf.PDFImageHandlerRawCCITTFax | |||
org.apache.fop.render.pdf.PDFImageHandlerSVG | |||
org.apache.fop.render.java2d.Java2DImageHandlerRenderedImage | |||
org.apache.fop.render.java2d.Java2DImageHandlerGraphics2D | |||
org.apache.fop.render.pcl.PCLImageHandlerRenderedImage | |||
org.apache.fop.render.pcl.PCLImageHandlerGraphics2D | |||
org.apache.fop.render.ps.PSImageHandlerRenderedImage | |||
org.apache.fop.render.ps.PSImageHandlerEPS | |||
org.apache.fop.render.ps.PSImageHandlerRawCCITTFax | |||
org.apache.fop.render.ps.PSImageHandlerRawJPEG | |||
org.apache.fop.render.ps.PSImageHandlerGraphics2D | |||
org.apache.fop.render.ps.PSImageHandlerSVG | |||
org.apache.fop.render.afp.AFPImageHandlerRenderedImage | |||
org.apache.fop.render.afp.AFPImageHandlerGraphics2D | |||
org.apache.fop.render.afp.AFPImageHandlerRawStream | |||
org.apache.fop.render.afp.AFPImageHandlerRawCCITTFax | |||
org.apache.fop.render.afp.AFPImageHandlerSVG |
@@ -7,4 +7,4 @@ org.apache.fop.render.xml.XMLRendererMaker | |||
org.apache.fop.render.awt.AWTRendererMaker | |||
org.apache.fop.render.print.PrintRendererMaker | |||
org.apache.fop.render.afp.AFPRendererMaker | |||
org.apache.fop.render.pcl.PCLRendererMaker | |||
org.apache.fop.render.pcl.PCLRendererMaker |
@@ -0,0 +1,6 @@ | |||
org.apache.fop.render.pdf.PDFDocumentHandlerMaker | |||
org.apache.fop.render.pcl.PCLDocumentHandlerMaker | |||
org.apache.fop.render.bitmap.TIFFDocumentHandlerMaker | |||
org.apache.fop.render.ps.PSDocumentHandlerMaker | |||
org.apache.fop.render.afp.AFPDocumentHandlerMaker | |||
org.apache.fop.render.intermediate.IFSerializerMaker |
@@ -1,2 +1,3 @@ | |||
org.apache.fop.image.loader.batik.ImageConverterSVG2G2D | |||
org.apache.fop.image.loader.batik.ImageConverterG2D2SVG | |||
org.apache.fop.image.loader.batik.ImageConverterWMF2G2D |
@@ -57,6 +57,7 @@ import org.apache.xmlgraphics.java2d.StrokingTextHandler; | |||
import org.apache.xmlgraphics.java2d.TextHandler; | |||
import org.apache.xmlgraphics.ps.ImageEncodingHelper; | |||
import org.apache.xmlgraphics.util.MimeConstants; | |||
import org.apache.xmlgraphics.util.UnitConv; | |||
import org.apache.fop.afp.goca.GraphicsSetLineType; | |||
import org.apache.fop.afp.modca.GraphicsObject; | |||
@@ -236,6 +237,32 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
this.gc = gc; | |||
} | |||
private int getResolution() { | |||
return this.paintingState.getResolution(); | |||
} | |||
/** | |||
* Converts a length value to an absolute value. | |||
* Please note that this only uses the "ScaleY" factor, so this will result | |||
* in a bad value should "ScaleX" and "ScaleY" be different. | |||
* @param length the length | |||
* @return the absolute length | |||
*/ | |||
public double convertToAbsoluteLength(double length) { | |||
AffineTransform current = getTransform(); | |||
double mult = getResolution() / (double)UnitConv.IN2PT; | |||
double factor = -current.getScaleY() / mult; | |||
return length * factor; | |||
} | |||
/** IBM's AFP Workbench paints lines that are wider than expected. We correct manually. */ | |||
private static final double GUESSED_WIDTH_CORRECTION = 1.7; | |||
private static final double SPEC_NORMAL_LINE_WIDTH = UnitConv.in2pt(0.01); //"approx" 0.01 inch | |||
private static final double NORMAL_LINE_WIDTH | |||
= SPEC_NORMAL_LINE_WIDTH * GUESSED_WIDTH_CORRECTION; | |||
/** | |||
* Apply the stroke to the AFP graphics object. | |||
* This takes the java stroke and outputs the appropriate settings | |||
@@ -249,7 +276,17 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
// set line width | |||
float lineWidth = basicStroke.getLineWidth(); | |||
graphicsObj.setLineWidth(Math.round(lineWidth / 2)); | |||
if (false) { | |||
//Old approach. Retained until verified problems with 1440 resolution | |||
graphicsObj.setLineWidth(Math.round(lineWidth / 2)); | |||
} else { | |||
double absoluteLineWidth = lineWidth * Math.abs(getTransform().getScaleY()); | |||
double multiplier = absoluteLineWidth / NORMAL_LINE_WIDTH; | |||
graphicsObj.setLineWidth((int)Math.round(multiplier)); | |||
//TODO Use GSFLW instead of GSLW for higher accuracy? | |||
} | |||
//No line join, miter limit and end cap support in GOCA. :-( | |||
// set line type/style (note: this is an approximation at best!) | |||
float[] dashArray = basicStroke.getDashArray(); | |||
@@ -689,7 +726,7 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand | |||
/** {@inheritDoc} */ | |||
public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, | |||
float x, float y, float width, float height) { | |||
log.debug("NYI: addNativeImage() "+ "image=" + image | |||
log.debug("NYI: addNativeImage() " + "image=" + image | |||
+ ",x=" + x + ",y=" + y + ",width=" + width + ",height=" + height); | |||
} | |||
@@ -19,8 +19,11 @@ | |||
package org.apache.fop.afp; | |||
import java.awt.Point; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.fonts.AFPPageFonts; | |||
import org.apache.fop.util.AbstractPaintingState; | |||
@@ -53,7 +56,7 @@ implements Cloneable { | |||
private int resolution = 240; // 240 dpi | |||
/** the current page */ | |||
private AFPPagePaintingState pagePaintingState = new AFPPagePaintingState(); | |||
private transient AFPPagePaintingState pagePaintingState = new AFPPagePaintingState(); | |||
// /** reference orientation */ | |||
// private int orientation = 0; | |||
@@ -313,6 +316,37 @@ implements Cloneable { | |||
return this.unitConv; | |||
} | |||
/** | |||
* Returns a point on the current page, taking the current painting state into account. | |||
* | |||
* @param x the X-coordinate | |||
* @param y the Y-coordinate | |||
* @return a point on the current page | |||
*/ | |||
public Point getPoint(int x, int y) { | |||
Point p = new Point(); | |||
int rotation = getRotation(); | |||
switch (rotation) { | |||
case 90: | |||
p.x = y; | |||
p.y = getPageWidth() - x; | |||
break; | |||
case 180: | |||
p.x = getPageWidth() - x; | |||
p.y = getPageHeight() - y; | |||
break; | |||
case 270: | |||
p.x = getPageHeight() - y; | |||
p.y = x; | |||
break; | |||
default: | |||
p.x = x; | |||
p.y = y; | |||
break; | |||
} | |||
return p; | |||
} | |||
/** {@inheritDoc} */ | |||
public Object clone() { | |||
AFPPaintingState paintingState = (AFPPaintingState)super.clone(); |
@@ -21,19 +21,32 @@ package org.apache.fop.afp; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.modca.AbstractNamedAFPObject; | |||
import org.apache.fop.afp.modca.AbstractPageObject; | |||
import org.apache.fop.afp.modca.IncludeObject; | |||
import org.apache.fop.afp.modca.IncludedResourceObject; | |||
import org.apache.fop.afp.modca.PageSegment; | |||
import org.apache.fop.afp.modca.Registry; | |||
import org.apache.fop.afp.modca.ResourceGroup; | |||
import org.apache.fop.afp.modca.ResourceObject; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
import org.apache.fop.afp.util.SimpleResourceAccessor; | |||
/** | |||
* Manages the creation and storage of document resources | |||
*/ | |||
public class AFPResourceManager { | |||
/** logging instance */ | |||
private static Log log = LogFactory.getLog(AFPResourceManager.class); | |||
/** The AFP datastream (document tree) */ | |||
private DataStream dataStream; | |||
@@ -47,8 +60,8 @@ public class AFPResourceManager { | |||
/** Maintain a reference count of instream objects for referencing purposes */ | |||
private int instreamObjectCount = 0; | |||
/** a mapping of resourceInfo --> names of includable objects */ | |||
private final Map/*<AFPResourceInfo,String>*/ includableObjectsMap | |||
/** a mapping of resourceInfo --> include name */ | |||
private final Map/*<AFPResourceInfo,String>*/ includeNameMap | |||
= new java.util.HashMap()/*<AFPResourceInfo,String>*/; | |||
private Map pageSegmentMap = new java.util.HashMap(); | |||
@@ -120,7 +133,7 @@ public class AFPResourceManager { | |||
AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo(); | |||
updateResourceInfoUri(resourceInfo); | |||
String objectName = (String)includableObjectsMap.get(resourceInfo); | |||
String objectName = (String)includeNameMap.get(resourceInfo); | |||
if (objectName != null) { | |||
// an existing data resource so reference it by adding an include to the current page | |||
includeObject(dataObjectInfo, objectName); | |||
@@ -156,35 +169,35 @@ public class AFPResourceManager { | |||
useInclude &= resourceGroup != null; | |||
if (useInclude) { | |||
boolean usePageSegment = dataObjectInfo.isCreatePageSegment(); | |||
// if it is to reside within a resource group at print-file or external level | |||
if (resourceLevel.isPrintFile() || resourceLevel.isExternal()) { | |||
if (usePageSegment) { | |||
String pageSegmentName = "S10" + namedObj.getName().substring(3); | |||
namedObj.setName(pageSegmentName); | |||
PageSegment seg = new PageSegment(pageSegmentName); | |||
seg.addObject(namedObj); | |||
namedObj = seg; | |||
} | |||
boolean usePageSegment = dataObjectInfo.isCreatePageSegment(); | |||
// wrap newly created data object in a resource object | |||
namedObj = dataObjectFactory.createResource(namedObj, resourceInfo, objectType); | |||
// if it is to reside within a resource group at print-file or external level | |||
if (resourceLevel.isPrintFile() || resourceLevel.isExternal()) { | |||
if (usePageSegment) { | |||
String pageSegmentName = "S10" + namedObj.getName().substring(3); | |||
namedObj.setName(pageSegmentName); | |||
PageSegment seg = new PageSegment(pageSegmentName); | |||
seg.addObject(namedObj); | |||
namedObj = seg; | |||
} | |||
// add data object into its resource group destination | |||
resourceGroup.addObject(namedObj); | |||
// wrap newly created data object in a resource object | |||
namedObj = dataObjectFactory.createResource(namedObj, resourceInfo, objectType); | |||
} | |||
// create the include object | |||
objectName = namedObj.getName(); | |||
if (usePageSegment) { | |||
includePageSegment(dataObjectInfo, objectName); | |||
pageSegmentMap.put(resourceInfo, objectName); | |||
} else { | |||
includeObject(dataObjectInfo, objectName); | |||
// record mapping of resource info to data object resource name | |||
includableObjectsMap.put(resourceInfo, objectName); | |||
} | |||
// add data object into its resource group destination | |||
resourceGroup.addObject(namedObj); | |||
// create the include object | |||
objectName = namedObj.getName(); | |||
if (usePageSegment) { | |||
includePageSegment(dataObjectInfo, objectName); | |||
pageSegmentMap.put(resourceInfo, objectName); | |||
} else { | |||
includeObject(dataObjectInfo, objectName); | |||
// record mapping of resource info to data object resource name | |||
includeNameMap.put(resourceInfo, objectName); | |||
} | |||
} else { | |||
// not to be included so inline data object directly into the current page | |||
@@ -206,10 +219,10 @@ public class AFPResourceManager { | |||
private void includeObject(AFPDataObjectInfo dataObjectInfo, | |||
String objectName) { | |||
IncludeObject includeObject | |||
= dataObjectFactory.createInclude(objectName, dataObjectInfo); | |||
dataStream.getCurrentPage().addObject(includeObject); | |||
} | |||
IncludeObject includeObject | |||
= dataObjectFactory.createInclude(objectName, dataObjectInfo); | |||
dataStream.getCurrentPage().addObject(includeObject); | |||
} | |||
private void includePageSegment(AFPDataObjectInfo dataObjectInfo, | |||
String pageSegmentName) { | |||
@@ -220,6 +233,53 @@ public class AFPResourceManager { | |||
currentPage.createIncludePageSegment(pageSegmentName, x, y, createHardPageSegments); | |||
} | |||
/** | |||
* Creates an included resource object by loading the contained object from a file. | |||
* @param resourceName the name of the resource | |||
* @param basePath the base path in which to look for the resource files | |||
* @param resourceObjectType the resource object type ({@link ResourceObject}.*) | |||
* @throws IOException if an I/O error occurs while loading the resource | |||
*/ | |||
public void createIncludedResource(String resourceName, String basePath, | |||
byte resourceObjectType) throws IOException { | |||
AFPResourceLevel resourceLevel = new AFPResourceLevel(AFPResourceLevel.PRINT_FILE); | |||
URI uri; | |||
try { | |||
uri = new URI(resourceName.trim()); | |||
} catch (URISyntaxException e) { | |||
throw new IOException("Could not create URI from resource name: " + resourceName | |||
+ " (" + e.getMessage() + ")"); | |||
} | |||
AFPResourceInfo resourceInfo = new AFPResourceInfo(); | |||
resourceInfo.setLevel(resourceLevel); | |||
resourceInfo.setName(resourceName); | |||
resourceInfo.setUri(uri.toASCIIString()); | |||
String objectName = (String)includeNameMap.get(resourceInfo); | |||
if (objectName == null) { | |||
if (log.isDebugEnabled()) { | |||
log.debug("Adding included resource: " + resourceName); | |||
} | |||
//TODO This works with local filenames only. In the long term, this | |||
//should work through FOP's URI resolver. | |||
ResourceAccessor accessor = new SimpleResourceAccessor(basePath); | |||
IncludedResourceObject resourceContent = new IncludedResourceObject( | |||
resourceName, accessor, uri); | |||
ResourceObject resourceObject = factory.createResource(resourceName); | |||
resourceObject.setDataObject(resourceContent); | |||
resourceObject.setType(resourceObjectType); | |||
ResourceGroup resourceGroup = streamer.getResourceGroup(resourceLevel); | |||
resourceGroup.addObject(resourceObject); | |||
// record mapping of resource info to data object resource name | |||
includeNameMap.put(resourceInfo, resourceName); | |||
} else { | |||
//skip, already created | |||
} | |||
} | |||
/** | |||
* Sets resource level defaults. The existing defaults over merged with the ones passed in | |||
* as parameter. | |||
@@ -236,4 +296,5 @@ public class AFPResourceManager { | |||
public AFPResourceLevelDefaults getResourceLevelDefaults() { | |||
return this.resourceLevelDefaults; | |||
} | |||
} | |||
} |
@@ -340,27 +340,7 @@ public class DataStream { | |||
* @return a point on the current page | |||
*/ | |||
private Point getPoint(int x, int y) { | |||
Point p = new Point(); | |||
int rotation = paintingState.getRotation(); | |||
switch (rotation) { | |||
case 90: | |||
p.x = y; | |||
p.y = currentPage.getWidth() - x; | |||
break; | |||
case 180: | |||
p.x = currentPage.getWidth() - x; | |||
p.y = currentPage.getHeight() - y; | |||
break; | |||
case 270: | |||
p.x = currentPage.getHeight() - y; | |||
p.y = x; | |||
break; | |||
default: | |||
p.x = x; | |||
p.y = y; | |||
break; | |||
} | |||
return p; | |||
return paintingState.getPoint(x, y); | |||
} | |||
/** |
@@ -97,13 +97,12 @@ public abstract class AFPFont extends Typeface { | |||
*/ | |||
public abstract CharacterSet getCharacterSet(int size); | |||
/** | |||
* Determines whether this font contains a particular character/glyph. | |||
* @param c character to check | |||
* @return True if the character is supported, False otherwise | |||
/** | |||
* Indicates if this font may be embedded. | |||
* @return True, if embedding is possible/permitted | |||
*/ | |||
public boolean hasChar(char c) { | |||
return true; | |||
public boolean isEmbeddable() { | |||
return false; //TODO Complete AFP font embedding | |||
} | |||
/** {@inheritDoc} */ |
@@ -21,10 +21,17 @@ package org.apache.fop.afp.fonts; | |||
import java.io.IOException; | |||
import java.io.UnsupportedEncodingException; | |||
import java.nio.ByteBuffer; | |||
import java.nio.CharBuffer; | |||
import java.nio.charset.CharacterCodingException; | |||
import java.nio.charset.Charset; | |||
import java.nio.charset.CharsetEncoder; | |||
import java.nio.charset.CodingErrorAction; | |||
import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.AFPConstants; | |||
import org.apache.fop.afp.util.StringUtils; | |||
@@ -65,6 +72,9 @@ public class CharacterSet { | |||
/** The encoding used for the code page */ | |||
protected String encoding; | |||
/** The charset encoder corresponding to this encoding */ | |||
private CharsetEncoder encoder; | |||
/** The character set relating to the font */ | |||
protected String name; | |||
@@ -104,6 +114,8 @@ public class CharacterSet { | |||
} | |||
this.codePage = codePage; | |||
this.encoding = encoding; | |||
this.encoder = Charset.forName(encoding).newEncoder(); | |||
this.encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); | |||
this.path = path; | |||
this.characterSetOrientations = new java.util.HashMap(4); | |||
@@ -303,6 +315,33 @@ public class CharacterSet { | |||
return c; | |||
} | |||
/** | |||
* Indicates whether the given char in the character set. | |||
* @param c the character to check | |||
* @return true if the character is in the character set | |||
*/ | |||
public boolean hasChar(char c) { | |||
return encoder.canEncode(c); | |||
} | |||
/** | |||
* Encodes a character sequence to a byte array. | |||
* @param chars the characters | |||
* @return the encoded characters | |||
* @throws CharacterCodingException if the encoding operation fails | |||
*/ | |||
public byte[] encodeChars(CharSequence chars) throws CharacterCodingException { | |||
ByteBuffer bb = encoder.encode(CharBuffer.wrap(chars)); | |||
if (bb.hasArray()) { | |||
return bb.array(); | |||
} else { | |||
bb.rewind(); | |||
byte[] bytes = new byte[bb.remaining()]; | |||
bb.get(bytes); | |||
return bytes; | |||
} | |||
} | |||
/** | |||
* Map a Unicode character to a code point in the font. | |||
* The code tables are already converted to Unicode therefore | |||
@@ -312,6 +351,7 @@ public class CharacterSet { | |||
* @return the mapped character | |||
*/ | |||
public char mapChar(char c) { | |||
//TODO This is not strictly correct but we'll let it be for the moment | |||
return c; | |||
} | |||
@@ -40,16 +40,6 @@ package org.apache.fop.afp.fonts; | |||
*/ | |||
public class CharacterSetOrientation { | |||
/** | |||
* The code page to which the character set relates | |||
*/ | |||
private String codePage; | |||
/** | |||
* The encoding used for the code page | |||
*/ | |||
private String encoding; | |||
/** | |||
* The ascender height for the character set | |||
*/ | |||
@@ -66,9 +56,9 @@ public class CharacterSetOrientation { | |||
private int capHeight; | |||
/** | |||
* The characters in the charcater set | |||
* The character widths in the character set | |||
*/ | |||
private int[] chars = new int[256]; | |||
private int[] charsWidths = new int[256]; | |||
/** | |||
* The height of lowercase letters | |||
@@ -166,8 +156,8 @@ public class CharacterSetOrientation { | |||
* @return the widths of all characters | |||
*/ | |||
public int[] getWidths() { | |||
int arr[] = new int[(getLastChar() - getFirstChar()) + 1]; | |||
System.arraycopy(chars, getFirstChar(), arr, 0, (getLastChar() - getFirstChar()) + 1); | |||
int[] arr = new int[(getLastChar() - getFirstChar()) + 1]; | |||
System.arraycopy(charsWidths, getFirstChar(), arr, 0, (getLastChar() - getFirstChar()) + 1); | |||
return arr; | |||
} | |||
@@ -187,11 +177,11 @@ public class CharacterSetOrientation { | |||
* @return the widths of the character | |||
*/ | |||
public int getWidth(int characterIndex) { | |||
if (characterIndex >= chars.length) { | |||
if (characterIndex >= charsWidths.length) { | |||
throw new IllegalArgumentException("Invalid character index: " | |||
+ characterIndex + ", maximum is " + (chars.length - 1)); | |||
+ characterIndex + ", maximum is " + (charsWidths.length - 1)); | |||
} | |||
return chars[characterIndex]; | |||
return charsWidths[characterIndex]; | |||
} | |||
/** | |||
@@ -253,14 +243,13 @@ public class CharacterSetOrientation { | |||
* @param width the widths of the character | |||
*/ | |||
public void setWidth(int character, int width) { | |||
if (character >= chars.length) { | |||
if (character >= charsWidths.length) { | |||
// Increase the size of the array if necessary | |||
int arr[] = new int[(character - firstChar) + 1]; | |||
System.arraycopy(chars, 0, arr, 0, chars.length); | |||
chars = arr; | |||
int[] arr = new int[(character - firstChar) + 1]; | |||
System.arraycopy(charsWidths, 0, arr, 0, charsWidths.length); | |||
charsWidths = arr; | |||
} | |||
chars[character] = width; | |||
charsWidths[character] = width; | |||
} | |||
@@ -166,6 +166,11 @@ public class OutlineFont extends AFPFont { | |||
return getWidths(1000); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean hasChar(char c) { | |||
return charSet.hasChar(c); | |||
} | |||
/** | |||
* Map a Unicode character to a code point in the font. | |||
* @param c character to map | |||
@@ -179,4 +184,5 @@ public class OutlineFont extends AFPFont { | |||
public String getEncodingName() { | |||
return charSet.getEncoding(); | |||
} | |||
} |
@@ -221,6 +221,11 @@ public class RasterFont extends AFPFont { | |||
return getWidths(1000); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean hasChar(char c) { | |||
return charSet.hasChar(c); | |||
} | |||
/** | |||
* Map a Unicode character to a code point in the font. | |||
* @param c character to map |
@@ -35,7 +35,7 @@ import org.apache.fop.afp.fonts.AFPFont; | |||
* page has a set of data objects associated with it. Each page within a | |||
* document is independent from any other page, and each must establish its own | |||
* environment parameters. | |||
* | |||
* <p> | |||
* The page is the level in the document component hierarchy that is used for | |||
* printing or displaying a document's content. The data objects contained in | |||
* the page envelope in the data stream are presented when the page is | |||
@@ -43,12 +43,11 @@ import org.apache.fop.afp.fonts.AFPFont; | |||
* directs the placement and orientation of the data on the page. In addition, | |||
* each page contains layout information that specifies the measurement units, | |||
* page width, and page depth. | |||
* | |||
* <p> | |||
* A page is initiated by a begin page structured field and terminated by an end | |||
* page structured field. Structured fields that define objects and active | |||
* environment groups or that specify attributes of the page may be encountered | |||
* in page state. | |||
* | |||
*/ | |||
public abstract class AbstractPageObject extends AbstractNamedAFPObject implements Completable { | |||
@@ -202,7 +201,7 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject implemen | |||
* | |||
* @return the presentation text object | |||
*/ | |||
private PresentationTextObject getPresentationTextObject() { | |||
public PresentationTextObject getPresentationTextObject() { | |||
if (currentPresentationTextObject == null) { | |||
PresentationTextObject presentationTextObject | |||
= factory.createPresentationTextObject(); |
@@ -179,20 +179,20 @@ public class GraphicsObject extends AbstractDataObject { | |||
} | |||
/** | |||
* Sets whether the following shape is to be filled | |||
* Sets whether the following shape is to be filled. | |||
* | |||
* @param fill true if the following shape is to be filled | |||
*/ | |||
public void setFill(boolean fill) { | |||
setPatternSymbol(fill ? | |||
GraphicsSetPatternSymbol.SOLID_FILL : | |||
GraphicsSetPatternSymbol.NO_FILL); | |||
setPatternSymbol(fill | |||
? GraphicsSetPatternSymbol.SOLID_FILL | |||
: GraphicsSetPatternSymbol.NO_FILL); | |||
} | |||
/** | |||
* Sets the fill pattern of the next shape | |||
* Sets the fill pattern of the next shape. | |||
* | |||
* @param the fill pattern of the next shape | |||
* @param patternSymbol the fill pattern of the next shape | |||
*/ | |||
public void setPatternSymbol(byte patternSymbol) { | |||
if (patternSymbol != graphicsState.patternSymbol) { | |||
@@ -332,6 +332,7 @@ public class GraphicsObject extends AbstractDataObject { | |||
*/ | |||
public void newSegment() { | |||
getData().newSegment(); | |||
graphicsState.lineWidth = 0; //Looks like a new segment invalidates the graphics state | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -366,7 +367,7 @@ public class GraphicsObject extends AbstractDataObject { | |||
} | |||
/** the internal graphics state */ | |||
private class GraphicsState { | |||
private static class GraphicsState { | |||
/** the current color */ | |||
private Color color; | |||
@@ -0,0 +1,63 @@ | |||
/* | |||
* 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.afp.modca; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.net.URI; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.fop.afp.util.ResourceAccessor; | |||
/** | |||
* Encapsulates an included resource object that is loaded from an external file. | |||
*/ | |||
public class IncludedResourceObject extends AbstractNamedAFPObject { | |||
private ResourceAccessor resourceAccessor; | |||
private URI uri; | |||
/** | |||
* Main constructor. | |||
* @param name the name of the included resource | |||
* @param resourceAccessor the resource accessor to load the external file with | |||
* @param uri the URI of the external file | |||
*/ | |||
public IncludedResourceObject(String name, | |||
ResourceAccessor resourceAccessor, URI uri) { | |||
super(name); | |||
this.resourceAccessor = resourceAccessor; | |||
this.uri = uri; | |||
} | |||
/** {@inheritDoc} */ | |||
public void writeToStream(OutputStream os) throws IOException { | |||
InputStream in = resourceAccessor.createInputStream(this.uri); | |||
try { | |||
IOUtils.copy(in, os); | |||
} finally { | |||
IOUtils.closeQuietly(in); | |||
} | |||
} | |||
} |
@@ -19,14 +19,13 @@ | |||
package org.apache.fop.afp.modca; | |||
import java.awt.Color; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.io.UnsupportedEncodingException; | |||
import org.apache.commons.io.output.ByteArrayOutputStream; | |||
import org.apache.fop.afp.AFPLineDataInfo; | |||
import org.apache.fop.afp.AFPTextDataInfo; | |||
import org.apache.fop.afp.ptoca.PtocaBuilder; | |||
import org.apache.fop.afp.ptoca.PtocaConstants; | |||
import org.apache.fop.afp.util.BinaryUtils; | |||
/** | |||
@@ -36,20 +35,21 @@ import org.apache.fop.afp.util.BinaryUtils; | |||
* that position them - modal control sequences that adjust the positions by | |||
* small amounts - other functions causing text to be presented with differences | |||
* in appearance. | |||
* | |||
* <p> | |||
* The graphic characters are expected to conform to a coded font representation | |||
* so that they can be translated from the code point in the object data to the | |||
* character in the coded font. The units of measure for linear displacements | |||
* are derived from the PresentationTextDescriptor or from the hierarchical | |||
* defaults. | |||
* | |||
* <p> | |||
* In addition to graphic character code points, Presentation Text data can | |||
* contain embedded control sequences. These are strings of two or more bytes | |||
* which signal an alternate mode of processing for the content of the current | |||
* Presentation Text data. | |||
* | |||
* <p> | |||
* The content for this object can be created using {@link PtocaBuilder}. | |||
*/ | |||
public class PresentationTextData extends AbstractAFPObject { | |||
public class PresentationTextData extends AbstractAFPObject implements PtocaConstants { | |||
/** the maximum size of the presentation text data.*/ | |||
private static final int MAX_SIZE = 8192; | |||
@@ -57,27 +57,6 @@ public class PresentationTextData extends AbstractAFPObject { | |||
/** the AFP data relating to this presentation text data. */ | |||
private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
/** the current x coordinate. */ | |||
private int currentX = -1; | |||
/** the current y cooridnate */ | |||
private int currentY = -1; | |||
/** the current font */ | |||
private String currentFont = ""; | |||
/** the current orientation */ | |||
private int currentOrientation = 0; | |||
/** the current color */ | |||
private Color currentColor = new Color(0, 0, 0); | |||
/** the current variable space increment */ | |||
private int currentVariableSpaceCharacterIncrement = 0; | |||
/** the current inter character adjustment */ | |||
private int currentInterCharacterAdjustment = 0; | |||
/** | |||
* Default constructor for the PresentationTextData. | |||
*/ | |||
@@ -85,6 +64,8 @@ public class PresentationTextData extends AbstractAFPObject { | |||
this(false); | |||
} | |||
private static final int HEADER_LENGTH = 9; | |||
/** | |||
* Constructor for the PresentationTextData, the boolean flag indicate | |||
* whether the control sequence prefix should be set to indicate the start | |||
@@ -105,7 +86,7 @@ public class PresentationTextData extends AbstractAFPObject { | |||
0x00, // Reserved | |||
0x00, // Reserved | |||
}; | |||
baos.write(data, 0, 9); | |||
baos.write(data, 0, HEADER_LENGTH); | |||
if (controlInd) { | |||
baos.write(new byte[] {0x2B, (byte) 0xD3}, 0, 2); | |||
@@ -113,420 +94,25 @@ public class PresentationTextData extends AbstractAFPObject { | |||
} | |||
/** | |||
* The Set Coded Font Local control sequence activates a coded font and | |||
* specifies the character attributes to be used. This is a modal control | |||
* sequence. | |||
* | |||
* @param font | |||
* The font local identifier. | |||
* @param afpdata | |||
* The output stream to which data should be written. | |||
*/ | |||
private void setCodedFont(byte font, ByteArrayOutputStream afpdata) { | |||
// Avoid unnecessary specification of the font | |||
if (String.valueOf(font).equals(currentFont)) { | |||
return; | |||
} else { | |||
currentFont = String.valueOf(font); | |||
} | |||
afpdata.write(new byte[] {0x03, (byte) 0xF1, font}, 0, 3); | |||
} | |||
/** | |||
* Establishes the current presentation position on the baseline at a new | |||
* I-axis coordinate, which is a specified number of measurement units from | |||
* the B-axis. There is no change to the current B-axis coordinate. | |||
* | |||
* @param coordinate | |||
* The coordinate for the inline move. | |||
* @param afpdata | |||
* The output stream to which data should be written. | |||
*/ | |||
private void absoluteMoveInline(int coordinate, | |||
ByteArrayOutputStream afpdata) { | |||
byte[] b = BinaryUtils.convert(coordinate, 2); | |||
afpdata.write(new byte[] {0x04, (byte) 0xC7, b[0], b[1]}, 0, 4); | |||
currentX = coordinate; | |||
} | |||
/** | |||
* Establishes the baseline and the current presentation position at a new | |||
* B-axis coordinate, which is a specified number of measurement units from | |||
* the I-axis. There is no change to the current I-axis coordinate. | |||
* | |||
* @param coordinate | |||
* The coordinate for the baseline move. | |||
* @param afpdata | |||
* The output stream to which data should be written. | |||
*/ | |||
private void absoluteMoveBaseline(int coordinate, | |||
ByteArrayOutputStream afpdata) { | |||
byte[] b = BinaryUtils.convert(coordinate, 2); | |||
afpdata.write(new byte[] {0x04, (byte) 0xD3, b[0], b[1]}, 0, 4); | |||
currentY = coordinate; | |||
} | |||
private static final int TRANSPARENT_MAX_SIZE = 253; | |||
/** | |||
* The Transparent Data control sequence contains a sequence of code points | |||
* that are presented without a scan for embedded control sequences. | |||
* | |||
* @param data | |||
* The text data to add. | |||
* @param afpdata | |||
* The output stream to which data should be written. | |||
*/ | |||
private void addTransparentData(byte[] data, ByteArrayOutputStream afpdata) { | |||
// Calculate the length | |||
int l = data.length + 2; | |||
if (l > 255) { | |||
// Check that we are not exceeding the maximum length | |||
throw new IllegalArgumentException( | |||
"Transparent data is longer than " + TRANSPARENT_MAX_SIZE + " bytes: " + data); | |||
} | |||
afpdata.write(new byte[] {BinaryUtils.convert(l)[0], (byte) 0xDB}, | |||
0, 2); | |||
afpdata.write(data, 0, data.length); | |||
} | |||
/** | |||
* Draws a line of specified length and specified width in the B-direction | |||
* from the current presentation position. The location of the current | |||
* presentation position is unchanged. | |||
* | |||
* @param length | |||
* The length of the rule. | |||
* @param width | |||
* The width of the rule. | |||
* @param afpdata | |||
* The output stream to which data should be written. | |||
*/ | |||
private void drawBaxisRule(int length, int width, | |||
ByteArrayOutputStream afpdata) { | |||
afpdata.write(new byte[] { | |||
0x07, // Length | |||
(byte) 0xE7, // Type | |||
}, 0, 2); | |||
// Rule length | |||
byte[] data1 = BinaryUtils.shortToByteArray((short) length); | |||
afpdata.write(data1, 0, data1.length); | |||
// Rule width | |||
byte[] data2 = BinaryUtils.shortToByteArray((short) width); | |||
afpdata.write(data2, 0, data2.length); | |||
// Rule width fraction | |||
afpdata.write(0x00); | |||
} | |||
/** | |||
* Draws a line of specified length and specified width in the I-direction | |||
* from the current presentation position. The location of the current | |||
* presentation position is unchanged. | |||
* | |||
* @param length | |||
* The length of the rule. | |||
* @param width | |||
* The width of the rule. | |||
* @param afpdata | |||
* The output stream to which data should be written. | |||
*/ | |||
private void drawIaxisRule(int length, int width, | |||
ByteArrayOutputStream afpdata) { | |||
afpdata.write(new byte[] { | |||
0x07, // Length | |||
(byte) 0xE5, // Type | |||
}, 0, 2); | |||
// Rule length | |||
byte[] data1 = BinaryUtils.shortToByteArray((short) length); | |||
afpdata.write(data1, 0, data1.length); | |||
// Rule width | |||
byte[] data2 = BinaryUtils.shortToByteArray((short) width); | |||
afpdata.write(data2, 0, data2.length); | |||
// Rule width fraction | |||
afpdata.write(0x00); | |||
} | |||
/** | |||
* Create the presentation text data for the byte array of data. | |||
* | |||
* @param textDataInfo | |||
* the afp text data | |||
* @throws MaximumSizeExceededException | |||
* thrown if the maximum number of text data is exceeded | |||
* @throws UnsupportedEncodingException | |||
* thrown if character encoding is not supported | |||
*/ | |||
public void createTextData(AFPTextDataInfo textDataInfo) | |||
throws MaximumSizeExceededException, UnsupportedEncodingException { | |||
ByteArrayOutputStream afpdata = new ByteArrayOutputStream(); | |||
int rotation = textDataInfo.getRotation(); | |||
if (currentOrientation != rotation) { | |||
setTextOrientation(rotation, afpdata); | |||
currentOrientation = rotation; | |||
currentX = -1; | |||
currentY = -1; | |||
} | |||
// Avoid unnecessary specification of the Y coordinate | |||
int y = textDataInfo.getY(); | |||
if (currentY != y) { | |||
absoluteMoveBaseline(y, afpdata); | |||
currentX = -1; | |||
} | |||
// Avoid unnecessary specification of the X coordinate | |||
int x = textDataInfo.getX(); | |||
if (currentX != x) { | |||
absoluteMoveInline(x, afpdata); | |||
} | |||
// Avoid unnecessary specification of the variable space increment | |||
if (textDataInfo.getVariableSpaceCharacterIncrement() | |||
!= currentVariableSpaceCharacterIncrement) { | |||
setVariableSpaceCharacterIncrement(textDataInfo | |||
.getVariableSpaceCharacterIncrement(), afpdata); | |||
currentVariableSpaceCharacterIncrement = textDataInfo | |||
.getVariableSpaceCharacterIncrement(); | |||
} | |||
// Avoid unnecessary specification of the inter character adjustment | |||
if (textDataInfo.getInterCharacterAdjustment() != currentInterCharacterAdjustment) { | |||
setInterCharacterAdjustment(textDataInfo.getInterCharacterAdjustment(), | |||
afpdata); | |||
currentInterCharacterAdjustment = textDataInfo | |||
.getInterCharacterAdjustment(); | |||
} | |||
// Avoid unnecessary specification of the text color | |||
if (!textDataInfo.getColor().equals(currentColor)) { | |||
setExtendedTextColor(textDataInfo.getColor(), afpdata); | |||
currentColor = textDataInfo.getColor(); | |||
} | |||
setCodedFont(BinaryUtils.convert(textDataInfo.getFontReference())[0], | |||
afpdata); | |||
// Add transparent data | |||
String textString = textDataInfo.getString(); | |||
String encoding = textDataInfo.getEncoding(); | |||
byte[] data = textString.getBytes(encoding); | |||
if (data.length <= TRANSPARENT_MAX_SIZE) { | |||
addTransparentData(data, afpdata); | |||
} else { | |||
// data size greater than TRANSPARENT_MAX_SIZE so slice | |||
int numTransData = data.length / TRANSPARENT_MAX_SIZE; | |||
byte[] buff = new byte[TRANSPARENT_MAX_SIZE]; | |||
int currIndex = 0; | |||
for (int transDataCnt = 0; transDataCnt < numTransData; transDataCnt++) { | |||
currIndex = transDataCnt * TRANSPARENT_MAX_SIZE; | |||
System.arraycopy(data, currIndex, buff, 0, TRANSPARENT_MAX_SIZE); | |||
addTransparentData(buff, afpdata); | |||
} | |||
int remainingTransData = data.length / TRANSPARENT_MAX_SIZE; | |||
buff = new byte[remainingTransData]; | |||
System.arraycopy(data, currIndex, buff, 0, remainingTransData); | |||
addTransparentData(buff, afpdata); | |||
} | |||
currentX = -1; | |||
int dataSize = afpdata.size(); | |||
if (baos.size() + dataSize > MAX_SIZE) { | |||
currentX = -1; | |||
currentY = -1; | |||
throw new MaximumSizeExceededException(); | |||
} | |||
byte[] outputdata = afpdata.toByteArray(); | |||
baos.write(outputdata, 0, outputdata.length); | |||
} | |||
private int ensurePositive(int value) { | |||
if (value < 0) { | |||
return 0; | |||
} | |||
return value; | |||
} | |||
/** | |||
* Drawing of lines using the starting and ending coordinates, thickness and | |||
* colour arguments. | |||
* | |||
* @param lineDataInfo the line data information. | |||
* @throws MaximumSizeExceededException | |||
* thrown if the maximum number of line data has been exceeded | |||
*/ | |||
public void createLineData(AFPLineDataInfo lineDataInfo) throws MaximumSizeExceededException { | |||
ByteArrayOutputStream afpdata = new ByteArrayOutputStream(); | |||
int orientation = lineDataInfo.getRotation(); | |||
if (currentOrientation != orientation) { | |||
setTextOrientation(orientation, afpdata); | |||
currentOrientation = orientation; | |||
} | |||
// Avoid unnecessary specification of the Y coordinate | |||
int y1 = ensurePositive(lineDataInfo.getY1()); | |||
if (y1 != currentY) { | |||
absoluteMoveBaseline(y1, afpdata); | |||
} | |||
// Avoid unnecessary specification of the X coordinate | |||
int x1 = ensurePositive(lineDataInfo.getX1()); | |||
if (x1 != currentX) { | |||
absoluteMoveInline(x1, afpdata); | |||
} | |||
Color color = lineDataInfo.getColor(); | |||
if (!color.equals(currentColor)) { | |||
setExtendedTextColor(color, afpdata); | |||
currentColor = color; | |||
} | |||
int x2 = ensurePositive(lineDataInfo.getX2()); | |||
int y2 = ensurePositive(lineDataInfo.getY2()); | |||
int thickness = lineDataInfo.getThickness(); | |||
if (y1 == y2) { | |||
drawIaxisRule(x2 - x1, thickness, afpdata); | |||
} else if (x1 == x2) { | |||
drawBaxisRule(y2 - y1, thickness, afpdata); | |||
} else { | |||
log.error("Invalid axis rule unable to draw line"); | |||
return; | |||
} | |||
int dataSize = afpdata.size(); | |||
if (baos.size() + dataSize > MAX_SIZE) { | |||
currentX = -1; | |||
currentY = -1; | |||
throw new MaximumSizeExceededException(); | |||
} | |||
byte[] outputdata = afpdata.toByteArray(); | |||
baos.write(outputdata, 0, outputdata.length); | |||
} | |||
/** | |||
* The Set Text Orientation control sequence establishes the I-direction and | |||
* B-direction for the subsequent text. This is a modal control sequence. | |||
* | |||
* Semantics: This control sequence specifies the I-axis and B-axis | |||
* orientations with respect to the Xp-axis for the current Presentation | |||
* Text object. The orientations are rotational values expressed in degrees | |||
* and minutes. | |||
* | |||
* @param orientation | |||
* The text orientation (0, 90, 180, 270). | |||
* @param os | |||
* The output stream to which data should be written. | |||
* Returns the number of data bytes still available in this object until it is full and a new | |||
* one has to be started. | |||
* @return the number of data bytes available | |||
*/ | |||
private void setTextOrientation(int orientation, | |||
ByteArrayOutputStream os) { | |||
os.write(new byte[] {0x06, (byte) 0xF7, }, 0, 2); | |||
switch (orientation) { | |||
case 90: | |||
os.write(0x2D); | |||
os.write(0x00); | |||
os.write(0x5A); | |||
os.write(0x00); | |||
break; | |||
case 180: | |||
os.write(0x5A); | |||
os.write(0x00); | |||
os.write(0x87); | |||
os.write(0x00); | |||
break; | |||
case 270: | |||
os.write(0x87); | |||
os.write(0x00); | |||
os.write(0x00); | |||
os.write(0x00); | |||
break; | |||
default: | |||
os.write(0x00); | |||
os.write(0x00); | |||
os.write(0x2D); | |||
os.write(0x00); | |||
break; | |||
} | |||
public int getBytesAvailable() { | |||
return MAX_SIZE - baos.size() + HEADER_LENGTH; | |||
} | |||
/** | |||
* The Set Extended Text Color control sequence specifies a color value and | |||
* defines the color space and encoding for that value. The specified color | |||
* value is applied to foreground areas of the text presentation space. This | |||
* is a modal control sequence. | |||
* | |||
* @param col | |||
* The color to be set. | |||
* @param os | |||
* The output stream to which data should be written. | |||
* Returns the output stream the content data is written to. | |||
* @return the output stream | |||
*/ | |||
private void setExtendedTextColor(Color col, ByteArrayOutputStream os) { | |||
byte[] colorData = new byte[] { | |||
15, // Control sequence length | |||
(byte) 0x81, // Control sequence function type | |||
0x00, // Reserved; must be zero | |||
0x01, // Color space - 0x01 = RGB | |||
0x00, // Reserved; must be zero | |||
0x00, // Reserved; must be zero | |||
0x00, // Reserved; must be zero | |||
0x00, // Reserved; must be zero | |||
8, // Number of bits in component 1 | |||
8, // Number of bits in component 2 | |||
8, // Number of bits in component 3 | |||
0, // Number of bits in component 4 | |||
(byte) (col.getRed()), // Red intensity | |||
(byte) (col.getGreen()), // Green intensity | |||
(byte) (col.getBlue()), // Blue intensity | |||
}; | |||
os.write(colorData, 0, colorData.length); | |||
} | |||
/** | |||
* //TODO This is a modal control sequence. | |||
* | |||
* @param incr | |||
* The increment to be set. | |||
* @param os | |||
* The output stream to which data should be written. | |||
*/ | |||
private void setVariableSpaceCharacterIncrement(int incr, | |||
ByteArrayOutputStream os) { | |||
byte[] b = BinaryUtils.convert(incr, 2); | |||
os.write(new byte[] { | |||
4, // Control sequence length | |||
(byte) 0xC5, // Control sequence function type | |||
b[0], b[1] }, | |||
0, 4); | |||
} | |||
/** | |||
* //TODO This is a modal control sequence. | |||
* | |||
* @param incr | |||
* The increment to be set. | |||
* @param os | |||
* The output stream to which data should be written. | |||
*/ | |||
private void setInterCharacterAdjustment(int incr, ByteArrayOutputStream os) { | |||
byte[] b = BinaryUtils.convert(Math.abs(incr), 2); | |||
os.write(new byte[] { | |||
5, // Control sequence length | |||
(byte) 0xC3, // Control sequence function type | |||
b[0], b[1], (byte) (incr >= 0 ? 0 : 1) // Direction | |||
}, 0, 5); | |||
protected OutputStream getOutputStream() { | |||
return this.baos; | |||
} | |||
/** {@inheritDoc} */ | |||
public void writeToStream(OutputStream os) throws IOException { | |||
assert getBytesAvailable() >= 0; | |||
byte[] data = baos.toByteArray(); | |||
byte[] size = BinaryUtils.convert(data.length - 1, 2); | |||
data[1] = size[0]; | |||
@@ -534,23 +120,4 @@ public class PresentationTextData extends AbstractAFPObject { | |||
os.write(data); | |||
} | |||
/** | |||
* A control sequence is a sequence of bytes that specifies a control | |||
* function. A control sequence consists of a control sequence introducer | |||
* and zero or more parameters. The control sequence can extend multiple | |||
* presentation text data objects, but must eventually be terminated. This | |||
* method terminates the control sequence. | |||
* | |||
* @throws MaximumSizeExceededException | |||
* thrown in the event that maximum size has been exceeded | |||
*/ | |||
public void endControlSequence() throws MaximumSizeExceededException { | |||
byte[] data = new byte[2]; | |||
data[0] = 0x02; | |||
data[1] = (byte) 0xF8; | |||
if (data.length + baos.size() > MAX_SIZE) { | |||
throw new MaximumSizeExceededException(); | |||
} | |||
baos.write(data, 0, data.length); | |||
} | |||
} |
@@ -26,6 +26,10 @@ import java.util.List; | |||
import org.apache.fop.afp.AFPLineDataInfo; | |||
import org.apache.fop.afp.AFPTextDataInfo; | |||
import org.apache.fop.afp.ptoca.LineDataInfoProducer; | |||
import org.apache.fop.afp.ptoca.PtocaBuilder; | |||
import org.apache.fop.afp.ptoca.PtocaProducer; | |||
import org.apache.fop.afp.ptoca.TextDataInfoProducer; | |||
/** | |||
* The Presentation Text object is the data object used in document processing | |||
@@ -41,6 +45,8 @@ import org.apache.fop.afp.AFPTextDataInfo; | |||
* collection of the graphic characters and control codes is called Presentation | |||
* Text, and the object that contains the Presentation Text is called the | |||
* PresentationText object. | |||
* <p> | |||
* The content for this object can be created using {@link PtocaBuilder}. | |||
*/ | |||
public class PresentationTextObject extends AbstractNamedAFPObject { | |||
@@ -54,6 +60,8 @@ public class PresentationTextObject extends AbstractNamedAFPObject { | |||
*/ | |||
private List/*<PresentationTextData>*/ presentationTextDataList = null; | |||
private PtocaBuilder builder = new DefaultBuilder(); | |||
/** | |||
* Construct a new PresentationTextObject for the specified name argument, | |||
* the name should be an 8 character identifier. | |||
@@ -72,17 +80,37 @@ public class PresentationTextObject extends AbstractNamedAFPObject { | |||
* @throws UnsupportedEncodingException thrown if character encoding is not supported | |||
*/ | |||
public void createTextData(AFPTextDataInfo textDataInfo) throws UnsupportedEncodingException { | |||
createControlSequences(new TextDataInfoProducer(textDataInfo)); | |||
} | |||
/** | |||
* Creates a chain of control sequences using a producer. | |||
* @param producer the producer | |||
* @throws UnsupportedEncodingException thrown if character encoding is not supported | |||
*/ | |||
public void createControlSequences(PtocaProducer producer) | |||
throws UnsupportedEncodingException { | |||
if (currentPresentationTextData == null) { | |||
startPresentationTextData(); | |||
} | |||
try { | |||
currentPresentationTextData.createTextData(textDataInfo); | |||
} catch (MaximumSizeExceededException msee) { | |||
endPresentationTextData(); | |||
createTextData(textDataInfo); | |||
producer.produce(builder); | |||
} catch (UnsupportedEncodingException e) { | |||
endPresentationTextData(); | |||
throw e; | |||
} catch (IOException ioe) { | |||
endPresentationTextData(); | |||
handleUnexpectedIOError(ioe); | |||
} | |||
} | |||
private class DefaultBuilder extends PtocaBuilder { | |||
protected OutputStream getOutputStreamForControlSequence(int length) { | |||
if (length > currentPresentationTextData.getBytesAvailable()) { | |||
endPresentationTextData(); | |||
startPresentationTextData(); | |||
} | |||
return currentPresentationTextData.getOutputStream(); | |||
} | |||
} | |||
@@ -93,14 +121,10 @@ public class PresentationTextObject extends AbstractNamedAFPObject { | |||
* @param lineDataInfo the line data information. | |||
*/ | |||
public void createLineData(AFPLineDataInfo lineDataInfo) { | |||
if (currentPresentationTextData == null) { | |||
startPresentationTextData(); | |||
} | |||
try { | |||
currentPresentationTextData.createLineData(lineDataInfo); | |||
} catch (MaximumSizeExceededException msee) { | |||
endPresentationTextData(); | |||
createLineData(lineDataInfo); | |||
createControlSequences(new LineDataInfoProducer(lineDataInfo)); | |||
} catch (UnsupportedEncodingException e) { | |||
handleUnexpectedIOError(e); //Won't happen for lines | |||
} | |||
} | |||
@@ -157,18 +181,24 @@ public class PresentationTextObject extends AbstractNamedAFPObject { | |||
startPresentationTextData(); | |||
} | |||
try { | |||
currentPresentationTextData.endControlSequence(); | |||
} catch (MaximumSizeExceededException msee) { | |||
builder.endChainedControlSequence(); | |||
} catch (IOException ioe) { | |||
endPresentationTextData(); | |||
endControlSequence(); | |||
handleUnexpectedIOError(ioe); | |||
//Should not occur since we're writing to byte arrays | |||
} | |||
} | |||
private void handleUnexpectedIOError(IOException ioe) { | |||
//"Unexpected" since we're currently dealing with ByteArrayOutputStreams here. | |||
throw new RuntimeException("Unexpected I/O error: " + ioe.getMessage(), ioe); | |||
} | |||
/** {@inheritDoc} */ | |||
public String toString() { | |||
if (presentationTextDataList != null) { | |||
return presentationTextDataList.toString(); | |||
} | |||
return null; | |||
return super.toString(); | |||
} | |||
} |
@@ -0,0 +1,76 @@ | |||
/* | |||
* 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.afp.ptoca; | |||
import java.io.IOException; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.AFPLineDataInfo; | |||
/** | |||
* {@link PtocaProducer} implementation that interprets {@link AFPLineDataInfo} objects. | |||
*/ | |||
public class LineDataInfoProducer implements PtocaProducer, PtocaConstants { | |||
/** Static logging instance */ | |||
private static final Log log = LogFactory.getLog(LineDataInfoProducer.class); | |||
private AFPLineDataInfo lineDataInfo; | |||
/** | |||
* Main constructor. | |||
* @param lineDataInfo the info object | |||
*/ | |||
public LineDataInfoProducer(AFPLineDataInfo lineDataInfo) { | |||
this.lineDataInfo = lineDataInfo; | |||
} | |||
/** {@inheritDoc} */ | |||
public void produce(PtocaBuilder builder) throws IOException { | |||
builder.setTextOrientation(lineDataInfo.getRotation()); | |||
int x1 = ensurePositive(lineDataInfo.getX1()); | |||
int y1 = ensurePositive(lineDataInfo.getY1()); | |||
builder.absoluteMoveBaseline(y1); | |||
builder.absoluteMoveInline(x1); | |||
builder.setExtendedTextColor(lineDataInfo.getColor()); | |||
int x2 = ensurePositive(lineDataInfo.getX2()); | |||
int y2 = ensurePositive(lineDataInfo.getY2()); | |||
int thickness = lineDataInfo.getThickness(); | |||
if (y1 == y2) { | |||
builder.drawIaxisRule(x2 - x1, thickness); | |||
} else if (x1 == x2) { | |||
builder.drawBaxisRule(y2 - y1, thickness); | |||
} else { | |||
log.error("Invalid axis rule: unable to draw line"); | |||
return; | |||
} | |||
} | |||
private static int ensurePositive(int value) { | |||
if (value < 0) { | |||
return 0; | |||
} | |||
return value; | |||
} | |||
} |
@@ -0,0 +1,389 @@ | |||
/* | |||
* 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.afp.ptoca; | |||
import java.awt.Color; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import org.apache.commons.io.output.ByteArrayOutputStream; | |||
/** | |||
* Generator class for PTOCA data structures. | |||
*/ | |||
public abstract class PtocaBuilder implements PtocaConstants { | |||
private ByteArrayOutputStream baout = new ByteArrayOutputStream(256); | |||
/** the current x coordinate. */ | |||
private int currentX = -1; | |||
/** the current y coordinate */ | |||
private int currentY = -1; | |||
/** the current font */ | |||
private int currentFont = Integer.MIN_VALUE; | |||
/** the current orientation */ | |||
private int currentOrientation = 0; | |||
/** the current color */ | |||
private Color currentColor = Color.BLACK; | |||
/** the current variable space increment */ | |||
private int currentVariableSpaceCharacterIncrement = 0; | |||
/** the current inter character adjustment */ | |||
private int currentInterCharacterAdjustment = 0; | |||
/** | |||
* Returns an {@link OutputStream} for the next control sequence. This gives a subclass a | |||
* chance to do chunking of control sequences into multiple presentation text data objects. | |||
* @param length the length of the following control sequence | |||
* @return the output stream where the control sequence will be written to | |||
*/ | |||
protected abstract OutputStream getOutputStreamForControlSequence(int length); | |||
private static byte chained(byte functionType) { | |||
return (byte)(functionType | CHAIN_BIT); | |||
} | |||
private void newControlSequence() { | |||
baout.reset(); | |||
} | |||
private void commit(byte functionType) throws IOException { | |||
int length = baout.size() + 2; | |||
assert length < 256; | |||
OutputStream out = getOutputStreamForControlSequence(length); | |||
out.write(length); | |||
out.write(functionType); | |||
baout.writeTo(out); | |||
} | |||
private void write(byte[] data, int offset, int length) { | |||
baout.write(data, offset, length); | |||
} | |||
private void writeByte(int data) { | |||
baout.write(data); | |||
} | |||
private void writeShort(int data) { | |||
baout.write((data >>> 8) & 0xFF); | |||
baout.write(data & 0xFF); | |||
} | |||
/** | |||
* Writes the introducer for a chained control sequence. | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void writeIntroducer() throws IOException { | |||
OutputStream out = getOutputStreamForControlSequence(ESCAPE.length); | |||
out.write(ESCAPE); | |||
} | |||
/** | |||
* The Set Coded Font Local control sequence activates a coded font and | |||
* specifies the character attributes to be used. | |||
* <p> | |||
* This is a modal control sequence. | |||
* | |||
* @param font The font local identifier. | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void setCodedFont(byte font) throws IOException { | |||
// Avoid unnecessary specification of the font | |||
if (currentFont == font) { | |||
return; | |||
} else { | |||
currentFont = font; | |||
} | |||
newControlSequence(); | |||
writeByte(font); | |||
commit(chained(SCFL)); | |||
} | |||
/** | |||
* Establishes the current presentation position on the baseline at a new | |||
* I-axis coordinate, which is a specified number of measurement units from | |||
* the B-axis. There is no change to the current B-axis coordinate. | |||
* | |||
* @param coordinate The coordinate for the inline move. | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void absoluteMoveInline(int coordinate) throws IOException { | |||
if (coordinate == this.currentX) { | |||
return; | |||
} | |||
newControlSequence(); | |||
writeShort(coordinate); | |||
commit(chained(AMI)); | |||
currentX = coordinate; | |||
} | |||
/** | |||
* Moves the inline coordinate of the presentation position relative to the current | |||
* inline position. | |||
* @param increment the increment in 1/1440 inch units | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void relativeMoveInline(int increment) throws IOException { | |||
newControlSequence(); | |||
writeShort(increment); | |||
commit(chained(RMI)); | |||
} | |||
/** | |||
* Establishes the baseline and the current presentation position at a new | |||
* B-axis coordinate, which is a specified number of measurement units from | |||
* the I-axis. There is no change to the current I-axis coordinate. | |||
* | |||
* @param coordinate The coordinate for the baseline move. | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void absoluteMoveBaseline(int coordinate) throws IOException { | |||
if (coordinate == this.currentY) { | |||
return; | |||
} | |||
newControlSequence(); | |||
writeShort(coordinate); | |||
commit(chained(AMB)); | |||
currentY = coordinate; | |||
currentX = -1; | |||
} | |||
private static final int TRANSPARENT_MAX_SIZE = 253; | |||
/** | |||
* The Transparent Data control sequence contains a sequence of code points | |||
* that are presented without a scan for embedded control sequences. If the data is larger | |||
* than fits in one chunk, additional chunks are automatically generated. | |||
* | |||
* @param data The text data to add. | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void addTransparentData(byte[] data) throws IOException { | |||
if (data.length <= TRANSPARENT_DATA_MAX_SIZE) { | |||
addTransparentDataChunk(data); | |||
} else { | |||
// data size greater than TRANSPARENT_MAX_SIZE, so slice | |||
int numTransData = data.length / TRANSPARENT_DATA_MAX_SIZE; | |||
int currIndex = 0; | |||
for (int transDataCnt = 0; transDataCnt < numTransData; transDataCnt++) { | |||
addTransparentDataChunk(data, currIndex, TRANSPARENT_DATA_MAX_SIZE); | |||
currIndex += TRANSPARENT_DATA_MAX_SIZE; | |||
} | |||
int left = data.length - currIndex; | |||
addTransparentDataChunk(data, currIndex, left); | |||
} | |||
} | |||
private void addTransparentDataChunk(byte[] data) throws IOException { | |||
addTransparentDataChunk(data, 0, data.length); | |||
} | |||
private void addTransparentDataChunk(byte[] data, int offset, int length) throws IOException { | |||
if (length > TRANSPARENT_MAX_SIZE) { | |||
// Check that we are not exceeding the maximum length | |||
throw new IllegalArgumentException( | |||
"Transparent data is longer than " + TRANSPARENT_MAX_SIZE + " bytes"); | |||
} | |||
newControlSequence(); | |||
write(data, offset, length); | |||
commit(chained(TRN)); | |||
} | |||
/** | |||
* Draws a line of specified length and specified width in the B-direction | |||
* from the current presentation position. The location of the current | |||
* presentation position is unchanged. | |||
* | |||
* @param length The length of the rule. | |||
* @param width The width of the rule. | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void drawBaxisRule(int length, int width) throws IOException { | |||
newControlSequence(); | |||
writeShort(length); // Rule length | |||
writeShort(width); // Rule width | |||
writeByte(0); // Rule width fraction is always null. enough? | |||
commit(chained(DBR)); | |||
} | |||
/** | |||
* Draws a line of specified length and specified width in the I-direction | |||
* from the current presentation position. The location of the current | |||
* presentation position is unchanged. | |||
* | |||
* @param length The length of the rule. | |||
* @param width The width of the rule. | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void drawIaxisRule(int length, int width) throws IOException { | |||
newControlSequence(); | |||
writeShort(length); // Rule length | |||
writeShort(width); // Rule width | |||
writeByte(0); // Rule width fraction is always null. enough? | |||
commit(chained(DIR)); | |||
} | |||
/** | |||
* The Set Text Orientation control sequence establishes the I-direction and | |||
* B-direction for the subsequent text. This is a modal control sequence. | |||
* | |||
* Semantics: This control sequence specifies the I-axis and B-axis | |||
* orientations with respect to the Xp-axis for the current Presentation | |||
* Text object. The orientations are rotational values expressed in degrees | |||
* and minutes. | |||
* | |||
* @param orientation The text orientation (0, 90, 180, 270). | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void setTextOrientation(int orientation) throws IOException { | |||
if (orientation == this.currentOrientation) { | |||
return; | |||
} | |||
newControlSequence(); | |||
switch (orientation) { | |||
case 90: | |||
writeByte(0x2D); | |||
writeByte(0x00); | |||
writeByte(0x5A); | |||
writeByte(0x00); | |||
break; | |||
case 180: | |||
writeByte(0x5A); | |||
writeByte(0x00); | |||
writeByte(0x87); | |||
writeByte(0x00); | |||
break; | |||
case 270: | |||
writeByte(0x87); | |||
writeByte(0x00); | |||
writeByte(0x00); | |||
writeByte(0x00); | |||
break; | |||
default: | |||
writeByte(0x00); | |||
writeByte(0x00); | |||
writeByte(0x2D); | |||
writeByte(0x00); | |||
break; | |||
} | |||
commit(chained(STO)); | |||
this.currentOrientation = orientation; | |||
currentX = -1; | |||
currentY = -1; | |||
} | |||
/** | |||
* The Set Extended Text Color control sequence specifies a color value and | |||
* defines the color space and encoding for that value. The specified color | |||
* value is applied to foreground areas of the text presentation space. | |||
* <p> | |||
* This is a modal control sequence. | |||
* | |||
* @param col The color to be set. | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void setExtendedTextColor(Color col) throws IOException { | |||
if (col.equals(currentColor)) { | |||
return; | |||
} | |||
newControlSequence(); | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(0x01); // Color space - 0x01 = RGB | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(0x00); // Reserved; must be zero | |||
writeByte(8); // Number of bits in component 1 | |||
writeByte(8); // Number of bits in component 2 | |||
writeByte(8); // Number of bits in component 3 | |||
writeByte(0); // Number of bits in component 4 | |||
writeByte(col.getRed()); // Red intensity | |||
writeByte(col.getGreen()); // Green intensity | |||
writeByte(col.getBlue()); // Blue intensity | |||
commit(chained(SEC)); | |||
this.currentColor = col; | |||
} | |||
/** | |||
* Sets the variable space character increment. | |||
* <p> | |||
* This is a modal control sequence. | |||
* | |||
* @param incr The increment to be set (positive integer, 1/1440 inch) | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void setVariableSpaceCharacterIncrement(int incr) throws IOException { | |||
if (incr == this.currentVariableSpaceCharacterIncrement) { | |||
return; | |||
} | |||
assert incr >= 0 && incr < (1 << 16); | |||
newControlSequence(); | |||
writeShort(Math.abs(incr)); //Increment | |||
commit(chained(SVI)); | |||
this.currentVariableSpaceCharacterIncrement = incr; | |||
} | |||
/** | |||
* Sets the intercharacter adjustment (additional increment or decrement between graphic | |||
* characters). | |||
* <p> | |||
* This is a modal control sequence. | |||
* | |||
* @param incr The increment to be set (1/1440 inch) | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void setInterCharacterAdjustment(int incr) throws IOException { | |||
if (incr == this.currentInterCharacterAdjustment) { | |||
return; | |||
} | |||
assert incr >= Short.MIN_VALUE && incr <= Short.MAX_VALUE; | |||
newControlSequence(); | |||
writeShort(Math.abs(incr)); //Increment | |||
writeByte(incr >= 0 ? 0 : 1); // Direction | |||
commit(chained(SIA)); | |||
this.currentInterCharacterAdjustment = incr; | |||
} | |||
/** | |||
* A control sequence is a sequence of bytes that specifies a control | |||
* function. A control sequence consists of a control sequence introducer | |||
* and zero or more parameters. The control sequence can extend multiple | |||
* presentation text data objects, but must eventually be terminated. This | |||
* method terminates the control sequence (by using a NOP command). | |||
* | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
public void endChainedControlSequence() throws IOException { | |||
newControlSequence(); | |||
commit(NOP); | |||
} | |||
} |
@@ -0,0 +1,69 @@ | |||
/* | |||
* 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.afp.ptoca; | |||
/** | |||
* A collection of PTOCA constants. | |||
*/ | |||
public interface PtocaConstants { | |||
/** | |||
* "Escape" sequence for normal PTOCA command sequences. | |||
*/ | |||
byte[] ESCAPE = new byte[] {0x2B, (byte)0xD3}; | |||
/** Bit to set for chained control sequences */ | |||
byte CHAIN_BIT = 1; | |||
/** Set Intercharacter Adjustment */ | |||
byte SIA = (byte)0xC2; | |||
/** Set Variable Space Character Increment */ | |||
byte SVI = (byte)0xC4; | |||
/** Absolute Move Inline */ | |||
byte AMI = (byte)0xC6; | |||
/** Relative Move Inline */ | |||
byte RMI = (byte)0xC8; | |||
/** Absolute Move Baseline */ | |||
byte AMB = (byte)0xD2; | |||
/** Transparent Data */ | |||
byte TRN = (byte)0xDA; | |||
/** Draw I-axis Rule */ | |||
byte DIR = (byte)0xE4; | |||
/** Draw B-axis Rule */ | |||
byte DBR = (byte)0xE6; | |||
/** Set Extended Text Color */ | |||
byte SEC = (byte)0x80; | |||
/** Set Coded Font Local */ | |||
byte SCFL = (byte)0xF0; | |||
/** Set Text Orientation */ | |||
byte STO = (byte)0xF6; | |||
/** No Operation */ | |||
byte NOP = (byte)0xF8; | |||
/** Maximum size of transparent data chunks */ | |||
int TRANSPARENT_DATA_MAX_SIZE = 253; | |||
} |
@@ -0,0 +1,39 @@ | |||
/* | |||
* 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.afp.ptoca; | |||
import java.io.IOException; | |||
import org.apache.fop.afp.modca.PresentationTextObject; | |||
/** | |||
* Producer interface that is passed to a {@link PresentationTextObject} to produce PTOCA control | |||
* sequences using a {@link PtocaBuilder}. | |||
*/ | |||
public interface PtocaProducer { | |||
/** | |||
* Produces the PTOCA control sequences by calling methods on {@link PtocaBuilder}. | |||
* @param builder the builder object | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
void produce(PtocaBuilder builder) throws IOException; | |||
} |
@@ -0,0 +1,62 @@ | |||
/* | |||
* 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.afp.ptoca; | |||
import java.io.IOException; | |||
import org.apache.fop.afp.AFPTextDataInfo; | |||
/** | |||
* {@link PtocaProducer} implementation that interprets {@link AFPTextDataInfo} objects. | |||
*/ | |||
public class TextDataInfoProducer implements PtocaProducer, PtocaConstants { | |||
private AFPTextDataInfo textDataInfo; | |||
/** | |||
* Main constructor. | |||
* @param textDataInfo the info object | |||
*/ | |||
public TextDataInfoProducer(AFPTextDataInfo textDataInfo) { | |||
this.textDataInfo = textDataInfo; | |||
} | |||
/** {@inheritDoc} */ | |||
public void produce(PtocaBuilder builder) throws IOException { | |||
builder.setTextOrientation(textDataInfo.getRotation()); | |||
builder.absoluteMoveBaseline(textDataInfo.getY()); | |||
builder.absoluteMoveInline(textDataInfo.getX()); | |||
builder.setVariableSpaceCharacterIncrement( | |||
textDataInfo.getVariableSpaceCharacterIncrement()); | |||
builder.setInterCharacterAdjustment( | |||
textDataInfo.getInterCharacterAdjustment()); | |||
builder.setExtendedTextColor(textDataInfo.getColor()); | |||
builder.setCodedFont((byte)textDataInfo.getFontReference()); | |||
// Add transparent data | |||
String textString = textDataInfo.getString(); | |||
String encoding = textDataInfo.getEncoding(); | |||
byte[] data = textString.getBytes(encoding); | |||
builder.addTransparentData(data); | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
<!-- | |||
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$ --> | |||
<HTML> | |||
<TITLE>org.apache.fop.afp.ptoca Package</TITLE> | |||
<BODY> | |||
<P>Contains a collection of classes for working with Presentation Text Objects (PTOCA).</P> | |||
</BODY> | |||
</HTML> |
@@ -19,19 +19,21 @@ | |||
package org.apache.fop.afp.svg; | |||
import org.apache.fop.svg.AbstractFOPImageElementBridge; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.fop.image.loader.batik.BatikImageFlavors; | |||
import org.apache.fop.svg.AbstractFOPImageElementBridge; | |||
/** | |||
* An AFP specific implementation of a Batik SVGImageElementBridge | |||
*/ | |||
public class AFPImageElementBridge extends AbstractFOPImageElementBridge { | |||
private final ImageFlavor[] supportedFlavors = new ImageFlavor[] | |||
{ImageFlavor.RAW_JPEG, | |||
ImageFlavor.RAW_CCITTFAX, | |||
{//ImageFlavor.RAW_JPEG, | |||
//ImageFlavor.RAW_CCITTFAX, | |||
ImageFlavor.GRAPHICS2D, | |||
ImageFlavor.XML_DOM}; | |||
BatikImageFlavors.SVG_DOM}; | |||
/** {@inheritDoc} */ | |||
protected ImageFlavor[] getSupportedFlavours() { |
@@ -25,6 +25,7 @@ import java.io.IOException; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.AFPGraphics2D; | |||
import org.apache.fop.afp.AFPPaintingState; | |||
import org.apache.fop.afp.fonts.AFPFont; | |||
@@ -77,7 +78,6 @@ public class AFPTextHandler implements FOPTextHandler { | |||
* @return a font reference | |||
*/ | |||
private int registerPageFont(AFPPageFonts pageFonts, String internalFontName, int fontSize) { | |||
FontInfo fontInfo = getFontInfo(); | |||
AFPFont afpFont = (AFPFont)fontInfo.getFonts().get(internalFontName); | |||
// register if necessary | |||
AFPFontAttributes afpFontAttributes = pageFonts.registerFont( | |||
@@ -101,37 +101,45 @@ public class AFPTextHandler implements FOPTextHandler { | |||
* {@inheritDoc} | |||
*/ | |||
public void drawString(Graphics2D g, String str, float x, float y) throws IOException { | |||
log.debug("drawString() str=" + str + ", x=" + x + ", y=" + y); | |||
AFPGraphics2D g2d = (AFPGraphics2D)g; | |||
GraphicsObject graphicsObj = g2d.getGraphicsObject(); | |||
Color color = g2d.getColor(); | |||
// set the color | |||
AFPPaintingState paintingState = g2d.getPaintingState(); | |||
if (paintingState.setColor(color)) { | |||
graphicsObj.setColor(color); | |||
if (log.isDebugEnabled()) { | |||
log.debug("drawString() str=" + str + ", x=" + x + ", y=" + y); | |||
} | |||
// set the character set | |||
int fontReference = 0; | |||
AFPPageFonts pageFonts = paintingState.getPageFonts(); | |||
if (overrideFont != null) { | |||
String internalFontName = overrideFont.getFontName(); | |||
int fontSize = overrideFont.getFontSize(); | |||
if (g instanceof AFPGraphics2D) { | |||
AFPGraphics2D g2d = (AFPGraphics2D)g; | |||
GraphicsObject graphicsObj = g2d.getGraphicsObject(); | |||
Color color = g2d.getColor(); | |||
// set the color | |||
AFPPaintingState paintingState = g2d.getPaintingState(); | |||
if (paintingState.setColor(color)) { | |||
graphicsObj.setColor(color); | |||
} | |||
// set the character set | |||
int fontReference = 0; | |||
int fontSize; | |||
String internalFontName; | |||
AFPPageFonts pageFonts = paintingState.getPageFonts(); | |||
if (overrideFont != null) { | |||
internalFontName = overrideFont.getFontName(); | |||
fontSize = overrideFont.getFontSize(); | |||
} else { | |||
java.awt.Font awtFont = g2d.getFont(); | |||
Font fopFont = fontInfo.getFontInstanceForAWTFont(awtFont); | |||
internalFontName = fopFont.getFontName(); | |||
fontSize = fopFont.getFontSize(); | |||
} | |||
fontSize = (int)Math.round( | |||
g2d.convertToAbsoluteLength(fontSize)); | |||
fontReference = registerPageFont(pageFonts, internalFontName, fontSize); | |||
graphicsObj.setCharacterSet(fontReference); | |||
// add the character string | |||
graphicsObj.addString(str, Math.round(x), Math.round(y)); | |||
} else { | |||
java.awt.Font awtFont = g2d.getFont(); | |||
// AffineTransform fontTransform = awtFont.getTransform(); | |||
FontInfo fontInfo = getFontInfo(); | |||
Font fopFont = fontInfo.getFontInstanceForAWTFont(awtFont); | |||
String internalFontName = fopFont.getFontName(); | |||
int fontSize = fopFont.getFontSize(); | |||
fontReference = registerPageFont(pageFonts, internalFontName, fontSize); | |||
//Inside Batik's SVG filter operations, you won't get an AFPGraphics2D | |||
g.drawString(str, x, y); | |||
} | |||
graphicsObj.setCharacterSet(fontReference); | |||
// add the character string | |||
graphicsObj.addString(str, Math.round(x), Math.round(y)); | |||
} | |||
/** |
@@ -19,6 +19,9 @@ | |||
package org.apache.fop.afp.svg; | |||
import java.awt.Graphics2D; | |||
import org.apache.fop.afp.AFPGraphics2D; | |||
import org.apache.fop.svg.AbstractFOPTextPainter; | |||
import org.apache.fop.svg.FOPTextHandler; | |||
@@ -41,4 +44,9 @@ public class AFPTextPainter extends AbstractFOPTextPainter { | |||
super(nativeTextHandler); | |||
} | |||
/** {@inheritDoc} */ | |||
protected boolean isSupportedGraphics2D(Graphics2D g2d) { | |||
return g2d instanceof AFPGraphics2D; | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
/* | |||
* 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.afp.util; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.fop.apps.FOUserAgent; | |||
/** | |||
* Default implementation of the {@link ResourceAccessor} interface for use inside FOP. | |||
*/ | |||
public class DefaultFOPResourceAccessor implements ResourceAccessor { | |||
private FOUserAgent userAgent; | |||
/** | |||
* Main constructor. | |||
* @param userAgent the FO user agent | |||
*/ | |||
public DefaultFOPResourceAccessor(FOUserAgent userAgent) { | |||
this.userAgent = userAgent; | |||
} | |||
/** {@inheritDoc} */ | |||
public InputStream createInputStream(URI uri) throws IOException { | |||
Source src = userAgent.resolveURI(uri.toASCIIString()); | |||
if (src == null) { | |||
return null; | |||
} else if (src instanceof StreamSource) { | |||
StreamSource ss = (StreamSource)src; | |||
InputStream in = ss.getInputStream(); | |||
return in; | |||
} else { | |||
return null; | |||
} | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
/* | |||
* 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.afp.util; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
/** | |||
* Defines an interface through which external resource objects can be accessed. | |||
*/ | |||
public interface ResourceAccessor { | |||
/** | |||
* Creates a new {@link InputStream} for the given URI that allows read access to an external | |||
* resource. | |||
* @param uri the URI of an external resource. | |||
* @return the new input stream | |||
* @throws IOException if an I/O error occurs while opening the resource | |||
*/ | |||
InputStream createInputStream(URI uri) throws IOException; | |||
} |
@@ -0,0 +1,58 @@ | |||
/* | |||
* 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.afp.util; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.net.URL; | |||
/** | |||
* Simple implementation of the {@link ResourceAccessor} interface for access via files. | |||
*/ | |||
public class SimpleResourceAccessor implements ResourceAccessor { | |||
private URI baseURI; | |||
/** | |||
* Creates a new simple resource accessor. | |||
* @param basePath the base path to resolve relative URIs to | |||
*/ | |||
public SimpleResourceAccessor(File basePath) { | |||
this.baseURI = basePath.toURI(); | |||
} | |||
/** | |||
* Creates a new simple resource accessor. | |||
* @param basePath the base path to resolve relative URIs to | |||
*/ | |||
public SimpleResourceAccessor(String basePath) { | |||
this(new File(basePath)); | |||
} | |||
/** {@inheritDoc} */ | |||
public InputStream createInputStream(URI uri) throws IOException { | |||
URI resolved = this.baseURI.resolve(uri); | |||
URL url = resolved.toURL(); | |||
return url.openStream(); | |||
} | |||
} |
@@ -46,6 +46,7 @@ import org.apache.fop.fo.FOEventHandler; | |||
import org.apache.fop.render.Renderer; | |||
import org.apache.fop.render.RendererFactory; | |||
import org.apache.fop.render.XMLHandlerRegistry; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
/** | |||
* This is the user agent for FOP. | |||
@@ -92,6 +93,7 @@ public class FOUserAgent { | |||
private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; | |||
private Map rendererOptions = new java.util.HashMap(); | |||
private File outputFile = null; | |||
private IFDocumentHandler documentHandlerOverride = null; | |||
private Renderer rendererOverride = null; | |||
private FOEventHandler foEventHandlerOverride = null; | |||
private boolean locatorEnabled = true; // true by default (for error messages). | |||
@@ -116,6 +118,8 @@ public class FOUserAgent { | |||
protected String author = null; | |||
/** Title of the document. */ | |||
protected String title = null; | |||
/** Subject of the document. */ | |||
protected String subject = null; | |||
/** Set of keywords applicable to this document. */ | |||
protected String keywords = null; | |||
@@ -158,6 +162,24 @@ public class FOUserAgent { | |||
// ---------------------------------------------- rendering-run dependent stuff | |||
/** | |||
* Sets an explicit document handler to use which overrides the one that would be | |||
* selected by default. | |||
* @param documentHandler the document handler instance to use | |||
*/ | |||
public void setDocumentHandlerOverride(IFDocumentHandler documentHandler) { | |||
this.documentHandlerOverride = documentHandler; | |||
} | |||
/** | |||
* Returns the overriding {@link IFDocumentHandler} instance, if any. | |||
* @return the overriding document handler or null | |||
*/ | |||
public IFDocumentHandler getDocumentHandlerOverride() { | |||
return this.documentHandlerOverride; | |||
} | |||
/** | |||
* Sets an explicit renderer to use which overrides the one defined by the | |||
* render type setting. | |||
@@ -273,6 +295,22 @@ public class FOUserAgent { | |||
return title; | |||
} | |||
/** | |||
* Sets the subject of the document. | |||
* @param subject of document | |||
*/ | |||
public void setSubject(String subject) { | |||
this.subject = subject; | |||
} | |||
/** | |||
* Returns the subject of the document | |||
* @return the subject | |||
*/ | |||
public String getSubject() { | |||
return subject; | |||
} | |||
/** | |||
* Sets the keywords for the document. | |||
* @param keywords for the document |
@@ -47,6 +47,7 @@ import org.apache.fop.fonts.FontCache; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.hyphenation.HyphenationTreeResolver; | |||
import org.apache.fop.layoutmgr.LayoutManagerMaker; | |||
import org.apache.fop.render.ImageHandlerRegistry; | |||
import org.apache.fop.render.RendererFactory; | |||
import org.apache.fop.render.XMLHandlerRegistry; | |||
import org.apache.fop.util.ColorSpaceCache; | |||
@@ -69,6 +70,9 @@ public class FopFactory implements ImageContext { | |||
/** Registry for XML handlers */ | |||
private XMLHandlerRegistry xmlHandlers; | |||
/** Registry for image handlers */ | |||
private ImageHandlerRegistry imageHandlers; | |||
/** The registry for ElementMapping instances */ | |||
private ElementMappingRegistry elementMappingRegistry; | |||
@@ -156,6 +160,7 @@ public class FopFactory implements ImageContext { | |||
this.imageManager = new ImageManager(this); | |||
this.rendererFactory = new RendererFactory(); | |||
this.xmlHandlers = new XMLHandlerRegistry(); | |||
this.imageHandlers = new ImageHandlerRegistry(); | |||
this.ignoredNamespaces = new java.util.HashSet(); | |||
} | |||
@@ -276,6 +281,11 @@ public class FopFactory implements ImageContext { | |||
return this.xmlHandlers; | |||
} | |||
/** @return the image handler registry */ | |||
public ImageHandlerRegistry getImageHandlerRegistry() { | |||
return this.imageHandlers; | |||
} | |||
/** @return the element mapping registry */ | |||
public ElementMappingRegistry getElementMappingRegistry() { | |||
return this.elementMappingRegistry; |
@@ -30,5 +30,6 @@ public interface MimeConstants extends org.apache.xmlgraphics.util.MimeConstants | |||
String MIME_FOP_PRINT = "application/X-fop-print"; | |||
/** Apache FOP's area tree XML */ | |||
String MIME_FOP_AREA_TREE = "application/X-fop-areatree"; | |||
/** Apache FOP's intermediate format XML */ | |||
String MIME_FOP_IF = "application/X-fop-intermediate-format"; | |||
} |
@@ -36,8 +36,23 @@ import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.sax.SAXTransformerFactory; | |||
import javax.xml.transform.sax.TransformerHandler; | |||
import org.w3c.dom.DOMImplementation; | |||
import org.w3c.dom.Document; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.image.loader.ImageInfo; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.xmlgraphics.image.loader.ImageSessionContext; | |||
import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.area.Trait.Background; | |||
import org.apache.fop.area.Trait.InternalLink; | |||
@@ -65,16 +80,7 @@ import org.apache.fop.util.ContentHandlerFactory; | |||
import org.apache.fop.util.ContentHandlerFactoryRegistry; | |||
import org.apache.fop.util.ConversionUtils; | |||
import org.apache.fop.util.DefaultErrorListener; | |||
import org.apache.xmlgraphics.image.loader.ImageInfo; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.xmlgraphics.image.loader.ImageSessionContext; | |||
import org.apache.xmlgraphics.util.QName; | |||
import org.w3c.dom.DOMImplementation; | |||
import org.w3c.dom.Document; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
import org.apache.fop.util.XMLUtil; | |||
/** | |||
* This is a parser for the area tree XML (intermediate format) which is used to reread an area | |||
@@ -245,7 +251,7 @@ public class AreaTreeParser { | |||
delegate.startDocument(); | |||
delegate.startElement(uri, localName, qName, attributes); | |||
} else { | |||
lastAttributes = attributes; | |||
lastAttributes = new AttributesImpl(attributes); | |||
boolean handled = true; | |||
if ("".equals(uri)) { | |||
Maker maker = (Maker)makers.get(localName); | |||
@@ -381,12 +387,12 @@ public class AreaTreeParser { | |||
if (currentPageViewport != null) { | |||
throw new IllegalStateException("currentPageViewport must be null"); | |||
} | |||
Rectangle2D viewArea = getAttributeAsRectangle2D(attributes, "bounds"); | |||
int pageNumber = getAttributeAsInteger(attributes, "nr", -1); | |||
Rectangle2D viewArea = XMLUtil.getAttributeAsRectangle2D(attributes, "bounds"); | |||
int pageNumber = XMLUtil.getAttributeAsInt(attributes, "nr", -1); | |||
String key = attributes.getValue("key"); | |||
String pageNumberString = attributes.getValue("formatted-nr"); | |||
String pageMaster = attributes.getValue("simple-page-master-name"); | |||
boolean blank = getAttributeAsBoolean(attributes, "blank", false); | |||
boolean blank = XMLUtil.getAttributeAsBoolean(attributes, "blank", false); | |||
currentPageViewport = new PageViewport(viewArea, | |||
pageNumber, pageNumberString, | |||
pageMaster, blank); | |||
@@ -417,10 +423,10 @@ public class AreaTreeParser { | |||
if (rv != null) { | |||
throw new IllegalStateException("Current RegionViewport must be null"); | |||
} | |||
Rectangle2D viewArea = getAttributeAsRectangle2D(attributes, "rect"); | |||
Rectangle2D viewArea = XMLUtil.getAttributeAsRectangle2D(attributes, "rect"); | |||
rv = new RegionViewport(viewArea); | |||
transferForeignObjects(attributes, rv); | |||
rv.setClip(getAttributeAsBoolean(attributes, "clipped", false)); | |||
rv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false)); | |||
setAreaAttributes(attributes, rv); | |||
setTraits(attributes, rv, SUBSET_COMMON); | |||
setTraits(attributes, rv, SUBSET_BOX); | |||
@@ -485,14 +491,15 @@ public class AreaTreeParser { | |||
throw new IllegalStateException("Current BodyRegion must be null"); | |||
} | |||
String regionName = attributes.getValue("name"); | |||
int columnCount = getAttributeAsInteger(attributes, "columnCount", 1); | |||
int columnGap = getAttributeAsInteger(attributes, "columnGap", 0); | |||
int columnCount = XMLUtil.getAttributeAsInt(attributes, "columnCount", 1); | |||
int columnGap = XMLUtil.getAttributeAsInt(attributes, "columnGap", 0); | |||
RegionViewport rv = getCurrentRegionViewport(); | |||
body = new BodyRegion(Constants.FO_REGION_BODY, | |||
regionName, rv, columnCount, columnGap); | |||
transferForeignObjects(attributes, body); | |||
body.setCTM(getAttributeAsCTM(attributes, "ctm")); | |||
setAreaAttributes(attributes, body); | |||
setTraits(attributes, body, SUBSET_BORDER_PADDING); | |||
rv.setRegionReference(body); | |||
currentPageViewport.getPage().setRegionViewport( | |||
Constants.FO_REGION_BODY, rv); | |||
@@ -537,8 +544,8 @@ public class AreaTreeParser { | |||
private class SpanMaker extends AbstractMaker { | |||
public void startElement(Attributes attributes) { | |||
int ipd = getAttributeAsInteger(attributes, "ipd", 0); | |||
int columnCount = getAttributeAsInteger(attributes, "columnCount", 1); | |||
int ipd = XMLUtil.getAttributeAsInt(attributes, "ipd", 0); | |||
int columnCount = XMLUtil.getAttributeAsInt(attributes, "columnCount", 1); | |||
BodyRegion body = getCurrentBodyRegion(); | |||
Span span = new Span(columnCount, | |||
body.getColumnGap(), ipd); | |||
@@ -554,7 +561,7 @@ public class AreaTreeParser { | |||
public void startElement(Attributes attributes) { | |||
Footnote fn = getCurrentBodyRegion().getFootnote(); | |||
transferForeignObjects(attributes, fn); | |||
fn.setTop(getAttributeAsInteger(attributes, "top-offset", 0)); | |||
fn.setTop(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0)); | |||
areaStack.push(fn); | |||
} | |||
@@ -579,18 +586,18 @@ public class AreaTreeParser { | |||
private class BlockMaker extends AbstractMaker { | |||
public void startElement(Attributes attributes) { | |||
boolean isViewport = getAttributeAsBoolean(attributes, | |||
boolean isViewport = XMLUtil.getAttributeAsBoolean(attributes, | |||
"is-viewport-area", false); | |||
Block block; | |||
if (isViewport) { | |||
BlockViewport bv = new BlockViewport(); | |||
bv.setClip(getAttributeAsBoolean(attributes, "clipped", false)); | |||
bv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false)); | |||
bv.setCTM(getAttributeAsCTM(attributes, "ctm")); | |||
if (bv.getPositioning() != BlockViewport.RELATIVE) { | |||
bv.setXOffset( | |||
getAttributeAsInteger(attributes, "left-position", 0)); | |||
XMLUtil.getAttributeAsInt(attributes, "left-position", 0)); | |||
bv.setYOffset( | |||
getAttributeAsInteger(attributes, "top-position", 0)); | |||
XMLUtil.getAttributeAsInt(attributes, "top-position", 0)); | |||
} | |||
block = bv; | |||
} else { | |||
@@ -607,10 +614,10 @@ public class AreaTreeParser { | |||
block.setPositioning(Block.STACK); | |||
} | |||
if (attributes.getValue("left-offset") != null) { | |||
block.setXOffset(getAttributeAsInteger(attributes, "left-offset", 0)); | |||
block.setXOffset(XMLUtil.getAttributeAsInt(attributes, "left-offset", 0)); | |||
} | |||
if (attributes.getValue("top-offset") != null) { | |||
block.setYOffset(getAttributeAsInteger(attributes, "top-offset", 0)); | |||
block.setYOffset(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0)); | |||
} | |||
transferForeignObjects(attributes, block); | |||
setAreaAttributes(attributes, block); | |||
@@ -652,7 +659,7 @@ public class AreaTreeParser { | |||
public void startElement(Attributes attributes) { | |||
InlineArea inl = new InlineArea(); | |||
transferForeignObjects(attributes, inl); | |||
inl.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||
inl.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||
setAreaAttributes(attributes, inl); | |||
setTraits(attributes, inl, SUBSET_COMMON); | |||
setTraits(attributes, inl, SUBSET_BOX); | |||
@@ -672,7 +679,7 @@ public class AreaTreeParser { | |||
public void startElement(Attributes attributes) { | |||
InlineParent ip = new InlineParent(); | |||
transferForeignObjects(attributes, ip); | |||
ip.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||
ip.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||
setAreaAttributes(attributes, ip); | |||
setTraits(attributes, ip, SUBSET_COMMON); | |||
setTraits(attributes, ip, SUBSET_BOX); | |||
@@ -693,7 +700,7 @@ public class AreaTreeParser { | |||
public void startElement(Attributes attributes) { | |||
InlineBlockParent ibp = new InlineBlockParent(); | |||
transferForeignObjects(attributes, ibp); | |||
ibp.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||
ibp.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||
setAreaAttributes(attributes, ibp); | |||
setTraits(attributes, ibp, SUBSET_COMMON); | |||
setTraits(attributes, ibp, SUBSET_BOX); | |||
@@ -720,11 +727,11 @@ public class AreaTreeParser { | |||
setTraits(attributes, text, SUBSET_BOX); | |||
setTraits(attributes, text, SUBSET_COLOR); | |||
setTraits(attributes, text, SUBSET_FONT); | |||
text.setBaselineOffset(getAttributeAsInteger(attributes, "baseline", 0)); | |||
text.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||
text.setTextLetterSpaceAdjust(getAttributeAsInteger(attributes, | |||
text.setBaselineOffset(XMLUtil.getAttributeAsInt(attributes, "baseline", 0)); | |||
text.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||
text.setTextLetterSpaceAdjust(XMLUtil.getAttributeAsInt(attributes, | |||
"tlsadjust", 0)); | |||
text.setTextWordSpaceAdjust(getAttributeAsInteger(attributes, | |||
text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes, | |||
"twsadjust", 0)); | |||
Area parent = (Area)areaStack.peek(); | |||
parent.addChildArea(text); | |||
@@ -739,7 +746,7 @@ public class AreaTreeParser { | |||
private class WordMaker extends AbstractMaker { | |||
public void endElement() { | |||
int offset = getAttributeAsInteger(lastAttributes, "offset", 0); | |||
int offset = XMLUtil.getAttributeAsInt(lastAttributes, "offset", 0); | |||
int[] letterAdjust | |||
= ConversionUtils.toIntArray( | |||
lastAttributes.getValue("letter-adjust"), "\\s"); | |||
@@ -758,11 +765,11 @@ public class AreaTreeParser { | |||
private class SpaceMaker extends AbstractMaker { | |||
public void endElement() { | |||
int offset = getAttributeAsInteger(lastAttributes, "offset", 0); | |||
int offset = XMLUtil.getAttributeAsInt(lastAttributes, "offset", 0); | |||
//TODO the isAdjustable parameter is currently not used/implemented | |||
if (content.position() > 0) { | |||
content.flip(); | |||
boolean adjustable = getAttributeAsBoolean(lastAttributes, "adj", true); | |||
boolean adjustable = XMLUtil.getAttributeAsBoolean(lastAttributes, "adj", true); | |||
SpaceArea space = new SpaceArea(content.charAt(0), offset, adjustable); | |||
AbstractTextArea text = getCurrentText(); | |||
space.setParentArea(text); | |||
@@ -794,13 +801,13 @@ public class AreaTreeParser { | |||
setTraits(attributes, leader, SUBSET_BOX); | |||
setTraits(attributes, leader, SUBSET_COLOR); | |||
setTraits(attributes, leader, SUBSET_FONT); | |||
leader.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||
leader.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||
String ruleStyle = attributes.getValue("ruleStyle"); | |||
if (ruleStyle != null) { | |||
leader.setRuleStyle(ruleStyle); | |||
} | |||
leader.setRuleThickness( | |||
getAttributeAsInteger(attributes, "ruleThickness", 0)); | |||
XMLUtil.getAttributeAsInt(attributes, "ruleThickness", 0)); | |||
Area parent = (Area)areaStack.peek(); | |||
parent.addChildArea(leader); | |||
} | |||
@@ -815,9 +822,9 @@ public class AreaTreeParser { | |||
setTraits(attributes, viewport, SUBSET_COMMON); | |||
setTraits(attributes, viewport, SUBSET_BOX); | |||
setTraits(attributes, viewport, SUBSET_COLOR); | |||
viewport.setContentPosition(getAttributeAsRectangle2D(attributes, "pos")); | |||
viewport.setClip(getAttributeAsBoolean(attributes, "clip", false)); | |||
viewport.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||
viewport.setContentPosition(XMLUtil.getAttributeAsRectangle2D(attributes, "pos")); | |||
viewport.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clip", false)); | |||
viewport.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||
Area parent = (Area)areaStack.peek(); | |||
parent.addChildArea(viewport); | |||
areaStack.push(viewport); | |||
@@ -884,7 +891,8 @@ public class AreaTreeParser { | |||
public void startElement(Attributes attributes) { | |||
String title = attributes.getValue("title"); | |||
boolean showChildren = getAttributeAsBoolean(attributes, "show-children", false); | |||
boolean showChildren = XMLUtil.getAttributeAsBoolean( | |||
attributes, "show-children", false); | |||
String[] linkdata | |||
= InternalLink.parseXMLAttribute(attributes.getValue("internal-link")); | |||
PageViewport pv = (PageViewport) pageViewportsByKey.get(linkdata[0]); | |||
@@ -933,6 +941,7 @@ public class AreaTreeParser { | |||
transferForeignObjects(attributes, reg); | |||
reg.setCTM(getAttributeAsCTM(attributes, "ctm")); | |||
setAreaAttributes(attributes, reg); | |||
setTraits(attributes, reg, SUBSET_BORDER_PADDING); | |||
rv.setRegionReference(reg); | |||
currentPageViewport.getPage().setRegionViewport( | |||
side, rv); | |||
@@ -987,6 +996,9 @@ public class AreaTreeParser { | |||
Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END, | |||
Trait.START_INDENT, Trait.END_INDENT, | |||
Trait.IS_REFERENCE_AREA, Trait.IS_VIEWPORT_AREA}; | |||
private static final Object[] SUBSET_BORDER_PADDING = new Object[] { | |||
Trait.BORDER_BEFORE, Trait.BORDER_AFTER, Trait.BORDER_START, Trait.BORDER_END, | |||
Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END}; | |||
private void setTraits(Attributes attributes, Area area, Object[] traitSubset) { | |||
for (int i = traitSubset.length; --i >= 0;) { | |||
@@ -1044,9 +1056,9 @@ public class AreaTreeParser { | |||
if (repeat != null) { | |||
bkg.setRepeat(repeat); | |||
} | |||
bkg.setHoriz(getAttributeAsInteger(attributes, | |||
bkg.setHoriz(XMLUtil.getAttributeAsInt(attributes, | |||
"bkg-horz-offset", 0)); | |||
bkg.setVertical(getAttributeAsInteger(attributes, | |||
bkg.setVertical(XMLUtil.getAttributeAsInt(attributes, | |||
"bkg-vert-offset", 0)); | |||
} | |||
area.addTrait(trait, bkg); | |||
@@ -1058,7 +1070,7 @@ public class AreaTreeParser { | |||
String fontName = attributes.getValue("font-name"); | |||
if (fontName != null) { | |||
String fontStyle = attributes.getValue("font-style"); | |||
int fontWeight = getAttributeAsInteger( | |||
int fontWeight = XMLUtil.getAttributeAsInt( | |||
attributes, "font-weight", Font.WEIGHT_NORMAL); | |||
area.addTrait(trait, | |||
FontInfo.createFontKey(fontName, fontStyle, fontWeight)); | |||
@@ -1068,26 +1080,6 @@ public class AreaTreeParser { | |||
} | |||
} | |||
private static boolean getAttributeAsBoolean(Attributes attributes, String name, | |||
boolean defaultValue) { | |||
String s = attributes.getValue(name); | |||
if (s == null) { | |||
return defaultValue; | |||
} else { | |||
return Boolean.valueOf(s).booleanValue(); | |||
} | |||
} | |||
private static int getAttributeAsInteger(Attributes attributes, String name, | |||
int defaultValue) { | |||
String s = attributes.getValue(name); | |||
if (s == null) { | |||
return defaultValue; | |||
} else { | |||
return Integer.parseInt(s); | |||
} | |||
} | |||
private static CTM getAttributeAsCTM(Attributes attributes, String name) { | |||
String s = attributes.getValue(name).trim(); | |||
if (s.startsWith("[") && s.endsWith("]")) { | |||
@@ -1102,15 +1094,6 @@ public class AreaTreeParser { | |||
} | |||
} | |||
private static Rectangle2D getAttributeAsRectangle2D(Attributes attributes, String name) { | |||
String s = attributes.getValue(name).trim(); | |||
double[] values = ConversionUtils.toDoubleArray(s, "\\s"); | |||
if (values.length != 4) { | |||
throw new IllegalArgumentException("Rectangle must consist of 4 double values!"); | |||
} | |||
return new Rectangle2D.Double(values[0], values[1], values[2], values[3]); | |||
} | |||
private static void transferForeignObjects(Attributes atts, AreaTreeObject ato) { | |||
for (int i = 0, c = atts.getLength(); i < c; i++) { | |||
String ns = atts.getURI(i); |
@@ -128,8 +128,10 @@ public class Page extends AreaTreeObject implements Serializable, Cloneable { | |||
} | |||
// set borders and padding traits | |||
// (a little extensions wrt what prescribed by the specs at 6.4.14) | |||
TraitSetter.addBorders(rr, r.getCommonBorderPaddingBackground(), false, false, false, false, null); | |||
TraitSetter.addPadding(rr, r.getCommonBorderPaddingBackground(), false, false, false, false, null); | |||
TraitSetter.addBorders(rr, r.getCommonBorderPaddingBackground(), | |||
false, false, false, false, null); | |||
TraitSetter.addPadding(rr, r.getCommonBorderPaddingBackground(), | |||
false, false, false, false, null); | |||
setRegionReferencePosition(rr, r, rvp.getViewArea()); | |||
rvp.setRegionReference(rr); | |||
setRegionViewport(r.getNameId(), rvp); | |||
@@ -182,8 +184,12 @@ public class Page extends AreaTreeObject implements Serializable, Cloneable { | |||
FODimension reldims = new FODimension(0, 0); | |||
rr.setCTM(CTM.getCTMandRelDims(r.getReferenceOrientation(), | |||
r.getWritingMode(), absRegVPRect, reldims)); | |||
rr.setIPD(reldims.ipd); | |||
rr.setBPD(reldims.bpd); | |||
rr.setIPD(reldims.ipd | |||
- rr.getBorderAndPaddingWidthStart() | |||
- rr.getBorderAndPaddingWidthEnd()); | |||
rr.setBPD(reldims.bpd | |||
- rr.getBorderAndPaddingWidthBefore() | |||
- rr.getBorderAndPaddingWidthAfter()); | |||
} | |||
/** |
@@ -73,18 +73,6 @@ public class RegionReference extends Area implements Cloneable { | |||
blocks.add(child); | |||
} | |||
/** {@inheritDoc} */ | |||
public int getBPD() { | |||
// subtract bpd of borders and padding before / after | |||
return super.getBPD() - getBorderAndPaddingWidthBefore() - getBorderAndPaddingWidthAfter(); | |||
} | |||
/** {@inheritDoc} */ | |||
public int getIPD() { | |||
// subtract ipd of borders and padding start / end | |||
return super.getIPD() - getBorderAndPaddingWidthStart() - getBorderAndPaddingWidthEnd(); | |||
} | |||
/** | |||
* Set the Coordinate Transformation Matrix which transforms content | |||
* coordinates in this region reference area which are specified in |
@@ -26,16 +26,17 @@ import java.util.Vector; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.sax.SAXResult; | |||
import org.xml.sax.SAXException; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.area.AreaTreeModel; | |||
import org.apache.fop.area.AreaTreeParser; | |||
import org.apache.fop.area.RenderPagesModel; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.xml.sax.SAXException; | |||
/** | |||
* InputHandler for the area tree XML (intermediate format) as input. | |||
* InputHandler for the area tree XML (the old intermediate format) as input. | |||
*/ | |||
public class AreaTreeInputHandler extends InputHandler { | |||
@@ -30,8 +30,11 @@ import java.util.Vector; | |||
import javax.swing.UIManager; | |||
import org.xml.sax.SAXException; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.Version; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
@@ -43,12 +46,12 @@ import org.apache.fop.pdf.PDFEncryptionParams; | |||
import org.apache.fop.pdf.PDFXMode; | |||
import org.apache.fop.render.Renderer; | |||
import org.apache.fop.render.awt.AWTRenderer; | |||
import org.apache.fop.render.intermediate.IFRenderer; | |||
import org.apache.fop.render.pdf.PDFRenderer; | |||
import org.apache.fop.render.print.PagesMode; | |||
import org.apache.fop.render.print.PrintRenderer; | |||
import org.apache.fop.render.xml.XMLRenderer; | |||
import org.apache.fop.util.CommandLineLogger; | |||
import org.xml.sax.SAXException; | |||
/** | |||
* Options parses the commandline arguments | |||
@@ -70,8 +73,10 @@ public class CommandLineOptions { | |||
public static final int XSLT_INPUT = 2; | |||
/** input: Area Tree XML file */ | |||
public static final int AREATREE_INPUT = 3; | |||
/** input: Intermediate Format XML file */ | |||
public static final int IF_INPUT = 4; | |||
/** input: Image file */ | |||
public static final int IMAGE_INPUT = 4; | |||
public static final int IMAGE_INPUT = 5; | |||
/* show configuration information */ | |||
private Boolean showConfiguration = Boolean.FALSE; | |||
@@ -87,6 +92,8 @@ public class CommandLineOptions { | |||
private File xmlfile = null; | |||
/* area tree input file */ | |||
private File areatreefile = null; | |||
/* intermediate format input file */ | |||
private File iffile = null; | |||
/* area tree input file */ | |||
private File imagefile = null; | |||
/* output file */ | |||
@@ -200,6 +207,13 @@ public class CommandLineOptions { | |||
//Make sure the prepared XMLRenderer is used | |||
foUserAgent.setRendererOverride(xmlRenderer); | |||
} else if (MimeConstants.MIME_FOP_IF.equals(outputmode)) { | |||
// render from FO to Intermediate Format | |||
IFRenderer xml2Renderer = new IFRenderer(); | |||
xml2Renderer.setUserAgent(foUserAgent); | |||
//Make sure the prepared IFRenderer is used | |||
foUserAgent.setRendererOverride(xml2Renderer); | |||
} | |||
return true; | |||
} | |||
@@ -266,6 +280,8 @@ public class CommandLineOptions { | |||
i = i + parseXMLInputOption(args, i); | |||
} else if (args[i].equals("-atin")) { | |||
i = i + parseAreaTreeInputOption(args, i); | |||
} else if (args[i].equals("-ifin")) { | |||
i = i + parseIFInputOption(args, i); | |||
} else if (args[i].equals("-imagein")) { | |||
i = i + parseImageInputOption(args, i); | |||
} else if (args[i].equals("-awt")) { | |||
@@ -309,6 +325,8 @@ public class CommandLineOptions { | |||
i = i + parseCustomOutputOption(args, i); | |||
} else if (args[i].equals("-at")) { | |||
i = i + parseAreaTreeOption(args, i); | |||
} else if (args[i].equals("-if")) { | |||
i = i + parseIntermediateFormatOption(args, i); | |||
} else if (args[i].equals("-v")) { | |||
printVersion(); | |||
return false; | |||
@@ -377,7 +395,7 @@ public class CommandLineOptions { | |||
} | |||
private int parseFOInputOption(String[] args, int i) throws FOPException { | |||
inputmode = FO_INPUT; | |||
setInputFormat(FO_INPUT); | |||
if ((i + 1 == args.length) | |||
|| (isOption(args[i + 1]))) { | |||
throw new FOPException("you must specify the fo file for the '-fo' option"); | |||
@@ -393,7 +411,7 @@ public class CommandLineOptions { | |||
} | |||
private int parseXSLInputOption(String[] args, int i) throws FOPException { | |||
inputmode = XSLT_INPUT; | |||
setInputFormat(XSLT_INPUT); | |||
if ((i + 1 == args.length) | |||
|| (isOption(args[i + 1]))) { | |||
throw new FOPException("you must specify the stylesheet " | |||
@@ -405,7 +423,7 @@ public class CommandLineOptions { | |||
} | |||
private int parseXMLInputOption(String[] args, int i) throws FOPException { | |||
inputmode = XSLT_INPUT; | |||
setInputFormat(XSLT_INPUT); | |||
if ((i + 1 == args.length) | |||
|| (isOption(args[i + 1]))) { | |||
throw new FOPException("you must specify the input file " | |||
@@ -676,8 +694,25 @@ public class CommandLineOptions { | |||
} | |||
} | |||
private int parseIntermediateFormatOption(String[] args, int i) throws FOPException { | |||
setOutputMode(MimeConstants.MIME_FOP_IF); | |||
if ((i + 1 == args.length) | |||
|| (args[i + 1].charAt(0) == '-')) { | |||
throw new FOPException("you must specify the intermediate format output file"); | |||
} else if ((i + 2 == args.length) | |||
|| (args[i + 2].charAt(0) == '-')) { | |||
// only output file is specified | |||
outfile = new File(args[i + 1]); | |||
return 1; | |||
} else { | |||
// mimic format and output file have been specified | |||
outfile = new File(args[i + 2]); | |||
return 2; | |||
} | |||
} | |||
private int parseAreaTreeInputOption(String[] args, int i) throws FOPException { | |||
inputmode = AREATREE_INPUT; | |||
setInputFormat(AREATREE_INPUT); | |||
if ((i + 1 == args.length) | |||
|| (isOption(args[i + 1]))) { | |||
throw new FOPException("you must specify the Area Tree file for the '-atin' option"); | |||
@@ -692,8 +727,24 @@ public class CommandLineOptions { | |||
} | |||
} | |||
private int parseIFInputOption(String[] args, int i) throws FOPException { | |||
setInputFormat(IF_INPUT); | |||
if ((i + 1 == args.length) | |||
|| (isOption(args[i + 1]))) { | |||
throw new FOPException("you must specify the intermediate file for the '-ifin' option"); | |||
} else { | |||
String filename = args[i + 1]; | |||
if (isSystemInOutFile(filename)) { | |||
this.useStdIn = true; | |||
} else { | |||
iffile = new File(filename); | |||
} | |||
return 1; | |||
} | |||
} | |||
private int parseImageInputOption(String[] args, int i) throws FOPException { | |||
inputmode = IMAGE_INPUT; | |||
setInputFormat(IMAGE_INPUT); | |||
if ((i + 1 == args.length) | |||
|| (isOption(args[i + 1]))) { | |||
throw new FOPException("you must specify the image file for the '-imagein' option"); | |||
@@ -800,6 +851,14 @@ public class CommandLineOptions { | |||
} | |||
} | |||
private void setInputFormat(int format) throws FOPException { | |||
if (inputmode == NOT_SET || inputmode == format) { | |||
inputmode = format; | |||
} else { | |||
throw new FOPException("Only one input mode can be specified!"); | |||
} | |||
} | |||
/** | |||
* checks whether all necessary information has been given in a consistent way | |||
*/ | |||
@@ -854,11 +913,6 @@ public class CommandLineOptions { | |||
throw new FOPException( | |||
"FO output mode is only available if you use -xml and -xsl"); | |||
} | |||
if (xmlfile != null || xsltfile != null) { | |||
log.warn("fo input mode, but xmlfile or xslt file are set:"); | |||
log.error("xml file: " + xmlfile); | |||
log.error("xslt file: " + xsltfile); | |||
} | |||
if (fofile != null && !fofile.exists()) { | |||
throw new FileNotFoundException("Error: fo file " | |||
+ fofile.getAbsolutePath() | |||
@@ -872,24 +926,31 @@ public class CommandLineOptions { | |||
throw new FOPException( | |||
"Area Tree Output is not available if Area Tree is used as input!"); | |||
} | |||
if (xmlfile != null || xsltfile != null) { | |||
log.warn("area tree input mode, but xmlfile or xslt file are set:"); | |||
log.error("xml file: " + xmlfile); | |||
log.error("xslt file: " + xsltfile); | |||
} | |||
if (areatreefile != null && !areatreefile.exists()) { | |||
throw new FileNotFoundException("Error: area tree file " | |||
+ areatreefile.getAbsolutePath() | |||
+ " not found "); | |||
} | |||
} else if (inputmode == IMAGE_INPUT) { | |||
} else if (inputmode == IF_INPUT) { | |||
if (outputmode.equals(MimeConstants.MIME_XSL_FO)) { | |||
throw new FOPException( | |||
"FO output mode is only available if you use -xml and -xsl"); | |||
} else if (outputmode.equals(MimeConstants.MIME_FOP_AREA_TREE)) { | |||
throw new FOPException( | |||
"Area Tree Output is not available if Intermediate Format is used as input!"); | |||
} else if (outputmode.equals(MimeConstants.MIME_FOP_IF)) { | |||
throw new FOPException( | |||
"Intermediate Output is not available if Intermediate Format is used as input!"); | |||
} | |||
if (xmlfile != null) { | |||
log.warn("image input mode, but XML file is set:"); | |||
log.error("XML file: " + xmlfile.toString()); | |||
if (iffile != null && !iffile.exists()) { | |||
throw new FileNotFoundException("Error: intermediate format file " | |||
+ iffile.getAbsolutePath() | |||
+ " not found "); | |||
} | |||
} else if (inputmode == IMAGE_INPUT) { | |||
if (outputmode.equals(MimeConstants.MIME_XSL_FO)) { | |||
throw new FOPException( | |||
"FO output mode is only available if you use -xml and -xsl"); | |||
} | |||
if (imagefile != null && !imagefile.exists()) { | |||
throw new FileNotFoundException("Error: image file " | |||
@@ -940,6 +1001,8 @@ public class CommandLineOptions { | |||
return new InputHandler(fofile); | |||
case AREATREE_INPUT: | |||
return new AreaTreeInputHandler(areatreefile); | |||
case IF_INPUT: | |||
return new IFInputHandler(iffile); | |||
case XSLT_INPUT: | |||
return new InputHandler(xmlfile, xsltfile, xsltParams); | |||
case IMAGE_INPUT: | |||
@@ -1074,6 +1137,7 @@ public class CommandLineOptions { | |||
+ " -fo infile xsl:fo input file \n" | |||
+ " -xml infile xml input file, must be used together with -xsl \n" | |||
+ " -atin infile area tree input file \n" | |||
+ " -ifin infile intermediate format input file \n" | |||
+ " -imagein infile image input file (piping through stdin not supported)\n" | |||
+ " -xsl stylesheet xslt stylesheet \n \n" | |||
+ " -param name value <value> to use for parameter <name> in xslt stylesheet\n" | |||
@@ -1095,6 +1159,7 @@ public class CommandLineOptions { | |||
+ " -at [mime] out representation of area tree as XML (outfile req'd) \n" | |||
+ " specify optional mime output to allow AT to be converted\n" | |||
+ " to final format later\n" | |||
+ " -if out representation of area tree as intermediate format XML (outfile req'd)\n" | |||
+ " -print input file will be rendered and sent to the printer \n" | |||
+ " see options with \"-print help\" \n" | |||
+ " -out mime outfile input will be rendered using the given MIME type\n" | |||
@@ -1159,6 +1224,30 @@ public class CommandLineOptions { | |||
} | |||
log.info("xslt stylesheet: " + xsltfile.toString()); | |||
break; | |||
case AREATREE_INPUT: | |||
log.info("AT "); | |||
if (this.useStdIn) { | |||
log.info("area tree input file: from stdin"); | |||
} else { | |||
log.info("area tree input file: " + areatreefile.toString()); | |||
} | |||
break; | |||
case IF_INPUT: | |||
log.info("IF "); | |||
if (this.useStdIn) { | |||
log.info("intermediate input file: from stdin"); | |||
} else { | |||
log.info("intermediate input file: " + iffile.toString()); | |||
} | |||
break; | |||
case IMAGE_INPUT: | |||
log.info("Image "); | |||
if (this.useStdIn) { | |||
log.info("image input file: from stdin"); | |||
} else { | |||
log.info("image input file: " + imagefile.toString()); | |||
} | |||
break; | |||
default: | |||
log.info("unknown input type"); | |||
} | |||
@@ -1187,6 +1276,9 @@ public class CommandLineOptions { | |||
} else { | |||
log.info("output file: " + outfile.toString()); | |||
} | |||
} else if (MimeConstants.MIME_FOP_IF.equals(outputmode)) { | |||
log.info("intermediate format"); | |||
log.info("output file: " + outfile.toString()); | |||
} else { | |||
log.info(outputmode); | |||
if (this.useStdOut) { |
@@ -0,0 +1,83 @@ | |||
/* | |||
* 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.cli; | |||
import java.io.File; | |||
import java.io.OutputStream; | |||
import java.util.Vector; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.stream.StreamResult; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFException; | |||
import org.apache.fop.render.intermediate.IFParser; | |||
/** | |||
* InputHandler for the intermediate format XML as input. | |||
*/ | |||
public class IFInputHandler extends InputHandler { | |||
/** | |||
* Constructor for XML->XSLT->intermediate XML input | |||
* @param xmlfile XML file | |||
* @param xsltfile XSLT file | |||
* @param params Vector of command-line parameters (name, value, | |||
* name, value, ...) for XSL stylesheet, null if none | |||
*/ | |||
public IFInputHandler(File xmlfile, File xsltfile, Vector params) { | |||
super(xmlfile, xsltfile, params); | |||
} | |||
/** | |||
* Constructor for intermediate input | |||
* @param iffile the file to read the intermediate format document from. | |||
*/ | |||
public IFInputHandler(File iffile) { | |||
super(iffile); | |||
} | |||
/** {@inheritDoc} */ | |||
public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out) | |||
throws FOPException { | |||
IFDocumentHandler documentHandler | |||
= userAgent.getFactory().getRendererFactory().createDocumentHandler( | |||
userAgent, outputFormat); | |||
try { | |||
documentHandler.setResult(new StreamResult(out)); | |||
documentHandler.setDefaultFontInfo(new FontInfo()); | |||
//Create IF parser | |||
IFParser parser = new IFParser(); | |||
// Resulting SAX events are sent to the parser | |||
Result res = new SAXResult(parser.getContentHandler(documentHandler, userAgent)); | |||
transformTo(res); | |||
} catch (IFException ife) { | |||
throw new FOPException(ife); | |||
} | |||
} | |||
} |
@@ -33,6 +33,7 @@ import org.xml.sax.Locator; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.datatypes.Length; | |||
import org.apache.fop.util.XMLConstants; | |||
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener; | |||
/** | |||
@@ -41,8 +42,6 @@ import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener; | |||
*/ | |||
public abstract class XMLObj extends FONode implements ObjectBuiltListener { | |||
private static final String XMLNS_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/"; | |||
// temp reference for attributes | |||
private Attributes attr = null; | |||
@@ -116,7 +115,7 @@ public abstract class XMLObj extends FONode implements ObjectBuiltListener { | |||
private static HashMap ns = new HashMap(); | |||
static { | |||
ns.put("xlink", "http://www.w3.org/1999/xlink"); | |||
ns.put(XMLConstants.XLINK_PREFIX, XMLConstants.XLINK_NAMESPACE); | |||
} | |||
/** | |||
@@ -143,7 +142,7 @@ public abstract class XMLObj extends FONode implements ObjectBuiltListener { | |||
} else { | |||
String pref = qname.substring(0, idx); | |||
String tail = qname.substring(idx + 1); | |||
if (pref.equals("xmlns")) { | |||
if (pref.equals(XMLConstants.XMLNS_PREFIX)) { | |||
ns.put(tail, rf); | |||
} else { | |||
element.setAttributeNS((String)ns.get(pref), tail, rf); | |||
@@ -181,8 +180,9 @@ public abstract class XMLObj extends FONode implements ObjectBuiltListener { | |||
element = doc.getDocumentElement(); | |||
buildTopLevel(doc, element); | |||
if (!element.hasAttributeNS(XMLNS_NAMESPACE_URI, "xmlns")) { | |||
element.setAttributeNS(XMLNS_NAMESPACE_URI, "xmlns", | |||
if (!element.hasAttributeNS( | |||
XMLConstants.XMLNS_NAMESPACE_URI, XMLConstants.XMLNS_PREFIX)) { | |||
element.setAttributeNS(XMLConstants.XMLNS_NAMESPACE_URI, XMLConstants.XMLNS_PREFIX, | |||
getNamespaceURI()); | |||
} | |||
@@ -53,16 +53,21 @@ public abstract class FontLoader { | |||
protected boolean loaded = false; | |||
/** true if the font will be embedded, false if it will be referenced only. */ | |||
protected boolean embedded = true; | |||
/** true if kerning information shall be loaded if available. */ | |||
protected boolean useKerning = true; | |||
/** | |||
* Default constructor. | |||
* @param fontFileURI the URI to the PFB file of a Type 1 font | |||
* @param embedded indicates whether the font is embedded or referenced | |||
* @param useKerning indicates whether kerning information shall be loaded if available | |||
* @param resolver the font resolver used to resolve URIs | |||
*/ | |||
public FontLoader(String fontFileURI, boolean embedded, FontResolver resolver) { | |||
public FontLoader(String fontFileURI, boolean embedded, boolean useKerning, | |||
FontResolver resolver) { | |||
this.fontFileURI = fontFileURI; | |||
this.embedded = embedded; | |||
this.useKerning = useKerning; | |||
this.resolver = resolver; | |||
} | |||
@@ -82,7 +87,8 @@ public abstract class FontLoader { | |||
*/ | |||
public static CustomFont loadFont(File fontFile, String subFontName, | |||
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException { | |||
return loadFont(fontFile.getAbsolutePath(), subFontName, embedded, encodingMode, resolver); | |||
return loadFont(fontFile.getAbsolutePath(), subFontName, | |||
embedded, encodingMode, true, resolver); | |||
} | |||
/** | |||
@@ -96,8 +102,11 @@ public abstract class FontLoader { | |||
* @throws IOException In case of an I/O error | |||
*/ | |||
public static CustomFont loadFont(URL fontUrl, String subFontName, | |||
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException { | |||
return loadFont(fontUrl.toExternalForm(), subFontName, embedded, encodingMode, resolver); | |||
boolean embedded, EncodingMode encodingMode, | |||
FontResolver resolver) throws IOException { | |||
return loadFont(fontUrl.toExternalForm(), subFontName, | |||
embedded, encodingMode, true, | |||
resolver); | |||
} | |||
/** | |||
@@ -106,12 +115,14 @@ public abstract class FontLoader { | |||
* @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) | |||
* @param embedded indicates whether the font is embedded or referenced | |||
* @param encodingMode the requested encoding mode | |||
* @param useKerning indicates whether kerning information should be loaded if available | |||
* @param resolver the font resolver to use when resolving URIs | |||
* @return the newly loaded font | |||
* @throws IOException In case of an I/O error | |||
*/ | |||
public static CustomFont loadFont(String fontFileURI, String subFontName, | |||
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException { | |||
boolean embedded, EncodingMode encodingMode, boolean useKerning, | |||
FontResolver resolver) throws IOException { | |||
fontFileURI = fontFileURI.trim(); | |||
boolean type1 = isType1(fontFileURI); | |||
FontLoader loader; | |||
@@ -120,9 +131,10 @@ public abstract class FontLoader { | |||
throw new IllegalArgumentException( | |||
"CID encoding mode not supported for Type 1 fonts"); | |||
} | |||
loader = new Type1FontLoader(fontFileURI, embedded, resolver); | |||
loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resolver); | |||
} else { | |||
loader = new TTFFontLoader(fontFileURI, subFontName, embedded, encodingMode, resolver); | |||
loader = new TTFFontLoader(fontFileURI, subFontName, | |||
embedded, encodingMode, useKerning, resolver); | |||
} | |||
return loader.getFont(); | |||
} |
@@ -132,7 +132,7 @@ public class LazyFont extends Typeface implements FontDescriptor { | |||
throw new RuntimeException("Cannot load font. No font URIs available."); | |||
} | |||
realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName, | |||
this.embedded, this.encodingMode, resolver); | |||
this.embedded, this.encodingMode, useKerning, resolver); | |||
} | |||
if (realFont instanceof FontDescriptor) { | |||
realFontDescriptor = (FontDescriptor) realFont; |
@@ -225,7 +225,7 @@ public class FontInfoFinder { | |||
} | |||
try { | |||
TTFFontLoader ttfLoader = new TTFFontLoader( | |||
fontFileURI, fontName, true, EncodingMode.AUTO, resolver); | |||
fontFileURI, fontName, true, EncodingMode.AUTO, true, resolver); | |||
customFont = ttfLoader.getFont(); | |||
if (this.eventListener != null) { | |||
customFont.setEventListener(this.eventListener); |
@@ -55,7 +55,7 @@ public class TTFFontLoader extends FontLoader { | |||
* @param resolver the FontResolver for font URI resolution | |||
*/ | |||
public TTFFontLoader(String fontFileURI, FontResolver resolver) { | |||
this(fontFileURI, null, true, EncodingMode.AUTO, resolver); | |||
this(fontFileURI, null, true, EncodingMode.AUTO, true, resolver); | |||
} | |||
/** | |||
@@ -65,11 +65,13 @@ public class TTFFontLoader extends FontLoader { | |||
* TrueType fonts) | |||
* @param embedded indicates whether the font is embedded or referenced | |||
* @param encodingMode the requested encoding mode | |||
* @param useKerning true to enable loading kerning info if available, false to disable | |||
* @param resolver the FontResolver for font URI resolution | |||
*/ | |||
public TTFFontLoader(String fontFileURI, String subFontName, | |||
boolean embedded, EncodingMode encodingMode, FontResolver resolver) { | |||
super(fontFileURI, embedded, resolver); | |||
boolean embedded, EncodingMode encodingMode, boolean useKerning, | |||
FontResolver resolver) { | |||
super(fontFileURI, embedded, true, resolver); | |||
this.subFontName = subFontName; | |||
this.encodingMode = encodingMode; | |||
if (this.encodingMode == EncodingMode.AUTO) { | |||
@@ -164,7 +166,9 @@ public class TTFFontLoader extends FontLoader { | |||
copyWidthsSingleByte(ttf); | |||
} | |||
copyKerning(ttf, isCid); | |||
if (useKerning) { | |||
copyKerning(ttf, isCid); | |||
} | |||
if (this.embedded && ttf.isEmbeddable()) { | |||
returnFont.setEmbedFileName(this.fontFileURI); | |||
} |
@@ -45,12 +45,13 @@ public class Type1FontLoader extends FontLoader { | |||
* Constructs a new Type 1 font loader. | |||
* @param fontFileURI the URI to the PFB file of a Type 1 font | |||
* @param embedded indicates whether the font is embedded or referenced | |||
* @param useKerning indicates whether to load kerning information if available | |||
* @param resolver the font resolver used to resolve URIs | |||
* @throws IOException In case of an I/O error | |||
*/ | |||
public Type1FontLoader(String fontFileURI, boolean embedded, FontResolver resolver) | |||
throws IOException { | |||
super(fontFileURI, embedded, resolver); | |||
public Type1FontLoader(String fontFileURI, boolean embedded, boolean useKerning, | |||
FontResolver resolver) throws IOException { | |||
super(fontFileURI, embedded, useKerning, resolver); | |||
} | |||
private String getPFMURI(String pfbURI) { | |||
@@ -322,7 +323,9 @@ public class Type1FontLoader extends FontLoader { | |||
singleFont.setWidth(chm.getCharCode(), (int)Math.round(chm.getWidthX())); | |||
} | |||
} | |||
returnFont.replaceKerningMap(afm.createXKerningMapEncoded()); | |||
if (useKerning) { | |||
returnFont.replaceKerningMap(afm.createXKerningMapEncoded()); | |||
} | |||
} else { | |||
returnFont.setFlags(pfm.getFlags()); | |||
returnFont.setFirstChar(pfm.getFirstChar()); | |||
@@ -330,7 +333,9 @@ public class Type1FontLoader extends FontLoader { | |||
for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) { | |||
singleFont.setWidth(i, pfm.getCharWidth(i)); | |||
} | |||
returnFont.replaceKerningMap(pfm.getKerning()); | |||
if (useKerning) { | |||
returnFont.replaceKerningMap(pfm.getKerning()); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,36 @@ | |||
/* | |||
* 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.image.loader.batik; | |||
import org.apache.batik.dom.svg.SVGDOMImplementation; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.xmlgraphics.image.loader.XMLNamespaceEnabledImageFlavor; | |||
/** | |||
* Image flavors used by Batik. | |||
*/ | |||
public interface BatikImageFlavors { | |||
/** An SVG image in form of a W3C DOM instance */ | |||
XMLNamespaceEnabledImageFlavor SVG_DOM = new XMLNamespaceEnabledImageFlavor( | |||
ImageFlavor.XML_DOM, SVGDOMImplementation.SVG_NAMESPACE_URI); | |||
} |
@@ -0,0 +1,94 @@ | |||
/* | |||
* 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.image.loader.batik; | |||
import java.awt.Dimension; | |||
import java.awt.geom.Rectangle2D; | |||
import java.util.Map; | |||
import org.w3c.dom.DOMImplementation; | |||
import org.w3c.dom.Document; | |||
import org.w3c.dom.Element; | |||
import org.apache.batik.dom.GenericDOMImplementation; | |||
import org.apache.batik.dom.svg.SVGDOMImplementation; | |||
import org.apache.batik.svggen.SVGGeneratorContext; | |||
import org.apache.batik.svggen.SVGGraphics2D; | |||
import org.apache.xmlgraphics.image.loader.Image; | |||
import org.apache.xmlgraphics.image.loader.ImageException; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.xmlgraphics.image.loader.ImageSize; | |||
import org.apache.xmlgraphics.image.loader.impl.AbstractImageConverter; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; | |||
/** | |||
* This ImageConverter converts Java2D images into SVG images. | |||
*/ | |||
public class ImageConverterG2D2SVG extends AbstractImageConverter { | |||
/** {@inheritDoc} */ | |||
public Image convert(Image src, Map hints) throws ImageException { | |||
checkSourceFlavor(src); | |||
ImageGraphics2D g2dImage = (ImageGraphics2D)src; | |||
DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); | |||
// Create an instance of org.w3c.dom.Document | |||
Document document = domImpl.createDocument( | |||
SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null); | |||
Element root = document.getDocumentElement(); | |||
// Create an SVGGeneratorContext to customize SVG generation | |||
SVGGeneratorContext genCtx = SVGGeneratorContext.createDefault(document); | |||
genCtx.setComment("Generated by Apache Batik's SVGGraphics2D"); | |||
genCtx.setEmbeddedFontsOn(true); | |||
// Create an instance of the SVG Generator | |||
SVGGraphics2D g2d = new SVGGraphics2D(genCtx, true); | |||
ImageSize size = src.getSize(); | |||
Dimension dim = size.getDimensionMpt(); | |||
g2d.setSVGCanvasSize(dim); | |||
//SVGGraphics2D doesn't generate the viewBox by itself | |||
root.setAttribute("viewBox", "0 0 " + dim.width + " " + dim.height); | |||
g2dImage.getGraphics2DImagePainter().paint(g2d, | |||
new Rectangle2D.Float(0, 0, dim.width, dim.height)); | |||
//Populate the document root with the generated SVG content. | |||
g2d.getRoot(root); | |||
//Return the generated SVG image | |||
ImageXMLDOM svgImage = new ImageXMLDOM(src.getInfo(), document, BatikImageFlavors.SVG_DOM); | |||
g2d.dispose(); | |||
return svgImage; | |||
} | |||
/** {@inheritDoc} */ | |||
public ImageFlavor getSourceFlavor() { | |||
return ImageFlavor.GRAPHICS2D; | |||
} | |||
/** {@inheritDoc} */ | |||
public ImageFlavor getTargetFlavor() { | |||
return BatikImageFlavors.SVG_DOM; | |||
} | |||
} |
@@ -34,7 +34,6 @@ import org.apache.batik.bridge.BridgeContext; | |||
import org.apache.batik.bridge.UnitProcessor; | |||
import org.apache.batik.bridge.UserAgent; | |||
import org.apache.batik.dom.svg.SAXSVGDocumentFactory; | |||
import org.apache.batik.dom.svg.SVGDOMImplementation; | |||
import org.apache.batik.dom.svg.SVGOMDocument; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -198,7 +197,7 @@ public class PreloaderSVG extends AbstractImagePreloader { | |||
//The whole image had to be loaded for this, so keep it | |||
ImageXMLDOM xmlImage = new ImageXMLDOM(info, | |||
doc, SVGDOMImplementation.SVG_NAMESPACE_URI); | |||
doc, BatikImageFlavors.SVG_DOM); | |||
info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, xmlImage); | |||
return info; | |||
} |
@@ -19,13 +19,11 @@ | |||
package org.apache.fop.pdf; | |||
import java.text.DecimalFormat; | |||
import java.text.DecimalFormatSymbols; | |||
import java.util.Locale; | |||
import org.apache.fop.util.DecimalFormatCache; | |||
/** | |||
* This class represents a simple number object. It also contains contains some | |||
* utility methods for outputing numbers to PDF. | |||
* utility methods for outputting numbers to PDF. | |||
*/ | |||
public class PDFNumber extends PDFObject { | |||
@@ -67,33 +65,6 @@ public class PDFNumber extends PDFObject { | |||
return doubleOut(doubleDown, 6); | |||
} | |||
private static final String BASE_FORMAT = "0.################"; | |||
private static class DecimalFormatThreadLocal extends ThreadLocal { | |||
private int dec; | |||
public DecimalFormatThreadLocal(int dec) { | |||
this.dec = dec; | |||
} | |||
protected synchronized Object initialValue() { | |||
String s = "0"; | |||
if (dec > 0) { | |||
s = BASE_FORMAT.substring(0, dec + 2); | |||
} | |||
DecimalFormat df = new DecimalFormat(s, new DecimalFormatSymbols(Locale.US)); | |||
return df; | |||
} | |||
}; | |||
//DecimalFormat is not thread-safe! | |||
private static final ThreadLocal[] DECIMAL_FORMAT_CACHE = new DecimalFormatThreadLocal[17]; | |||
static { | |||
for (int i = 0, c = DECIMAL_FORMAT_CACHE.length; i < c; i++) { | |||
DECIMAL_FORMAT_CACHE[i] = new DecimalFormatThreadLocal(i); | |||
} | |||
} | |||
/** | |||
* Output a double value to a string suitable for PDF. | |||
* In this method it is possible to set the maximum | |||
@@ -104,12 +75,7 @@ public class PDFNumber extends PDFObject { | |||
* @return the value as a string | |||
*/ | |||
public static String doubleOut(double doubleDown, int dec) { | |||
if (dec < 0 || dec >= DECIMAL_FORMAT_CACHE.length) { | |||
throw new IllegalArgumentException("Parameter dec must be between 1 and " | |||
+ (DECIMAL_FORMAT_CACHE.length + 1)); | |||
} | |||
DecimalFormat df = (DecimalFormat)DECIMAL_FORMAT_CACHE[dec].get(); | |||
return df.format(doubleDown); | |||
return DecimalFormatCache.getDecimalFormat(dec).format(doubleDown); | |||
} | |||
/** {@inheritDoc} */ |
@@ -62,14 +62,15 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
* @return true if the new paint changes the current paint | |||
*/ | |||
public boolean setPaint(Paint p) { | |||
Paint paint = ((PDFData)getData()).paint; | |||
PDFData data = getPDFData(); | |||
Paint paint = data.paint; | |||
if (paint == null) { | |||
if (p != null) { | |||
((PDFData)getData()).paint = p; | |||
data.paint = p; | |||
return true; | |||
} | |||
} else if (!paint.equals(p)) { | |||
((PDFData)getData()).paint = p; | |||
data.paint = p; | |||
return true; | |||
} | |||
return false; | |||
@@ -88,7 +89,7 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
* @return true if the clip will change the current clip. | |||
*/ | |||
public boolean checkClip(Shape cl) { | |||
Shape clip = ((PDFData)getData()).clip; | |||
Shape clip = getPDFData().clip; | |||
if (clip == null) { | |||
if (cl != null) { | |||
return true; | |||
@@ -108,16 +109,39 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
* @param cl the new clip in the current state | |||
*/ | |||
public void setClip(Shape cl) { | |||
Shape clip = ((PDFData)getData()).clip; | |||
PDFData data = getPDFData(); | |||
Shape clip = data.clip; | |||
if (clip != null) { | |||
Area newClip = new Area(clip); | |||
newClip.intersect(new Area(cl)); | |||
((PDFData)getData()).clip = new GeneralPath(newClip); | |||
data.clip = new GeneralPath(newClip); | |||
} else { | |||
((PDFData)getData()).clip = cl; | |||
data.clip = cl; | |||
} | |||
} | |||
/** | |||
* Sets the character spacing (Tc). | |||
* @param value the new value | |||
* @return true if the value was changed with respect to the previous value | |||
*/ | |||
public boolean setCharacterSpacing(float value) { | |||
PDFData data = getPDFData(); | |||
if (value != data.characterSpacing) { | |||
data.characterSpacing = value; | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Returns the current character spacing (Tc) value. | |||
* @return the Tc value | |||
*/ | |||
public float getCharacterSpacing() { | |||
return getPDFData().characterSpacing; | |||
} | |||
/** | |||
* Get the current stack level. | |||
* | |||
@@ -149,8 +173,8 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
newState.addValues(state); | |||
} | |||
} | |||
if (((PDFData)getData()).gstate != null) { | |||
newState.addValues(((PDFData)getData()).gstate); | |||
if (getPDFData().gstate != null) { | |||
newState.addValues(getPDFData().gstate); | |||
} | |||
return newState; | |||
} | |||
@@ -177,32 +201,38 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
getStateStack().add(copy); | |||
} | |||
private PDFData getPDFData() { | |||
return (PDFData)getData(); | |||
} | |||
private class PDFData extends org.apache.fop.util.AbstractPaintingState.AbstractData { | |||
private static final long serialVersionUID = 3527950647293177764L; | |||
private Paint paint = null; | |||
private Paint backPaint = null; | |||
private int lineCap = 0; | |||
private int lineJoin = 0; | |||
private float miterLimit = 0; | |||
private boolean text = false; | |||
private int dashOffset = 0; | |||
//private int lineCap = 0; //Disabled the ones that are not used, yet | |||
//private int lineJoin = 0; | |||
//private float miterLimit = 0; | |||
//private int dashOffset = 0; | |||
private Shape clip = null; | |||
private PDFGState gstate = null; | |||
//text state | |||
private float characterSpacing = 0f; | |||
/** {@inheritDoc} */ | |||
public Object clone() { | |||
PDFData obj = (PDFData)super.clone(); | |||
obj.paint = this.paint; | |||
obj.backPaint = this.paint; | |||
obj.lineCap = this.lineCap; | |||
obj.lineJoin = this.lineJoin; | |||
obj.miterLimit = this.miterLimit; | |||
obj.text = this.text; | |||
obj.dashOffset = this.dashOffset; | |||
//obj.lineCap = this.lineCap; | |||
//obj.lineJoin = this.lineJoin; | |||
//obj.miterLimit = this.miterLimit; | |||
//obj.dashOffset = this.dashOffset; | |||
obj.clip = this.clip; | |||
obj.gstate = this.gstate; | |||
obj.characterSpacing = this.characterSpacing; | |||
return obj; | |||
} | |||
@@ -211,10 +241,9 @@ public class PDFPaintingState extends org.apache.fop.util.AbstractPaintingState | |||
return super.toString() | |||
+ ", paint=" + paint | |||
+ ", backPaint=" + backPaint | |||
+ ", lineCap=" + lineCap | |||
+ ", miterLimit=" + miterLimit | |||
+ ", text=" + text | |||
+ ", dashOffset=" + dashOffset | |||
//+ ", lineCap=" + lineCap | |||
//+ ", miterLimit=" + miterLimit | |||
//+ ", dashOffset=" + dashOffset | |||
+ ", clip=" + clip | |||
+ ", gstate=" + gstate; | |||
} |
@@ -33,7 +33,8 @@ import java.lang.ref.SoftReference; | |||
*/ | |||
public class PDFReference implements PDFWritable { | |||
private String indirectReference; | |||
private int objectNumber; | |||
private int generation; | |||
private Reference objReference; | |||
@@ -42,7 +43,8 @@ public class PDFReference implements PDFWritable { | |||
* @param obj the object to be referenced | |||
*/ | |||
public PDFReference(PDFObject obj) { | |||
this.indirectReference = obj.referencePDF(); | |||
this.objectNumber = obj.getObjectNumber(); | |||
this.generation = obj.getGeneration(); | |||
this.objReference = new SoftReference(obj); | |||
} | |||
@@ -54,7 +56,11 @@ public class PDFReference implements PDFWritable { | |||
if (ref == null) { | |||
throw new NullPointerException("ref must not be null"); | |||
} | |||
this.indirectReference = ref; | |||
String[] parts = ref.split(" "); | |||
assert parts.length == 3; | |||
this.objectNumber = Integer.parseInt(parts[0]); | |||
this.generation = Integer.parseInt(parts[1]); | |||
assert "R".equals(parts[2]); | |||
} | |||
/** | |||
@@ -73,9 +79,25 @@ public class PDFReference implements PDFWritable { | |||
} | |||
} | |||
/** | |||
* Returns the object number. | |||
* @return the object number | |||
*/ | |||
public int getObjectNumber() { | |||
return this.objectNumber; | |||
} | |||
/** | |||
* Returns the generation. | |||
* @return the generation | |||
*/ | |||
public int getGeneration() { | |||
return this.generation; | |||
} | |||
/** {@inheritDoc} */ | |||
public String toString() { | |||
return this.indirectReference; | |||
return getObjectNumber() + " " + getGeneration() + " R"; | |||
} | |||
/** {@inheritDoc} */ |
@@ -270,7 +270,15 @@ public abstract class PDFTextUtil { | |||
* @param adjust the glyph adjust value in thousands of text unit space. | |||
*/ | |||
public void adjustGlyphTJ(double adjust) { | |||
bufTJ.append(endText).append(" "); | |||
if (bufTJ == null) { | |||
bufTJ = new StringBuffer(); | |||
} | |||
if (bufTJ.length() > 0) { | |||
bufTJ.append(endText).append(" "); | |||
} | |||
if (bufTJ.length() == 0) { | |||
bufTJ.append("["); | |||
} | |||
bufTJ.append(PDFNumber.doubleOut(adjust, DEC - 4)); | |||
bufTJ.append(" "); | |||
bufTJ.append(startText); |
@@ -41,14 +41,22 @@ public class PDFUri extends PDFAction { | |||
* @return the action to place next to /A within a Link | |||
*/ | |||
public String getAction() { | |||
if (hasObjectNumber()) { | |||
return referencePDF(); | |||
} else { | |||
return getDictString(); | |||
} | |||
} | |||
private String getDictString() { | |||
return "<< /URI (" + uri + ")\n/S /URI >>"; | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public String toPDFString() { | |||
throw new UnsupportedOperationException("This method should not be called"); | |||
//TODO Convert this class into a dictionary | |||
return getObjectID() + getDictString() + "\nendobj\n"; | |||
//throw new UnsupportedOperationException("This method should not be called"); | |||
} | |||
} |
@@ -33,11 +33,9 @@ import org.apache.batik.dom.svg.SVGDOMImplementation; | |||
import org.apache.batik.gvt.GraphicsNode; | |||
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | |||
import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.events.EventBroadcaster; | |||
import org.apache.fop.fo.extensions.ExtensionElementMapping; | |||
import org.apache.fop.image.loader.batik.BatikUtil; | |||
import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl; | |||
import org.apache.fop.render.RendererContext.RendererContextWrapper; | |||
@@ -52,13 +50,6 @@ import org.apache.fop.svg.SVGUserAgent; | |||
*/ | |||
public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererContextConstants { | |||
/** Qualified name for the "conversion-mode" extension attribute. */ | |||
protected static final QName CONVERSION_MODE = new QName( | |||
ExtensionElementMapping.URI, null, "conversion-mode"); | |||
/** "bitmap" value for the "conversion-mode" extension attribute. */ | |||
protected static final String BITMAP = "bitmap"; | |||
/** {@inheritDoc} */ | |||
public void handleXML(RendererContext context, | |||
Document doc, String ns) throws Exception { | |||
@@ -82,9 +73,9 @@ public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererC | |||
} | |||
/** | |||
* Builds the GVT root | |||
* Builds the GVT root. | |||
* | |||
* @param rendererContext the renderer context | |||
* @param userAgent the user agent | |||
* @param ctx the batik bridge context | |||
* @param doc the document | |||
* @return a built GVT root tree |
@@ -0,0 +1,141 @@ | |||
/* | |||
* 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.render; | |||
import java.awt.Color; | |||
import java.awt.Dimension; | |||
import java.awt.Graphics2D; | |||
import java.awt.Point; | |||
import java.awt.RenderingHints; | |||
import java.awt.Transparency; | |||
import java.awt.color.ColorSpace; | |||
import java.awt.geom.Rectangle2D; | |||
import java.awt.image.BufferedImage; | |||
import java.awt.image.ColorModel; | |||
import java.awt.image.ComponentColorModel; | |||
import java.awt.image.DataBuffer; | |||
import java.awt.image.Raster; | |||
import java.awt.image.WritableRaster; | |||
import org.apache.fop.util.UnitConv; | |||
/** | |||
* Abstract base class for ImageHandler implementations that process Java2D images through | |||
* the Graphics2DImagePainter interface. | |||
*/ | |||
public abstract class AbstractImageHandlerGraphics2D implements ImageHandler { | |||
/** | |||
* Paints the image to a BufferedImage and returns that. | |||
* @param painter the painter which will paint the actual image | |||
* @param context the renderer context for the current renderer | |||
* @param targetDimension the target dimensions of the image to be converted to a bitmap | |||
* @param resolution the requested bitmap resolution | |||
* @param gray true if the generated image should be in grayscales | |||
* @param withAlpha true if an alpha channel should be created | |||
* @return the generated BufferedImage | |||
*/ | |||
protected BufferedImage paintToBufferedImage( | |||
org.apache.xmlgraphics.java2d.Graphics2DImagePainter painter, | |||
Dimension targetDimension, | |||
int resolution, boolean gray, boolean withAlpha) { | |||
int bmw = (int)Math.ceil(UnitConv.mpt2px(targetDimension.getWidth(), resolution)); | |||
int bmh = (int)Math.ceil(UnitConv.mpt2px(targetDimension.getHeight(), resolution)); | |||
BufferedImage bi; | |||
if (gray) { | |||
if (withAlpha) { | |||
bi = createGrayBufferedImageWithAlpha(bmw, bmh); | |||
} else { | |||
bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_BYTE_GRAY); | |||
} | |||
} else { | |||
if (withAlpha) { | |||
bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_INT_ARGB); | |||
} else { | |||
bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_INT_RGB); | |||
} | |||
} | |||
Graphics2D g2d = bi.createGraphics(); | |||
try { | |||
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, | |||
RenderingHints.VALUE_FRACTIONALMETRICS_ON); | |||
setRenderingHintsForBufferedImage(g2d); | |||
g2d.setBackground(Color.white); | |||
g2d.setColor(Color.black); | |||
if (!withAlpha) { | |||
g2d.clearRect(0, 0, bmw, bmh); | |||
} | |||
/* debug code | |||
int off = 2; | |||
g2d.drawLine(off, 0, off, bmh); | |||
g2d.drawLine(bmw - off, 0, bmw - off, bmh); | |||
g2d.drawLine(0, off, bmw, off); | |||
g2d.drawLine(0, bmh - off, bmw, bmh - off); | |||
*/ | |||
double sx = (double)bmw / targetDimension.getWidth(); | |||
double sy = (double)bmh / targetDimension.getHeight(); | |||
g2d.scale(sx, sy); | |||
//Paint the image on the BufferedImage | |||
Rectangle2D area = new Rectangle2D.Double( | |||
0.0, 0.0, targetDimension.getWidth(), targetDimension.getHeight()); | |||
painter.paint(g2d, area); | |||
} finally { | |||
g2d.dispose(); | |||
} | |||
return bi; | |||
} | |||
private static BufferedImage createGrayBufferedImageWithAlpha(int width, int height) { | |||
BufferedImage bi; | |||
boolean alphaPremultiplied = true; | |||
int bands = 2; | |||
int[] bits = new int[bands]; | |||
for (int i = 0; i < bands; i++) { | |||
bits[i] = 8; | |||
} | |||
ColorModel cm = new ComponentColorModel( | |||
ColorSpace.getInstance(ColorSpace.CS_GRAY), | |||
bits, | |||
true, alphaPremultiplied, | |||
Transparency.TRANSLUCENT, | |||
DataBuffer.TYPE_BYTE); | |||
WritableRaster wr = Raster.createInterleavedRaster( | |||
DataBuffer.TYPE_BYTE, | |||
width, height, bands, | |||
new Point(0, 0)); | |||
bi = new BufferedImage(cm, wr, alphaPremultiplied, null); | |||
return bi; | |||
} | |||
/** | |||
* Sets rendering hints on the Graphics2D created for painting to a BufferedImage. Subclasses | |||
* can modify the settings to customize the behavior. | |||
* @param g2d the Graphics2D instance | |||
*/ | |||
protected void setRenderingHintsForBufferedImage(Graphics2D g2d) { | |||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, | |||
RenderingHints.VALUE_ANTIALIAS_ON); | |||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, | |||
RenderingHints.VALUE_TEXT_ANTIALIAS_ON); | |||
} | |||
} |
@@ -27,6 +27,7 @@ import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.image.loader.Image; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.xmlgraphics.util.Service; | |||
@@ -43,8 +44,8 @@ public abstract class AbstractImageHandlerRegistry { | |||
private static final Comparator HANDLER_COMPARATOR = new Comparator() { | |||
public int compare(Object o1, Object o2) { | |||
ImageHandler h1 = (ImageHandler)o1; | |||
ImageHandler h2 = (ImageHandler)o2; | |||
ImageHandlerBase h1 = (ImageHandlerBase)o1; | |||
ImageHandlerBase h2 = (ImageHandlerBase)o2; | |||
return h1.getPriority() - h2.getPriority(); | |||
} | |||
}; | |||
@@ -76,8 +77,8 @@ public abstract class AbstractImageHandlerRegistry { | |||
*/ | |||
public void addHandler(String classname) { | |||
try { | |||
ImageHandler handlerInstance | |||
= (ImageHandler)Class.forName(classname).newInstance(); | |||
ImageHandlerBase handlerInstance | |||
= (ImageHandlerBase)Class.forName(classname).newInstance(); | |||
addHandler(handlerInstance); | |||
} catch (ClassNotFoundException e) { | |||
throw new IllegalArgumentException("Could not find " | |||
@@ -99,13 +100,13 @@ public abstract class AbstractImageHandlerRegistry { | |||
* Add an image handler. The handler itself is inspected to find out what it supports. | |||
* @param handler the ImageHandler instance | |||
*/ | |||
public synchronized void addHandler(ImageHandler handler) { | |||
public synchronized void addHandler(ImageHandlerBase handler) { | |||
this.handlers.put(handler.getSupportedImageClass(), handler); | |||
//Sorted insert | |||
ListIterator iter = this.handlerList.listIterator(); | |||
while (iter.hasNext()) { | |||
ImageHandler h = (ImageHandler)iter.next(); | |||
ImageHandlerBase h = (ImageHandlerBase)iter.next(); | |||
if (getHandlerComparator().compare(handler, h) < 0) { | |||
iter.previous(); | |||
break; | |||
@@ -121,7 +122,7 @@ public abstract class AbstractImageHandlerRegistry { | |||
* @param img the Image to be handled | |||
* @return the ImageHandler responsible for handling the image or null if none is available | |||
*/ | |||
public ImageHandler getHandler(Image img) { | |||
public ImageHandlerBase getHandler(Image img) { | |||
return getHandler(img.getClass()); | |||
} | |||
@@ -131,11 +132,11 @@ public abstract class AbstractImageHandlerRegistry { | |||
* @param imageClass the Image subclass for which to get a handler | |||
* @return the ImageHandler responsible for handling the image or null if none is available | |||
*/ | |||
public synchronized ImageHandler getHandler(Class imageClass) { | |||
ImageHandler handler = null; | |||
public synchronized ImageHandlerBase getHandler(Class imageClass) { | |||
ImageHandlerBase handler = null; | |||
Class cl = imageClass; | |||
while (cl != null) { | |||
handler = (ImageHandler)handlers.get(cl); | |||
handler = (ImageHandlerBase)handlers.get(cl); | |||
if (handler != null) { | |||
break; | |||
} | |||
@@ -154,7 +155,7 @@ public abstract class AbstractImageHandlerRegistry { | |||
List flavors = new java.util.ArrayList(); | |||
Iterator iter = this.handlerList.iterator(); | |||
while (iter.hasNext()) { | |||
ImageFlavor[] f = ((ImageHandler)iter.next()).getSupportedImageFlavors(); | |||
ImageFlavor[] f = ((ImageHandlerBase)iter.next()).getSupportedImageFlavors(); | |||
for (int i = 0; i < f.length; i++) { | |||
flavors.add(f[i]); | |||
} | |||
@@ -175,7 +176,7 @@ public abstract class AbstractImageHandlerRegistry { | |||
Iterator providers = Service.providers(imageHandlerClass); | |||
if (providers != null) { | |||
while (providers.hasNext()) { | |||
ImageHandler handler = (ImageHandler)providers.next(); | |||
ImageHandlerBase handler = (ImageHandlerBase)providers.next(); | |||
try { | |||
if (log.isDebugEnabled()) { | |||
log.debug("Dynamically adding ImageHandler: " |
@@ -475,7 +475,8 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { | |||
} | |||
} | |||
private static final QName FOX_TRANSFORM | |||
/** Constant for the fox:transform extension attribute */ | |||
protected static final QName FOX_TRANSFORM | |||
= new QName(ExtensionElementMapping.URI, "fox:transform"); | |||
/** {@inheritDoc} */ |
@@ -21,6 +21,7 @@ package org.apache.fop.render; | |||
// Java | |||
import java.awt.Rectangle; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Rectangle2D; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
@@ -111,7 +112,7 @@ public abstract class AbstractRenderer | |||
private Set warnedXMLHandlers; | |||
/** {@inheritDoc} */ | |||
public abstract void setupFontInfo(FontInfo fontInfo); | |||
public abstract void setupFontInfo(FontInfo fontInfo) throws FOPException; | |||
/** {@inheritDoc} */ | |||
public void setUserAgent(FOUserAgent agent) { | |||
@@ -833,4 +834,34 @@ public abstract class AbstractRenderer | |||
public String getMimeType() { | |||
return null; | |||
} | |||
/** | |||
* Converts a millipoint-based transformation matrix to points. | |||
* @param at a millipoint-based transformation matrix | |||
* @return a point-based transformation matrix | |||
*/ | |||
protected AffineTransform mptToPt(AffineTransform at) { | |||
double[] matrix = new double[6]; | |||
at.getMatrix(matrix); | |||
//Convert to points | |||
matrix[4] = matrix[4] / 1000; | |||
matrix[5] = matrix[5] / 1000; | |||
return new AffineTransform(matrix); | |||
} | |||
/** | |||
* Converts a point-based transformation matrix to millipoints. | |||
* @param at a point-based transformation matrix | |||
* @return a millipoint-based transformation matrix | |||
*/ | |||
protected AffineTransform ptToMpt(AffineTransform at) { | |||
double[] matrix = new double[6]; | |||
at.getMatrix(matrix); | |||
//Convert to millipoints | |||
//Math.round() because things like this can happen: 65.6 * 1000 = 65.599999999999999 | |||
//which is bad for testing | |||
matrix[4] = Math.round(matrix[4] * 1000); | |||
matrix[5] = Math.round(matrix[5] * 1000); | |||
return new AffineTransform(matrix); | |||
} | |||
} |
@@ -23,6 +23,7 @@ import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOUserAgent; | |||
/** | |||
@@ -68,7 +69,7 @@ public abstract class AbstractRendererConfigurator { | |||
* @param mimeType the MIME type of the renderer | |||
* @return the requested configuration subtree, null if there's no configuration | |||
*/ | |||
private Configuration getRendererConfig(String mimeType) { | |||
protected Configuration getRendererConfig(String mimeType) { | |||
Configuration cfg = userAgent.getFactory().getUserConfig(); | |||
if (cfg == null) { | |||
if (log.isDebugEnabled()) { |
@@ -0,0 +1,86 @@ | |||
/* | |||
* 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.render; | |||
import java.util.Collections; | |||
import java.util.Map; | |||
import org.apache.fop.apps.FOUserAgent; | |||
/** | |||
* Abstract base class for RenderingContext implementations. | |||
*/ | |||
public abstract class AbstractRenderingContext implements RenderingContext { | |||
private FOUserAgent userAgent; | |||
private Map hints; | |||
/** | |||
* Main constructor. | |||
* @param userAgent the user agent | |||
*/ | |||
public AbstractRenderingContext(FOUserAgent userAgent) { | |||
this.userAgent = userAgent; | |||
} | |||
/** | |||
* Returns the user agent. | |||
* | |||
* @return The user agent | |||
*/ | |||
public FOUserAgent getUserAgent() { | |||
return userAgent; | |||
} | |||
/** {@inheritDoc} */ | |||
public void putHints(Map additionalHints) { | |||
if (additionalHints == null) { | |||
return; | |||
} | |||
if (this.hints == null) { | |||
this.hints = new java.util.HashMap(); | |||
} | |||
this.hints.putAll(additionalHints); | |||
} | |||
/** {@inheritDoc} */ | |||
public void putHint(Object key, Object value) { | |||
this.hints.put(key, value); | |||
} | |||
/** {@inheritDoc} */ | |||
public Map getHints() { | |||
if (this.hints == null) { | |||
return Collections.EMPTY_MAP; | |||
} else { | |||
return Collections.unmodifiableMap(this.hints); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public Object getHint(Object key) { | |||
if (this.hints == null) { | |||
return null; | |||
} else { | |||
return this.hints.get(key); | |||
} | |||
} | |||
} | |||
@@ -27,4 +27,4 @@ package org.apache.fop.render; | |||
public interface Graphics2DImagePainter | |||
extends org.apache.xmlgraphics.java2d.Graphics2DImagePainter { | |||
} | |||
} |
@@ -34,10 +34,10 @@ public interface ImageAdapter { | |||
* Paints an image at the given position. | |||
* @param image the image which will be painted | |||
* @param context the renderer context for the current renderer | |||
* @param x X position of the image | |||
* @param y Y position of the image | |||
* @param width width of the image | |||
* @param height height of the image | |||
* @param x X position of the image (in millipoints) | |||
* @param y Y position of the image (in millipoints) | |||
* @param width width of the image (in millipoints) | |||
* @param height height of the image (in millipoints) | |||
* @throws IOException In case of an I/O error while writing the output format | |||
*/ | |||
void paintImage(RenderedImage image, |
@@ -19,27 +19,39 @@ | |||
package org.apache.fop.render; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import java.awt.Rectangle; | |||
import java.io.IOException; | |||
public interface ImageHandler { | |||
import org.apache.xmlgraphics.image.loader.Image; | |||
/** | |||
* Returns the priority for this image handler. A lower value means higher priority. This | |||
* information is used to build the ordered/prioritized list of supported ImageFlavors. | |||
* The built-in handlers use priorities between 100 and 999. | |||
* @return a positive integer (>0) indicating the priority | |||
*/ | |||
int getPriority(); | |||
/** | |||
* This interface is a service provider interface for image handlers. | |||
*/ | |||
public interface ImageHandler extends ImageHandlerBase { | |||
/** | |||
* Returns the {@link ImageFlavor}s supported by this instance | |||
* @return the supported image flavors | |||
* Indicates whether the image handler is compatible with the indicated target represented | |||
* by the rendering context object and with the image to be processed. The image is also | |||
* passed as a parameter because a handler might not support every subtype of image that is | |||
* presented. For example: in the case of {@code ImageXMLDOM}, the image might carry an SVG | |||
* or some other XML format. One handler might only handle SVG but no other XML format. | |||
* @param targetContext the target rendering context | |||
* @param image the image to be processed (or null if only to check based on the rendering | |||
* context) | |||
* @return true if this handler is compatible with the target rendering context | |||
*/ | |||
ImageFlavor[] getSupportedImageFlavors(); | |||
boolean isCompatible(RenderingContext targetContext, Image image); | |||
/** | |||
* Returns the {@link Class} subclass supported by this instance. | |||
* @return the image Class type | |||
* Handles the given {@link Image} instance painting it at the indicated position in the | |||
* output format being generated. | |||
* @param context the rendering context | |||
* @param image the image to be handled | |||
* @param pos the position and scaling of the image relative to the origin point of the | |||
* current viewport (in millipoints) | |||
* @throws IOException if an I/O error occurs | |||
*/ | |||
Class getSupportedImageClass(); | |||
void handleImage(RenderingContext context, Image image, | |||
Rectangle pos) throws IOException; | |||
} |
@@ -0,0 +1,50 @@ | |||
/* | |||
* 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.render; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
/** | |||
* This interface is a service provider base interface for image handlers. It only contains | |||
* methods necessary for registration and is extended by sub-interfaces with the actual | |||
* image handling contract. | |||
*/ | |||
public interface ImageHandlerBase { | |||
/** | |||
* Returns the priority for this image handler. A lower value means higher priority. This | |||
* information is used to build the ordered/prioritized list of supported ImageFlavors. | |||
* The built-in handlers use priorities between 100 and 999. | |||
* @return a positive integer (>0) indicating the priority | |||
*/ | |||
int getPriority(); | |||
/** | |||
* Returns the {@link ImageFlavor}s supported by this instance | |||
* @return the supported image flavors | |||
*/ | |||
ImageFlavor[] getSupportedImageFlavors(); | |||
/** | |||
* Returns the {@link Class} subclass supported by this instance. | |||
* @return the image Class type | |||
*/ | |||
Class getSupportedImageClass(); | |||
} |
@@ -0,0 +1,177 @@ | |||
/* | |||
* 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.render; | |||
import java.util.Comparator; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.image.loader.Image; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.xmlgraphics.util.Service; | |||
/** | |||
* This class holds references to various image handlers. It also | |||
* supports automatic discovery of additional handlers available through | |||
* the class path. | |||
*/ | |||
public class ImageHandlerRegistry { | |||
/** the logger */ | |||
private static Log log = LogFactory.getLog(ImageHandlerRegistry.class); | |||
private static final Comparator HANDLER_COMPARATOR = new Comparator() { | |||
public int compare(Object o1, Object o2) { | |||
ImageHandler h1 = (ImageHandler)o1; | |||
ImageHandler h2 = (ImageHandler)o2; | |||
return h1.getPriority() - h2.getPriority(); | |||
} | |||
}; | |||
/** Map containing image handlers for various {@code Image} subclasses. */ | |||
private Map handlers = new java.util.HashMap(); | |||
/** List containing the same handlers as above but ordered by priority */ | |||
private List handlerList = new java.util.LinkedList(); | |||
private int handlerRegistrations; | |||
/** | |||
* Default constructor. | |||
*/ | |||
public ImageHandlerRegistry() { | |||
discoverHandlers(); | |||
} | |||
/** | |||
* Add an PDFImageHandler. The handler itself is inspected to find out what it supports. | |||
* @param classname the fully qualified class name | |||
*/ | |||
public void addHandler(String classname) { | |||
try { | |||
ImageHandler handlerInstance | |||
= (ImageHandler)Class.forName(classname).newInstance(); | |||
addHandler(handlerInstance); | |||
} catch (ClassNotFoundException e) { | |||
throw new IllegalArgumentException("Could not find " | |||
+ classname); | |||
} catch (InstantiationException e) { | |||
throw new IllegalArgumentException("Could not instantiate " | |||
+ classname); | |||
} catch (IllegalAccessException e) { | |||
throw new IllegalArgumentException("Could not access " | |||
+ classname); | |||
} catch (ClassCastException e) { | |||
throw new IllegalArgumentException(classname | |||
+ " is not an " | |||
+ ImageHandler.class.getName()); | |||
} | |||
} | |||
/** | |||
* Add an image handler. The handler itself is inspected to find out what it supports. | |||
* @param handler the ImageHandler instance | |||
*/ | |||
public synchronized void addHandler(ImageHandler handler) { | |||
Class imageClass = handler.getSupportedImageClass(); | |||
//List | |||
this.handlers.put(imageClass, handler); | |||
//Sorted insert (sort by priority) | |||
ListIterator iter = this.handlerList.listIterator(); | |||
while (iter.hasNext()) { | |||
ImageHandler h = (ImageHandler)iter.next(); | |||
if (HANDLER_COMPARATOR.compare(handler, h) < 0) { | |||
iter.previous(); | |||
break; | |||
} | |||
} | |||
iter.add(handler); | |||
this.handlerRegistrations++; | |||
} | |||
/** | |||
* Returns an {@code ImageHandler} which handles an specific image type given the MIME type | |||
* of the image. | |||
* @param targetContext the target rendering context that is used for identifying compatibility | |||
* @param image the Image to be handled | |||
* @return the image handler responsible for handling the image or null if none is available | |||
*/ | |||
public ImageHandler getHandler(RenderingContext targetContext, Image image) { | |||
ListIterator iter = this.handlerList.listIterator(); | |||
while (iter.hasNext()) { | |||
ImageHandler h = (ImageHandler)iter.next(); | |||
if (h.isCompatible(targetContext, image)) { | |||
//Return the first handler in the prioritized list that is compatible | |||
return h; | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* Returns the ordered array of supported image flavors. The array needs to be ordered by | |||
* priority so the image loader framework can return the preferred image type. | |||
* @return the array of image flavors | |||
*/ | |||
public synchronized ImageFlavor[] getSupportedFlavors(RenderingContext context) { | |||
//Extract all ImageFlavors into a single array | |||
List flavors = new java.util.ArrayList(); | |||
Iterator iter = this.handlerList.iterator(); | |||
while (iter.hasNext()) { | |||
ImageHandler handler = (ImageHandler)iter.next(); | |||
if (handler.isCompatible(context, null)) { | |||
ImageFlavor[] f = handler.getSupportedImageFlavors(); | |||
for (int i = 0; i < f.length; i++) { | |||
flavors.add(f[i]); | |||
} | |||
} | |||
} | |||
return (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]); | |||
} | |||
/** | |||
* Discovers ImageHandler implementations through the classpath and dynamically | |||
* registers them. | |||
*/ | |||
private void discoverHandlers() { | |||
// add mappings from available services | |||
Iterator providers = Service.providers(ImageHandler.class); | |||
if (providers != null) { | |||
while (providers.hasNext()) { | |||
ImageHandler handler = (ImageHandler)providers.next(); | |||
try { | |||
if (log.isDebugEnabled()) { | |||
log.debug("Dynamically adding ImageHandler: " | |||
+ handler.getClass().getName()); | |||
} | |||
addHandler(handler); | |||
} catch (IllegalArgumentException e) { | |||
log.error("Error while adding ImageHandler", e); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,64 @@ | |||
/* | |||
* 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.render; | |||
import java.util.Map; | |||
import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.fo.extensions.ExtensionElementMapping; | |||
/** | |||
* Utility methods for image handling. | |||
*/ | |||
public class ImageHandlerUtil { | |||
/** conversion-mode extension attribute */ | |||
public static final QName CONVERSION_MODE = new QName( | |||
ExtensionElementMapping.URI, null, "conversion-mode"); | |||
/** Conversion mode: indicates that the image shall be converted to a bitmap. */ | |||
public static final String CONVERSION_MODE_BITMAP = "bitmap"; | |||
/** | |||
* Indicates whether the image conversion mode is set to bitmap mode, i.e. the image shall | |||
* be converted to a bitmap. | |||
* @param mode the conversion mode | |||
* @return true if conversion mode is "bitmap" | |||
*/ | |||
public static boolean isConversionModeBitmap(String mode) { | |||
return CONVERSION_MODE_BITMAP.equalsIgnoreCase(mode); | |||
} | |||
/** | |||
* Indicates whether the image conversion mode is set to bitmap mode, i.e. the image shall | |||
* be converted to a bitmap. | |||
* @param foreignAttributes a map of foreign attributes (Map<QName, Object>) | |||
* @return true if conversion mode is "bitmap" | |||
*/ | |||
public static boolean isConversionModeBitmap(Map foreignAttributes) { | |||
if (foreignAttributes == null) { | |||
return false; | |||
} | |||
String conversionMode = (String)foreignAttributes.get(CONVERSION_MODE); | |||
return isConversionModeBitmap(conversionMode); | |||
} | |||
} |
@@ -24,6 +24,9 @@ import java.awt.geom.Rectangle2D; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.w3c.dom.Document; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.area.Trait; | |||
import org.apache.fop.fonts.CustomFontCollection; | |||
@@ -34,7 +37,6 @@ import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.fonts.FontResolver; | |||
import org.apache.fop.fonts.FontTriplet; | |||
import org.apache.fop.fonts.base14.Base14FontCollection; | |||
import org.w3c.dom.Document; | |||
/** Abstract base class of "Print" type renderers. */ | |||
public abstract class PrintRenderer extends AbstractRenderer { | |||
@@ -74,12 +76,8 @@ public abstract class PrintRenderer extends AbstractRenderer { | |||
return this.embedFontInfoList; | |||
} | |||
/** | |||
* Set up the font info | |||
* | |||
* @param inFontInfo font info to set up | |||
*/ | |||
public void setupFontInfo(FontInfo inFontInfo) { | |||
/** {@inheritDoc} */ | |||
public void setupFontInfo(FontInfo inFontInfo) throws FOPException { | |||
this.fontInfo = inFontInfo; | |||
FontManager fontManager = userAgent.getFactory().getFontManager(); | |||
FontCollection[] fontCollections = new FontCollection[] { | |||
@@ -96,7 +94,13 @@ public abstract class PrintRenderer extends AbstractRenderer { | |||
*/ | |||
protected String getInternalFontNameForArea(Area area) { | |||
FontTriplet triplet = (FontTriplet)area.getTrait(Trait.FONT); | |||
return fontInfo.getInternalFontKey(triplet); | |||
String key = fontInfo.getInternalFontKey(triplet); | |||
if (key == null) { | |||
//Find a default fallback font as last resort | |||
triplet = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); | |||
key = fontInfo.getInternalFontKey(triplet); | |||
} | |||
return key; | |||
} | |||
/** |
@@ -41,9 +41,11 @@ import org.apache.xmlgraphics.util.ClasspathResource; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.fonts.CustomFontCollection; | |||
import org.apache.fop.fonts.EmbedFontInfo; | |||
import org.apache.fop.fonts.EncodingMode; | |||
import org.apache.fop.fonts.FontCache; | |||
import org.apache.fop.fonts.FontCollection; | |||
import org.apache.fop.fonts.FontEventAdapter; | |||
import org.apache.fop.fonts.FontEventListener; | |||
import org.apache.fop.fonts.FontInfo; | |||
@@ -53,13 +55,16 @@ import org.apache.fop.fonts.FontTriplet; | |||
import org.apache.fop.fonts.FontUtil; | |||
import org.apache.fop.fonts.autodetect.FontFileFinder; | |||
import org.apache.fop.fonts.autodetect.FontInfoFinder; | |||
import org.apache.fop.fonts.base14.Base14FontCollection; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; | |||
import org.apache.fop.util.LogUtil; | |||
/** | |||
* Base Print renderer configurator (mostly handles font configuration) | |||
*/ | |||
public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
implements RendererConfigurator { | |||
implements RendererConfigurator, IFDocumentHandlerConfigurator { | |||
/** logger instance */ | |||
protected static Log log = LogFactory.getLog(PrintRendererConfigurator.class); | |||
@@ -87,6 +92,23 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
PrintRenderer printRenderer = (PrintRenderer)renderer; | |||
FontResolver fontResolver = printRenderer.getFontResolver(); | |||
FontEventListener listener = new FontEventAdapter( | |||
renderer.getUserAgent().getEventBroadcaster()); | |||
List embedFontInfoList = buildFontList(cfg, fontResolver, listener); | |||
printRenderer.addFontList(embedFontInfoList); | |||
} | |||
/** | |||
* Builds the font list from configuration. | |||
* @param cfg the configuration object | |||
* @param fontResolver a font resolver | |||
* @param listener the font event listener | |||
* @return the list of {@code EmbedFontInfo} objects | |||
* @throws FOPException if an error occurs while processing the configuration | |||
*/ | |||
protected List buildFontList(Configuration cfg, FontResolver fontResolver, | |||
FontEventListener listener) throws FOPException { | |||
FopFactory factory = userAgent.getFactory(); | |||
FontManager fontManager = factory.getFontManager(); | |||
if (fontResolver == null) { | |||
@@ -97,15 +119,13 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
boolean strict = factory.validateUserConfigStrictly(); | |||
FontCache fontCache = fontManager.getFontCache(); | |||
FontEventListener listener = new FontEventAdapter( | |||
renderer.getUserAgent().getEventBroadcaster()); | |||
List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontListFromConfiguration(cfg, | |||
fontResolver, strict, fontManager, listener); | |||
if (fontCache != null && fontCache.hasChanged()) { | |||
fontCache.save(); | |||
} | |||
printRenderer.addFontList(embedFontInfoList); | |||
return embedFontInfoList; | |||
} | |||
/** | |||
@@ -437,4 +457,33 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator | |||
return embedFontInfo; | |||
} | |||
// ---=== IFDocumentHandler configuration ===--- | |||
/** {@inheritDoc} */ | |||
public void configure(IFDocumentHandler documentHandler) throws FOPException { | |||
//nop | |||
} | |||
/** {@inheritDoc} */ | |||
public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo) | |||
throws FOPException { | |||
FontManager fontManager = userAgent.getFactory().getFontManager(); | |||
List fontCollections = new java.util.ArrayList(); | |||
fontCollections.add(new Base14FontCollection(fontManager.isBase14KerningEnabled())); | |||
Configuration cfg = super.getRendererConfig(documentHandler.getMimeType()); | |||
if (cfg != null) { | |||
FontResolver fontResolver = new DefaultFontResolver(userAgent); | |||
FontEventListener listener = new FontEventAdapter( | |||
userAgent.getEventBroadcaster()); | |||
List fontList = buildFontList(cfg, fontResolver, listener); | |||
fontCollections.add(new CustomFontCollection(fontResolver, fontList)); | |||
} | |||
fontManager.setup(fontInfo, | |||
(FontCollection[])fontCollections.toArray( | |||
new FontCollection[fontCollections.size()])); | |||
documentHandler.setFontInfo(fontInfo); | |||
} | |||
} |
@@ -98,8 +98,9 @@ public interface Renderer { | |||
* Set up the given FontInfo. | |||
* | |||
* @param fontInfo The font information | |||
* @throws FOPException if an error occurs while setting up the font info object | |||
*/ | |||
void setupFontInfo(FontInfo fontInfo); | |||
void setupFontInfo(FontInfo fontInfo) throws FOPException; | |||
/** | |||
* Reports if out of order rendering is supported. <p> |
@@ -24,8 +24,6 @@ import java.util.Iterator; | |||
import java.util.Map; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fo.extensions.ExtensionElementMapping; | |||
import org.apache.xmlgraphics.util.QName; | |||
/** | |||
* The Render Context for external handlers. This provides a rendering context | |||
@@ -33,12 +31,6 @@ import org.apache.xmlgraphics.util.QName; | |||
* render target. | |||
*/ | |||
public class RendererContext { | |||
/** conversion-mode extension attribute */ | |||
protected static final QName CONVERSION_MODE = new QName( | |||
ExtensionElementMapping.URI, null, "conversion-mode"); | |||
/** "bitmap" value for the "conversion-mode" extension attribute. */ | |||
protected static final String BITMAP = "bitmap"; | |||
private final String mime; | |||
private final AbstractRenderer renderer; |
@@ -34,6 +34,10 @@ import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.area.AreaTreeHandler; | |||
import org.apache.fop.fo.FOEventHandler; | |||
import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; | |||
import org.apache.fop.render.intermediate.IFRenderer; | |||
/** | |||
* Factory for FOEventHandlers and Renderers. | |||
@@ -45,7 +49,7 @@ public class RendererFactory { | |||
private Map rendererMakerMapping = new java.util.HashMap(); | |||
private Map eventHandlerMakerMapping = new java.util.HashMap(); | |||
private Map documentHandlerMakerMapping = new java.util.HashMap(); | |||
/** | |||
* Main constructor. | |||
@@ -53,6 +57,7 @@ public class RendererFactory { | |||
public RendererFactory() { | |||
discoverRenderers(); | |||
discoverFOEventHandlers(); | |||
discoverDocumentHandlers(); | |||
} | |||
/** | |||
@@ -89,6 +94,23 @@ public class RendererFactory { | |||
} | |||
} | |||
/** | |||
* Add a new document handler maker. If another maker has already been registered for a | |||
* particular MIME type, this call overwrites the existing one. | |||
* @param maker the intermediate format document handler maker | |||
*/ | |||
public void addDocumentHandlerMaker(AbstractIFDocumentHandlerMaker maker) { | |||
String[] mimes = maker.getSupportedMimeTypes(); | |||
for (int i = 0; i < mimes.length; i++) { | |||
//This overrides any renderer previously set for a MIME type | |||
if (documentHandlerMakerMapping.get(mimes[i]) != null) { | |||
log.trace("Overriding document handler for " + mimes[i] | |||
+ " with " + maker.getClass().getName()); | |||
} | |||
documentHandlerMakerMapping.put(mimes[i], maker); | |||
} | |||
} | |||
/** | |||
* Add a new RendererMaker. If another maker has already been registered for a | |||
* particular MIME type, this call overwrites the existing one. | |||
@@ -141,6 +163,32 @@ public class RendererFactory { | |||
} | |||
} | |||
/** | |||
* Add a new document handler maker. If another maker has already been registered for a | |||
* particular MIME type, this call overwrites the existing one. | |||
* @param className the fully qualified class name of the document handler maker | |||
*/ | |||
public void addDocumentHandlerMaker(String className) { | |||
try { | |||
AbstractIFDocumentHandlerMaker makerInstance | |||
= (AbstractIFDocumentHandlerMaker)Class.forName(className).newInstance(); | |||
addDocumentHandlerMaker(makerInstance); | |||
} catch (ClassNotFoundException e) { | |||
throw new IllegalArgumentException("Could not find " | |||
+ className); | |||
} catch (InstantiationException e) { | |||
throw new IllegalArgumentException("Could not instantiate " | |||
+ className); | |||
} catch (IllegalAccessException e) { | |||
throw new IllegalArgumentException("Could not access " | |||
+ className); | |||
} catch (ClassCastException e) { | |||
throw new IllegalArgumentException(className | |||
+ " is not an " | |||
+ AbstractIFDocumentHandlerMaker.class.getName()); | |||
} | |||
} | |||
/** | |||
* Returns a RendererMaker which handles the given MIME type. | |||
* @param mime the requested output format | |||
@@ -163,6 +211,17 @@ public class RendererFactory { | |||
return maker; | |||
} | |||
/** | |||
* Returns a RendererMaker which handles the given MIME type. | |||
* @param mime the requested output format | |||
* @return the requested RendererMaker or null if none is available | |||
*/ | |||
public AbstractIFDocumentHandlerMaker getDocumentHandlerMaker(String mime) { | |||
AbstractIFDocumentHandlerMaker maker | |||
= (AbstractIFDocumentHandlerMaker)documentHandlerMakerMapping.get(mime); | |||
return maker; | |||
} | |||
/** | |||
* Creates a Renderer object based on render-type desired | |||
* @param userAgent the user agent for access to configuration | |||
@@ -172,24 +231,41 @@ public class RendererFactory { | |||
*/ | |||
public Renderer createRenderer(FOUserAgent userAgent, String outputFormat) | |||
throws FOPException { | |||
if (userAgent.getRendererOverride() != null) { | |||
if (userAgent.getDocumentHandlerOverride() != null) { | |||
return createRendererForDocumentHandler(userAgent.getDocumentHandlerOverride()); | |||
} else if (userAgent.getRendererOverride() != null) { | |||
return userAgent.getRendererOverride(); | |||
} else { | |||
AbstractRendererMaker maker = getRendererMaker(outputFormat); | |||
if (maker == null) { | |||
throw new UnsupportedOperationException( | |||
"No renderer for the requested format available: " + outputFormat); | |||
} | |||
Renderer rend = maker.makeRenderer(userAgent); | |||
rend.setUserAgent(userAgent); | |||
RendererConfigurator configurator = maker.getConfigurator(userAgent); | |||
if (configurator != null) { | |||
configurator.configure(rend); | |||
if (maker != null) { | |||
Renderer rend = maker.makeRenderer(userAgent); | |||
rend.setUserAgent(userAgent); | |||
RendererConfigurator configurator = maker.getConfigurator(userAgent); | |||
if (configurator != null) { | |||
configurator.configure(rend); | |||
} | |||
return rend; | |||
} else { | |||
AbstractIFDocumentHandlerMaker documentHandlerMaker | |||
= getDocumentHandlerMaker(outputFormat); | |||
if (documentHandlerMaker != null) { | |||
IFDocumentHandler documentHandler = createDocumentHandler( | |||
userAgent, outputFormat); | |||
return createRendererForDocumentHandler(documentHandler); | |||
} else { | |||
throw new UnsupportedOperationException( | |||
"No renderer for the requested format available: " + outputFormat); | |||
} | |||
} | |||
return rend; | |||
} | |||
} | |||
private Renderer createRendererForDocumentHandler(IFDocumentHandler documentHandler) { | |||
IFRenderer rend = new IFRenderer(); | |||
rend.setUserAgent(documentHandler.getContext().getUserAgent()); | |||
rend.setDocumentHandler(documentHandler); | |||
return rend; | |||
} | |||
/** | |||
* Creates FOEventHandler instances based on the desired output. | |||
@@ -206,29 +282,64 @@ public class RendererFactory { | |||
return userAgent.getFOEventHandlerOverride(); | |||
} else { | |||
AbstractFOEventHandlerMaker maker = getFOEventHandlerMaker(outputFormat); | |||
if (maker == null) { | |||
if (maker != null) { | |||
return maker.makeFOEventHandler(userAgent, out); | |||
} else { | |||
AbstractRendererMaker rendMaker = getRendererMaker(outputFormat); | |||
if (rendMaker == null && userAgent.getRendererOverride() == null) { | |||
throw new UnsupportedOperationException( | |||
"Don't know how to handle \"" + outputFormat + "\" as an output format." | |||
+ " Neither an FOEventHandler, nor a Renderer could be found" | |||
+ " for this output format."); | |||
AbstractIFDocumentHandlerMaker documentHandlerMaker = null; | |||
boolean outputStreamMissing = (userAgent.getRendererOverride() == null) | |||
&& (userAgent.getDocumentHandlerOverride() == null); | |||
if (rendMaker == null) { | |||
documentHandlerMaker = getDocumentHandlerMaker(outputFormat); | |||
if (documentHandlerMaker != null) { | |||
outputStreamMissing &= (out == null) | |||
&& (documentHandlerMaker.needsOutputStream()); | |||
} | |||
} else { | |||
if (out == null | |||
&& userAgent.getRendererOverride() == null | |||
&& rendMaker.needsOutputStream()) { | |||
outputStreamMissing &= (out == null) && (rendMaker.needsOutputStream()); | |||
} | |||
if (userAgent.getRendererOverride() != null | |||
|| rendMaker != null | |||
|| userAgent.getDocumentHandlerOverride() != null | |||
|| documentHandlerMaker != null) { | |||
if (outputStreamMissing) { | |||
throw new FOPException( | |||
"OutputStream has not been set"); | |||
} | |||
//Found a Renderer so we need to construct an AreaTreeHandler. | |||
return new AreaTreeHandler(userAgent, outputFormat, out); | |||
} else { | |||
throw new UnsupportedOperationException( | |||
"Don't know how to handle \"" + outputFormat + "\" as an output format." | |||
+ " Neither an FOEventHandler, nor a Renderer could be found" | |||
+ " for this output format."); | |||
} | |||
} else { | |||
return maker.makeFOEventHandler(userAgent, out); | |||
} | |||
} | |||
} | |||
/** | |||
* Creates a {@code IFDocumentHandler} object based on the desired output format. | |||
* @param userAgent the user agent for access to configuration | |||
* @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). | |||
* @return the new {@code IFDocumentHandler} instance | |||
* @throws FOPException if the document handler cannot be properly constructed | |||
*/ | |||
public IFDocumentHandler createDocumentHandler(FOUserAgent userAgent, String outputFormat) | |||
throws FOPException { | |||
AbstractIFDocumentHandlerMaker maker = getDocumentHandlerMaker(outputFormat); | |||
if (maker == null) { | |||
throw new UnsupportedOperationException( | |||
"No IF document handler for the requested format available: " + outputFormat); | |||
} | |||
IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(userAgent); | |||
IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator(); | |||
if (configurator != null) { | |||
configurator.configure(documentHandler); | |||
} | |||
return documentHandler; | |||
} | |||
/** | |||
* @return an array of all supported MIME types | |||
*/ | |||
@@ -242,6 +353,10 @@ public class RendererFactory { | |||
while (iter.hasNext()) { | |||
lst.add(((String)iter.next())); | |||
} | |||
iter = this.documentHandlerMakerMapping.keySet().iterator(); | |||
while (iter.hasNext()) { | |||
lst.add(((String)iter.next())); | |||
} | |||
Collections.sort(lst); | |||
return (String[])lst.toArray(new String[lst.size()]); | |||
} | |||
@@ -296,4 +411,29 @@ public class RendererFactory { | |||
} | |||
} | |||
/** | |||
* Discovers {@code IFDocumentHandler} implementations through the classpath and dynamically | |||
* registers them. | |||
*/ | |||
private void discoverDocumentHandlers() { | |||
// add mappings from available services | |||
Iterator providers = Service.providers(IFDocumentHandler.class); | |||
if (providers != null) { | |||
while (providers.hasNext()) { | |||
AbstractIFDocumentHandlerMaker maker | |||
= (AbstractIFDocumentHandlerMaker)providers.next(); | |||
try { | |||
if (log.isDebugEnabled()) { | |||
log.debug("Dynamically adding maker for IFDocumentHandler: " | |||
+ maker.getClass().getName()); | |||
} | |||
addDocumentHandlerMaker(maker); | |||
} catch (IllegalArgumentException e) { | |||
log.error("Error while adding maker for IFDocumentHandler", e); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,71 @@ | |||
/* | |||
* 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.render; | |||
import java.util.Map; | |||
import org.apache.fop.apps.FOUserAgent; | |||
/** | |||
* Implementations of this interface provide context information needed by supporting classes | |||
* during specific tasks (like image rendering). | |||
*/ | |||
public interface RenderingContext { | |||
/** | |||
* Returns the MIME type associated with the current output format. | |||
* @return the MIME type (ex. application/pdf) | |||
*/ | |||
String getMimeType(); | |||
/** | |||
* Returns the user agent. The user agent is used to access configuration and other information | |||
* for the rendering process. | |||
* @return the user agent | |||
*/ | |||
FOUserAgent getUserAgent(); | |||
/** | |||
* Adds additional hints to the existing hints, overriding existing hints. | |||
* @param additionalHints a map of additional hints | |||
*/ | |||
void putHints(Map additionalHints); | |||
/** | |||
* Sets an additional hint, overriding an existing hint. | |||
* @param key the key | |||
* @param value the value | |||
*/ | |||
void putHint(Object key, Object value); | |||
/** | |||
* Returns an unmodifiable representation of all hints. | |||
* @return the hints | |||
*/ | |||
Map getHints(); | |||
/** | |||
* Returns a hint identified by a key. | |||
* @param key the key | |||
* @return the hint or null if no hint with the given key could be found | |||
*/ | |||
Object getHint(Object key); | |||
} |
@@ -0,0 +1,81 @@ | |||
/* | |||
* 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.render.afp; | |||
import org.apache.fop.afp.AFPResourceLevelDefaults; | |||
/** | |||
* Interface used to customize the AFP renderer or document handler. | |||
*/ | |||
public interface AFPCustomizable { | |||
/** | |||
* Sets the number of bits used per pixel | |||
* | |||
* @param bitsPerPixel | |||
* number of bits per pixel | |||
*/ | |||
void setBitsPerPixel(int bitsPerPixel); | |||
/** | |||
* Sets whether images are color or not | |||
* | |||
* @param colorImages | |||
* color image output | |||
*/ | |||
void setColorImages(boolean colorImages); | |||
/** | |||
* Sets whether images are supported natively or not | |||
* | |||
* @param nativeImages | |||
* native image support | |||
*/ | |||
void setNativeImagesSupported(boolean nativeImages); | |||
/** | |||
* Sets the output/device resolution | |||
* | |||
* @param resolution | |||
* the output resolution (dpi) | |||
*/ | |||
void setResolution(int resolution); | |||
/** | |||
* Returns the output/device resolution. | |||
* | |||
* @return the resolution in dpi | |||
*/ | |||
int getResolution(); | |||
/** | |||
* Sets the default resource group file path | |||
* @param filePath the default resource group file path | |||
*/ | |||
void setDefaultResourceGroupFilePath(String filePath); | |||
/** | |||
* Sets the resource level defaults. The object passed in provides information which resource | |||
* level shall be used by default for various kinds of resources. | |||
* @param defaults the resource level defaults | |||
*/ | |||
void setResourceLevelDefaults(AFPResourceLevelDefaults defaults); | |||
} |
@@ -0,0 +1,321 @@ | |||
/* | |||
* 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.render.afp; | |||
import java.awt.Color; | |||
import java.awt.Dimension; | |||
import java.awt.geom.AffineTransform; | |||
import java.io.IOException; | |||
import java.util.Map; | |||
import org.apache.fop.afp.AFPPaintingState; | |||
import org.apache.fop.afp.AFPResourceLevelDefaults; | |||
import org.apache.fop.afp.AFPResourceManager; | |||
import org.apache.fop.afp.AFPUnitConverter; | |||
import org.apache.fop.afp.DataStream; | |||
import org.apache.fop.afp.fonts.AFPFontCollection; | |||
import org.apache.fop.afp.fonts.AFPPageFonts; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.fonts.FontCollection; | |||
import org.apache.fop.fonts.FontEventAdapter; | |||
import org.apache.fop.fonts.FontInfo; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.render.afp.extensions.AFPElementMapping; | |||
import org.apache.fop.render.afp.extensions.AFPPageSetup; | |||
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; | |||
import org.apache.fop.render.intermediate.IFException; | |||
import org.apache.fop.render.intermediate.IFPainter; | |||
/** | |||
* {@code IFDocumentHandler} implementation that produces AFP (MO:DCA). | |||
*/ | |||
public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler | |||
implements AFPCustomizable { | |||
//** logging instance */ | |||
//private static Log log = LogFactory.getLog(AFPDocumentHandler.class); | |||
/** the resource manager */ | |||
private AFPResourceManager resourceManager; | |||
/** the painting state */ | |||
private final AFPPaintingState paintingState; | |||
/** unit converter */ | |||
private final AFPUnitConverter unitConv; | |||
/** the AFP datastream */ | |||
private DataStream dataStream; | |||
/** the map of page segments */ | |||
private Map/*<String,String>*/pageSegmentMap | |||
= new java.util.HashMap/*<String,String>*/(); | |||
private boolean inPageHeader; | |||
/** | |||
* Default constructor. | |||
*/ | |||
public AFPDocumentHandler() { | |||
this.resourceManager = new AFPResourceManager(); | |||
this.paintingState = new AFPPaintingState(); | |||
this.unitConv = paintingState.getUnitConverter(); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean supportsPagesOutOfOrder() { | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
public String getMimeType() { | |||
return MimeConstants.MIME_AFP; | |||
} | |||
/** {@inheritDoc} */ | |||
public void setContext(IFContext context) { | |||
super.setContext(context); | |||
} | |||
/** {@inheritDoc} */ | |||
public IFDocumentHandlerConfigurator getConfigurator() { | |||
return new AFPRendererConfigurator(getUserAgent()); | |||
} | |||
/** {@inheritDoc} */ | |||
public void setDefaultFontInfo(FontInfo fontInfo) { | |||
FontManager fontManager = getUserAgent().getFactory().getFontManager(); | |||
FontCollection[] fontCollections = new FontCollection[] { | |||
new AFPFontCollection(getUserAgent().getEventBroadcaster(), null) | |||
}; | |||
FontInfo fi = (fontInfo != null ? fontInfo : new FontInfo()); | |||
fi.setEventListener(new FontEventAdapter(getUserAgent().getEventBroadcaster())); | |||
fontManager.setup(fi, fontCollections); | |||
setFontInfo(fi); | |||
} | |||
AFPPaintingState getPaintingState() { | |||
return this.paintingState; | |||
} | |||
DataStream getDataStream() { | |||
return this.dataStream; | |||
} | |||
AFPResourceManager getResourceManager() { | |||
return this.resourceManager; | |||
} | |||
/** {@inheritDoc} */ | |||
public void startDocument() throws IFException { | |||
super.startDocument(); | |||
try { | |||
paintingState.setColor(Color.WHITE); | |||
this.dataStream = resourceManager.createDataStream(paintingState, outputStream); | |||
this.dataStream.startDocument(); | |||
} catch (IOException e) { | |||
throw new IFException("I/O error in startDocument()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void endDocumentHeader() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void endDocument() throws IFException { | |||
try { | |||
this.dataStream.endDocument(); | |||
this.dataStream = null; | |||
this.resourceManager.writeToStream(); | |||
this.resourceManager = null; | |||
} catch (IOException ioe) { | |||
throw new IFException("I/O error in endDocument()", ioe); | |||
} | |||
super.endDocument(); | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageSequence(String id) throws IFException { | |||
try { | |||
dataStream.startPageGroup(); | |||
} catch (IOException ioe) { | |||
throw new IFException("I/O error in startPageSequence()", ioe); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageSequence() throws IFException { | |||
//nop | |||
} | |||
/** | |||
* Returns the base AFP transform | |||
* | |||
* @return the base AFP transform | |||
*/ | |||
private AffineTransform getBaseTransform() { | |||
AffineTransform baseTransform = new AffineTransform(); | |||
double scale = unitConv.mpt2units(1); | |||
baseTransform.scale(scale, scale); | |||
return baseTransform; | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPage(int index, String name, String pageMasterName, Dimension size) | |||
throws IFException { | |||
paintingState.clear(); | |||
pageSegmentMap.clear(); | |||
AffineTransform baseTransform = getBaseTransform(); | |||
paintingState.concatenate(baseTransform); | |||
int pageWidth = Math.round(unitConv.mpt2units(size.width)); | |||
paintingState.setPageWidth(pageWidth); | |||
int pageHeight = Math.round(unitConv.mpt2units(size.height)); | |||
paintingState.setPageHeight(pageHeight); | |||
int pageRotation = paintingState.getPageRotation(); | |||
int resolution = paintingState.getResolution(); | |||
dataStream.startPage(pageWidth, pageHeight, pageRotation, | |||
resolution, resolution); | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageHeader() throws IFException { | |||
super.startPageHeader(); | |||
this.inPageHeader = true; | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageHeader() throws IFException { | |||
this.inPageHeader = false; | |||
super.endPageHeader(); | |||
} | |||
/** {@inheritDoc} */ | |||
public IFPainter startPageContent() throws IFException { | |||
return new AFPPainter(this); | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageContent() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPage() throws IFException { | |||
try { | |||
AFPPageFonts pageFonts = paintingState.getPageFonts(); | |||
if (pageFonts != null && !pageFonts.isEmpty()) { | |||
dataStream.addFontsToCurrentPage(pageFonts); | |||
} | |||
dataStream.endPage(); | |||
} catch (IOException ioe) { | |||
throw new IFException("I/O error in endPage()", ioe); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void handleExtensionObject(Object extension) throws IFException { | |||
if (extension instanceof AFPPageSetup) { | |||
AFPPageSetup aps = (AFPPageSetup)extension; | |||
if (!inPageHeader) { | |||
throw new IFException( | |||
"AFP page setup extension encountered outside the page header: " + aps, null); | |||
} | |||
String element = aps.getElementName(); | |||
if (AFPElementMapping.INCLUDE_PAGE_OVERLAY.equals(element)) { | |||
String overlay = aps.getName(); | |||
if (overlay != null) { | |||
dataStream.createIncludePageOverlay(overlay); | |||
} | |||
} else if (AFPElementMapping.INCLUDE_PAGE_SEGMENT.equals(element)) { | |||
String name = aps.getName(); | |||
String source = aps.getValue(); | |||
pageSegmentMap.put(source, name); | |||
} else if (AFPElementMapping.TAG_LOGICAL_ELEMENT.equals(element)) { | |||
String name = aps.getName(); | |||
String value = aps.getValue(); | |||
dataStream.createTagLogicalElement(name, value); | |||
} else if (AFPElementMapping.NO_OPERATION.equals(element)) { | |||
String content = aps.getContent(); | |||
if (content != null) { | |||
dataStream.createNoOperation(content); | |||
} | |||
} | |||
} | |||
} | |||
// ---=== AFPCustomizable ===--- | |||
/** {@inheritDoc} */ | |||
public void setBitsPerPixel(int bitsPerPixel) { | |||
paintingState.setBitsPerPixel(bitsPerPixel); | |||
} | |||
/** {@inheritDoc} */ | |||
public void setColorImages(boolean colorImages) { | |||
paintingState.setColorImages(colorImages); | |||
} | |||
/** {@inheritDoc} */ | |||
public void setNativeImagesSupported(boolean nativeImages) { | |||
paintingState.setNativeImagesSupported(nativeImages); | |||
} | |||
/** {@inheritDoc} */ | |||
public void setResolution(int resolution) { | |||
paintingState.setResolution(resolution); | |||
} | |||
/** {@inheritDoc} */ | |||
public int getResolution() { | |||
return paintingState.getResolution(); | |||
} | |||
/** {@inheritDoc} */ | |||
public void setDefaultResourceGroupFilePath(String filePath) { | |||
resourceManager.setDefaultResourceGroupFilePath(filePath); | |||
} | |||
/** {@inheritDoc} */ | |||
public void setResourceLevelDefaults(AFPResourceLevelDefaults defaults) { | |||
resourceManager.setResourceLevelDefaults(defaults); | |||
} | |||
/** | |||
* Returns the page segment name for a given URI if it actually represents a page segment. | |||
* Otherwise, it just returns null. | |||
* @param uri the URI that identifies the page segment | |||
* @return the page segment name or null if there's no page segment for the given URI | |||
*/ | |||
String getPageSegmentNameFor(String uri) { | |||
return (String)pageSegmentMap.get(uri); | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
/* | |||
* 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.render.afp; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker; | |||
import org.apache.fop.render.intermediate.IFContext; | |||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||
/** | |||
* Intermediate format document handler factory for AFP output. | |||
*/ | |||
public class AFPDocumentHandlerMaker extends AbstractIFDocumentHandlerMaker { | |||
//TODO Revert to normal MIME after stabilization! | |||
private static final String[] MIMES = new String[] | |||
{MimeConstants.MIME_AFP + ";mode=painter"}; | |||
/** {@inheritDoc} */ | |||
public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) { | |||
AFPDocumentHandler handler = new AFPDocumentHandler(); | |||
handler.setContext(new IFContext(ua)); | |||
return handler; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean needsOutputStream() { | |||
return true; | |||
} | |||
/** {@inheritDoc} */ | |||
public String[] getSupportedMimeTypes() { | |||
return MIMES; | |||
} | |||
} |
@@ -0,0 +1 @@ | |||
<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en"/> |
@@ -24,10 +24,12 @@ import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.afp.AFPResourceInfo; | |||
import org.apache.fop.afp.AFPResourceLevel; | |||
import org.apache.fop.render.afp.extensions.AFPElementMapping; | |||
import org.apache.xmlgraphics.util.QName; | |||
/** | |||
* Parses any AFP foreign attributes | |||
@@ -36,13 +38,16 @@ public class AFPForeignAttributeReader { | |||
private static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); | |||
/** the resource-name attribute */ | |||
public static final String RESOURCE_NAME = "afp:resource-name"; | |||
public static final QName RESOURCE_NAME = new QName( | |||
AFPElementMapping.NAMESPACE, "afp:resource-name"); | |||
/** the resource-level attribute */ | |||
public static final String RESOURCE_LEVEL = "afp:resource-level"; | |||
public static final QName RESOURCE_LEVEL = new QName( | |||
AFPElementMapping.NAMESPACE, "afp:resource-level"); | |||
/** the resource-group-file attribute */ | |||
public static final String RESOURCE_GROUP_FILE = "afp:resource-group-file"; | |||
public static final QName RESOURCE_GROUP_FILE = new QName( | |||
AFPElementMapping.NAMESPACE, "afp:resource-group-file"); | |||
/** | |||
* Main constructor | |||
@@ -59,8 +64,7 @@ public class AFPForeignAttributeReader { | |||
public AFPResourceInfo getResourceInfo(Map/*<QName, String>*/ foreignAttributes) { | |||
AFPResourceInfo resourceInfo = new AFPResourceInfo(); | |||
if (foreignAttributes != null && !foreignAttributes.isEmpty()) { | |||
QName resourceNameKey = new QName(AFPElementMapping.NAMESPACE, RESOURCE_NAME); | |||
String resourceName = (String)foreignAttributes.get(resourceNameKey); | |||
String resourceName = (String)foreignAttributes.get(RESOURCE_NAME); | |||
if (resourceName != null) { | |||
resourceInfo.setName(resourceName); | |||
} | |||
@@ -81,16 +85,13 @@ public class AFPForeignAttributeReader { | |||
public AFPResourceLevel getResourceLevel(Map/*<QName, String>*/ foreignAttributes) { | |||
AFPResourceLevel resourceLevel = null; | |||
if (foreignAttributes != null && !foreignAttributes.isEmpty()) { | |||
QName resourceLevelKey = new QName(AFPElementMapping.NAMESPACE, RESOURCE_LEVEL); | |||
if (foreignAttributes.containsKey(resourceLevelKey)) { | |||
String levelString = (String)foreignAttributes.get(resourceLevelKey); | |||
if (foreignAttributes.containsKey(RESOURCE_LEVEL)) { | |||
String levelString = (String)foreignAttributes.get(RESOURCE_LEVEL); | |||
resourceLevel = AFPResourceLevel.valueOf(levelString); | |||
// if external get resource group file attributes | |||
if (resourceLevel != null && resourceLevel.isExternal()) { | |||
QName resourceGroupFileKey = new QName(AFPElementMapping.NAMESPACE, | |||
RESOURCE_GROUP_FILE); | |||
String resourceGroupFile | |||
= (String)foreignAttributes.get(resourceGroupFileKey); | |||
= (String)foreignAttributes.get(RESOURCE_GROUP_FILE); | |||
if (resourceGroupFile == null) { | |||
String msg = RESOURCE_GROUP_FILE + " not specified"; | |||
log.error(msg); |
@@ -20,6 +20,7 @@ | |||
package org.apache.fop.render.afp; | |||
import java.awt.Point; | |||
import java.awt.Rectangle; | |||
import java.awt.geom.Rectangle2D; | |||
import java.io.IOException; | |||
import java.util.Map; | |||
@@ -29,12 +30,12 @@ import org.apache.fop.afp.AFPObjectAreaInfo; | |||
import org.apache.fop.afp.AFPPaintingState; | |||
import org.apache.fop.afp.AFPResourceInfo; | |||
import org.apache.fop.afp.AFPUnitConverter; | |||
import org.apache.fop.render.ImageHandler; | |||
import org.apache.fop.render.ImageHandlerBase; | |||
/** | |||
* A base abstract AFP image handler | |||
*/ | |||
public abstract class AFPImageHandler implements ImageHandler { | |||
public abstract class AFPImageHandler implements ImageHandlerBase { | |||
private static final int X = 0; | |||
private static final int Y = 1; | |||
@@ -55,33 +56,64 @@ public abstract class AFPImageHandler implements ImageHandler { | |||
AFPDataObjectInfo dataObjectInfo = createDataObjectInfo(); | |||
// set resource information | |||
Map foreignAttributes = rendererImageInfo.getForeignAttributes(); | |||
AFPResourceInfo resourceInfo | |||
= foreignAttributeReader.getResourceInfo(foreignAttributes); | |||
resourceInfo.setUri(rendererImageInfo.getURI()); | |||
dataObjectInfo.setResourceInfo(resourceInfo); | |||
setResourceInformation(dataObjectInfo, | |||
rendererImageInfo.getURI(), | |||
rendererImageInfo.getForeignAttributes()); | |||
// set object area | |||
AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); | |||
Point origin = rendererImageInfo.getOrigin(); | |||
Rectangle2D position = rendererImageInfo.getPosition(); | |||
float srcX = origin.x + (float)position.getX(); | |||
float srcY = origin.y + (float)position.getY(); | |||
int srcX = Math.round(origin.x + (float)position.getX()); | |||
int srcY = Math.round(origin.y + (float)position.getY()); | |||
Rectangle targetRect = new Rectangle( | |||
srcX, | |||
srcY, | |||
(int)Math.round(position.getWidth()), | |||
(int)Math.round(position.getHeight())); | |||
AFPRendererContext rendererContext | |||
= (AFPRendererContext)rendererImageInfo.getRendererContext(); | |||
AFPInfo afpInfo = rendererContext.getInfo(); | |||
AFPPaintingState paintingState = afpInfo.getPaintingState(); | |||
dataObjectInfo.setObjectAreaInfo(createObjectAreaInfo(paintingState, targetRect)); | |||
return dataObjectInfo; | |||
} | |||
/** | |||
* Sets resource information on the data object info. | |||
* @param dataObjectInfo the data object info instance | |||
* @param uri the image's URI (or null if no URI is available) | |||
* @param foreignAttributes a Map of foreign attributes (or null) | |||
*/ | |||
protected void setResourceInformation(AFPDataObjectInfo dataObjectInfo, | |||
String uri, Map foreignAttributes) { | |||
AFPResourceInfo resourceInfo | |||
= foreignAttributeReader.getResourceInfo(foreignAttributes); | |||
resourceInfo.setUri(uri); | |||
dataObjectInfo.setResourceInfo(resourceInfo); | |||
} | |||
/** | |||
* Creates and returns an {@link AFPObjectAreaInfo} instance for the placement of the image. | |||
* @param paintingState the painting state | |||
* @param targetRect the target rectangle in which to place the image (coordinates in mpt) | |||
* @return the newly created object area info instance | |||
*/ | |||
public static AFPObjectAreaInfo createObjectAreaInfo(AFPPaintingState paintingState, | |||
Rectangle targetRect) { | |||
AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); | |||
AFPUnitConverter unitConv = paintingState.getUnitConverter(); | |||
int[] coords = unitConv.mpts2units(new float[] {srcX, srcY}); | |||
int[] coords = unitConv.mpts2units(new float[] {targetRect.x, targetRect.y}); | |||
objectAreaInfo.setX(coords[X]); | |||
objectAreaInfo.setY(coords[Y]); | |||
int width = Math.round(unitConv.mpt2units((float)position.getWidth())); | |||
int width = Math.round(unitConv.mpt2units(targetRect.width)); | |||
objectAreaInfo.setWidth(width); | |||
int height = Math.round(unitConv.mpt2units((float)position.getHeight())); | |||
int height = Math.round(unitConv.mpt2units(targetRect.height)); | |||
objectAreaInfo.setHeight(height); | |||
int resolution = paintingState.getResolution(); | |||
@@ -89,10 +121,7 @@ public abstract class AFPImageHandler implements ImageHandler { | |||
objectAreaInfo.setWidthRes(resolution); | |||
objectAreaInfo.setRotation(paintingState.getRotation()); | |||
dataObjectInfo.setObjectAreaInfo(objectAreaInfo); | |||
return dataObjectInfo; | |||
return objectAreaInfo; | |||
} | |||
/** |
@@ -19,8 +19,10 @@ | |||
package org.apache.fop.render.afp; | |||
import java.awt.Rectangle; | |||
import java.io.IOException; | |||
import org.apache.xmlgraphics.image.loader.Image; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; | |||
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | |||
@@ -31,12 +33,16 @@ import org.apache.fop.afp.AFPGraphics2D; | |||
import org.apache.fop.afp.AFPGraphicsObjectInfo; | |||
import org.apache.fop.afp.AFPPaintingState; | |||
import org.apache.fop.afp.AFPResourceInfo; | |||
import org.apache.fop.afp.AFPResourceManager; | |||
import org.apache.fop.afp.modca.ResourceObject; | |||
import org.apache.fop.render.ImageHandler; | |||
import org.apache.fop.render.ImageHandlerUtil; | |||
import org.apache.fop.render.RenderingContext; | |||
/** | |||
* PDFImageHandler implementation which handles Graphics2D images. | |||
*/ | |||
public class AFPImageHandlerGraphics2D extends AFPImageHandler { | |||
public class AFPImageHandlerGraphics2D extends AFPImageHandler implements ImageHandler { | |||
private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { | |||
ImageFlavor.GRAPHICS2D | |||
@@ -65,18 +71,13 @@ public class AFPImageHandlerGraphics2D extends AFPImageHandler { | |||
AFPGraphicsObjectInfo graphicsObjectInfo | |||
= (AFPGraphicsObjectInfo)super.generateDataObjectInfo(rendererImageInfo); | |||
AFPResourceInfo resourceInfo = graphicsObjectInfo.getResourceInfo(); | |||
if (!resourceInfo.levelChanged()) { | |||
resourceInfo.setLevel(afpInfo.getResourceManager().getResourceLevelDefaults() | |||
.getDefaultResourceLevel(ResourceObject.TYPE_GRAPHIC)); | |||
} | |||
setDefaultResourceLevel(graphicsObjectInfo, afpInfo.getResourceManager()); | |||
// set mime type (unsupported by MOD:CA registry) | |||
graphicsObjectInfo.setMimeType(MimeConstants.MIME_AFP_GOCA); | |||
// set g2d | |||
boolean textAsShapes = false; | |||
AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes); | |||
graphicsObjectInfo.setGraphics2D(g2d); | |||
@@ -88,6 +89,15 @@ public class AFPImageHandlerGraphics2D extends AFPImageHandler { | |||
} | |||
} | |||
private void setDefaultResourceLevel(AFPGraphicsObjectInfo graphicsObjectInfo, | |||
AFPResourceManager resourceManager) { | |||
AFPResourceInfo resourceInfo = graphicsObjectInfo.getResourceInfo(); | |||
if (!resourceInfo.levelChanged()) { | |||
resourceInfo.setLevel(resourceManager.getResourceLevelDefaults() | |||
.getDefaultResourceLevel(ResourceObject.TYPE_GRAPHIC)); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public int getPriority() { | |||
return 200; | |||
@@ -107,4 +117,54 @@ public class AFPImageHandlerGraphics2D extends AFPImageHandler { | |||
protected AFPDataObjectInfo createDataObjectInfo() { | |||
return new AFPGraphicsObjectInfo(); | |||
} | |||
/** {@inheritDoc} */ | |||
public void handleImage(RenderingContext context, Image image, Rectangle pos) | |||
throws IOException { | |||
AFPRenderingContext afpContext = (AFPRenderingContext)context; | |||
AFPGraphicsObjectInfo graphicsObjectInfo = (AFPGraphicsObjectInfo)createDataObjectInfo(); | |||
// set resource information | |||
setResourceInformation(graphicsObjectInfo, | |||
image.getInfo().getOriginalURI(), | |||
afpContext.getForeignAttributes()); | |||
// Positioning | |||
graphicsObjectInfo.setObjectAreaInfo( | |||
createObjectAreaInfo(afpContext.getPaintingState(), pos)); | |||
setDefaultResourceLevel(graphicsObjectInfo, afpContext.getResourceManager()); | |||
// Image content | |||
ImageGraphics2D imageG2D = (ImageGraphics2D)image; | |||
boolean textAsShapes = false; //TODO Make configurable | |||
AFPGraphics2D g2d = new AFPGraphics2D( | |||
textAsShapes, | |||
afpContext.getPaintingState(), | |||
afpContext.getResourceManager(), | |||
graphicsObjectInfo.getResourceInfo(), | |||
afpContext.getFontInfo()); | |||
g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); | |||
graphicsObjectInfo.setGraphics2D(g2d); | |||
graphicsObjectInfo.setPainter(imageG2D.getGraphics2DImagePainter()); | |||
// Create image | |||
afpContext.getResourceManager().createObject(graphicsObjectInfo); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isCompatible(RenderingContext targetContext, Image image) { | |||
boolean supported = (image == null || image instanceof ImageGraphics2D) | |||
&& targetContext instanceof AFPRenderingContext; | |||
if (supported) { | |||
String mode = (String)targetContext.getHint(ImageHandlerUtil.CONVERSION_MODE); | |||
if (ImageHandlerUtil.isConversionModeBitmap(mode)) { | |||
//Disabling this image handler automatically causes a bitmap to be generated | |||
return false; | |||
} | |||
} | |||
return supported; | |||
} | |||
} |
@@ -19,12 +19,15 @@ | |||
package org.apache.fop.render.afp; | |||
import java.io.IOException; | |||
import org.apache.xmlgraphics.image.loader.Image; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; | |||
import org.apache.xmlgraphics.util.MimeConstants; | |||
import org.apache.fop.afp.AFPDataObjectInfo; | |||
import org.apache.fop.afp.AFPImageObjectInfo; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; | |||
import org.apache.fop.render.RenderingContext; | |||
/** | |||
* AFPImageHandler implementation which handles CCITT encoded images (CCITT fax group 3/4). | |||
@@ -36,17 +39,18 @@ public class AFPImageHandlerRawCCITTFax extends AbstractAFPImageHandlerRawStream | |||
}; | |||
/** {@inheritDoc} */ | |||
public AFPDataObjectInfo generateDataObjectInfo( | |||
AFPRendererImageInfo rendererImageInfo) throws IOException { | |||
AFPImageObjectInfo imageObjectInfo | |||
= (AFPImageObjectInfo)super.generateDataObjectInfo(rendererImageInfo); | |||
ImageRawCCITTFax ccitt = (ImageRawCCITTFax) rendererImageInfo.getImage(); | |||
protected void setAdditionalParameters(AFPDataObjectInfo dataObjectInfo, | |||
ImageRawStream image) { | |||
AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)dataObjectInfo; | |||
ImageRawCCITTFax ccitt = (ImageRawCCITTFax)image; | |||
int compression = ccitt.getCompression(); | |||
imageObjectInfo.setCompression(compression); | |||
imageObjectInfo.setBitsPerPixel(1); | |||
return imageObjectInfo; | |||
//CCITTFax flavor doesn't have TIFF associated but the AFP library listens to | |||
//that to identify CCITT encoded images. CCITT is not exclusive to TIFF. | |||
imageObjectInfo.setMimeType(MimeConstants.MIME_TIFF); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -69,4 +73,14 @@ public class AFPImageHandlerRawCCITTFax extends AbstractAFPImageHandlerRawStream | |||
return FLAVORS; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isCompatible(RenderingContext targetContext, Image image) { | |||
if (targetContext instanceof AFPRenderingContext) { | |||
AFPRenderingContext afpContext = (AFPRenderingContext)targetContext; | |||
return (afpContext.getPaintingState().isNativeImagesSupported()) | |||
&& (image == null || image instanceof ImageRawCCITTFax); | |||
} | |||
return false; | |||
} | |||
} |
@@ -19,10 +19,15 @@ | |||
package org.apache.fop.render.afp; | |||
import org.apache.fop.afp.AFPDataObjectInfo; | |||
import org.apache.xmlgraphics.image.loader.Image; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; | |||
import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; | |||
import org.apache.fop.afp.AFPDataObjectInfo; | |||
import org.apache.fop.render.RenderingContext; | |||
/** | |||
* AFPImageHandler implementation which handles raw stream images. | |||
*/ | |||
@@ -52,4 +57,14 @@ public class AFPImageHandlerRawStream extends AbstractAFPImageHandlerRawStream { | |||
protected AFPDataObjectInfo createDataObjectInfo() { | |||
return new AFPDataObjectInfo(); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isCompatible(RenderingContext targetContext, Image image) { | |||
if (targetContext instanceof AFPRenderingContext) { | |||
AFPRenderingContext afpContext = (AFPRenderingContext)targetContext; | |||
return (afpContext.getPaintingState().isNativeImagesSupported()) | |||
&& (image == null || image instanceof ImageRawJPEG || image instanceof ImageRawEPS); | |||
} | |||
return false; | |||
} | |||
} |
@@ -20,6 +20,7 @@ | |||
package org.apache.fop.render.afp; | |||
import java.awt.Dimension; | |||
import java.awt.Rectangle; | |||
import java.awt.image.ColorModel; | |||
import java.awt.image.RenderedImage; | |||
import java.io.IOException; | |||
@@ -28,6 +29,7 @@ import org.apache.commons.io.output.ByteArrayOutputStream; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.image.loader.Image; | |||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | |||
import org.apache.xmlgraphics.image.loader.ImageInfo; | |||
import org.apache.xmlgraphics.image.loader.ImageSize; | |||
@@ -41,13 +43,16 @@ import org.apache.fop.afp.AFPImageObjectInfo; | |||
import org.apache.fop.afp.AFPObjectAreaInfo; | |||
import org.apache.fop.afp.AFPPaintingState; | |||
import org.apache.fop.afp.AFPResourceInfo; | |||
import org.apache.fop.afp.AFPResourceManager; | |||
import org.apache.fop.afp.modca.ResourceObject; | |||
import org.apache.fop.render.ImageHandler; | |||
import org.apache.fop.render.RenderingContext; | |||
import org.apache.fop.util.bitmap.BitmapImageUtil; | |||
/** | |||
* PDFImageHandler implementation which handles RenderedImage instances. | |||
*/ | |||
public class AFPImageHandlerRenderedImage extends AFPImageHandler { | |||
public class AFPImageHandlerRenderedImage extends AFPImageHandler implements ImageHandler { | |||
/** logging instance */ | |||
private static Log log = LogFactory.getLog(AFPImageHandlerRenderedImage.class); | |||
@@ -67,34 +72,40 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler { | |||
= (AFPRendererContext)rendererImageInfo.getRendererContext(); | |||
AFPInfo afpInfo = rendererContext.getInfo(); | |||
AFPResourceInfo resourceInfo = imageObjectInfo.getResourceInfo(); | |||
if (!resourceInfo.levelChanged()) { | |||
resourceInfo.setLevel(afpInfo.getResourceManager().getResourceLevelDefaults() | |||
.getDefaultResourceLevel(ResourceObject.TYPE_IMAGE)); | |||
} | |||
setDefaultResourceLevel(imageObjectInfo, afpInfo.getResourceManager()); | |||
AFPPaintingState paintingState = afpInfo.getPaintingState(); | |||
ImageRendered imageRendered = (ImageRendered) rendererImageInfo.img; | |||
Dimension targetSize = new Dimension(afpInfo.getWidth(), afpInfo.getHeight()); | |||
updateDataObjectInfo(imageObjectInfo, paintingState, imageRendered, targetSize); | |||
return imageObjectInfo; | |||
} | |||
private AFPDataObjectInfo updateDataObjectInfo(AFPImageObjectInfo imageObjectInfo, | |||
AFPPaintingState paintingState, ImageRendered imageRendered, Dimension targetSize) | |||
throws IOException { | |||
int resolution = paintingState.getResolution(); | |||
int maxPixelSize = paintingState.getBitsPerPixel(); | |||
if (paintingState.isColorImages()) { | |||
maxPixelSize *= 3; //RGB only at the moment | |||
} | |||
ImageRendered imageRendered = (ImageRendered) rendererImageInfo.img; | |||
RenderedImage renderedImage = imageRendered.getRenderedImage(); | |||
ImageInfo imageInfo = rendererImageInfo.getImageInfo(); | |||
ImageInfo imageInfo = imageRendered.getInfo(); | |||
ImageSize intrinsicSize = imageInfo.getSize(); | |||
boolean useFS10 = (maxPixelSize == 1) || BitmapImageUtil.isMonochromeImage(renderedImage); | |||
boolean usePageSegments = useFS10 | |||
&& !resourceInfo.getLevel().isInline(); | |||
&& !imageObjectInfo.getResourceInfo().getLevel().isInline(); | |||
ImageSize effIntrinsicSize = intrinsicSize; | |||
if (usePageSegments) { | |||
//Resize, optionally resample and convert image | |||
Dimension resampledDim = new Dimension( | |||
(int)Math.ceil(UnitConv.mpt2px(afpInfo.getWidth(), resolution)), | |||
(int)Math.ceil(UnitConv.mpt2px(afpInfo.getHeight(), resolution))); | |||
(int)Math.ceil(UnitConv.mpt2px(targetSize.getWidth(), resolution)), | |||
(int)Math.ceil(UnitConv.mpt2px(targetSize.getHeight(), resolution))); | |||
imageObjectInfo.setCreatePageSegment(true); | |||
imageObjectInfo.getResourceInfo().setImageDimension(resampledDim); | |||
@@ -130,6 +141,8 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler { | |||
int dataWidth = renderedImage.getWidth(); | |||
imageObjectInfo.setDataWidth(dataWidth); | |||
//TODO To reduce AFP file size, investigate using a compression scheme. | |||
//Currently, all image data is uncompressed. | |||
ColorModel cm = renderedImage.getColorModel(); | |||
if (log.isTraceEnabled()) { | |||
log.trace("ColorModel: " + cm); | |||
@@ -209,6 +222,15 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler { | |||
return imageObjectInfo; | |||
} | |||
private void setDefaultResourceLevel(AFPImageObjectInfo imageObjectInfo, | |||
AFPResourceManager resourceManager) { | |||
AFPResourceInfo resourceInfo = imageObjectInfo.getResourceInfo(); | |||
if (!resourceInfo.levelChanged()) { | |||
resourceInfo.setLevel(resourceManager.getResourceLevelDefaults() | |||
.getDefaultResourceLevel(ResourceObject.TYPE_IMAGE)); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
protected AFPDataObjectInfo createDataObjectInfo() { | |||
return new AFPImageObjectInfo(); | |||
@@ -229,4 +251,35 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler { | |||
return FLAVORS; | |||
} | |||
/** {@inheritDoc} */ | |||
public void handleImage(RenderingContext context, Image image, Rectangle pos) | |||
throws IOException { | |||
AFPRenderingContext afpContext = (AFPRenderingContext)context; | |||
AFPImageObjectInfo imageObjectInfo = (AFPImageObjectInfo)createDataObjectInfo(); | |||
// set resource information | |||
setResourceInformation(imageObjectInfo, | |||
image.getInfo().getOriginalURI(), | |||
afpContext.getForeignAttributes()); | |||
setDefaultResourceLevel(imageObjectInfo, afpContext.getResourceManager()); | |||
// Positioning | |||
imageObjectInfo.setObjectAreaInfo(createObjectAreaInfo(afpContext.getPaintingState(), pos)); | |||
Dimension targetSize = pos.getSize(); | |||
// Image content | |||
ImageRendered imageRend = (ImageRendered)image; | |||
updateDataObjectInfo(imageObjectInfo, afpContext.getPaintingState(), imageRend, targetSize); | |||
// Create image | |||
afpContext.getResourceManager().createObject(imageObjectInfo); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isCompatible(RenderingContext targetContext, Image image) { | |||
return (image == null || image instanceof ImageRendered) | |||
&& targetContext instanceof AFPRenderingContext; | |||
} | |||
} |