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
<include name="org/apache/fop/area/AreaTreeControl*"/> | <include name="org/apache/fop/area/AreaTreeControl*"/> | ||||
<include name="org/apache/fop/svg/**"/> | <include name="org/apache/fop/svg/**"/> | ||||
<include name="org/apache/fop/fonts/**"/> | <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/CMYKColorSpace*.class"/> | ||||
<include name="org/apache/fop/util/Color*.class"/> | <include name="org/apache/fop/util/Color*.class"/> | ||||
<include name="org/apache/fop/util/ASCII*.class"/> | <include name="org/apache/fop/util/ASCII*.class"/> | ||||
<include name="org/apache/fop/util/SubInputStream.class"/> | <include name="org/apache/fop/util/SubInputStream.class"/> | ||||
<include name="org/apache/fop/util/Finalizable.class"/> | <include name="org/apache/fop/util/Finalizable.class"/> | ||||
<include name="org/apache/fop/util/CharUtilities.class"/> | <include name="org/apache/fop/util/CharUtilities.class"/> | ||||
<include name="org/apache/fop/util/DecimalFormatCache*.class"/> | |||||
</patternset> | </patternset> | ||||
<!-- PDF transcoder --> | <!-- PDF transcoder --> | ||||
<patternset> | <patternset> | ||||
<include name="org/apache/fop/render/pdf/**"/> | <include name="org/apache/fop/render/pdf/**"/> | ||||
<exclude name="org/apache/fop/render/pdf/PDFRenderer.class"/> | <exclude name="org/apache/fop/render/pdf/PDFRenderer.class"/> | ||||
<exclude name="org/apache/fop/render/pdf/PDFXMLHandler*"/> | <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/render/*RendererConfigurator**"/> | ||||
<include name="org/apache/fop/util/AbstractPaintingState**"/> | <include name="org/apache/fop/util/AbstractPaintingState**"/> | ||||
<include name="org/apache/fop/pdf/**"/> | <include name="org/apache/fop/pdf/**"/> | ||||
<test name="org.apache.fop.fotreetest.FOTreeTestSuite" todir="${junit.reports.dir}" outfile="TEST-FO-tree"/> | <test name="org.apache.fop.fotreetest.FOTreeTestSuite" todir="${junit.reports.dir}" outfile="TEST-FO-tree"/> | ||||
</junit> | </junit> | ||||
</target> | </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> | ||||
<target name="junit-text-linebreak" depends="junit-compile" description="Runs FOP's JUnit unicode linebreak tests" if="junit.present"> | <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"/> | <echo message="Running tests for Unicode UAX#14 support"/> | ||||
</junit> | </junit> | ||||
</target> | </target> | ||||
<target name="junit-reduced" depends="junit-userconfig, junit-basic, junit-transcoder, junit-text-linebreak, junit-fotree"/> | <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"> | <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> | <fail><condition><or><isset property="fop.junit.error"/><isset property="fop.junit.failure"/><not><isset property="hyphenation.present"/></not></or></condition> | ||||
NOTE: | NOTE: |
/* | |||||
* 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); | |||||
} | |||||
} | |||||
} |
/* | |||||
* 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); | |||||
} | |||||
} | |||||
} |
import javax.xml.transform.TransformerException; | import javax.xml.transform.TransformerException; | ||||
import javax.xml.transform.TransformerFactory; | import javax.xml.transform.TransformerFactory; | ||||
import javax.xml.transform.sax.SAXResult; | import javax.xml.transform.sax.SAXResult; | ||||
import javax.xml.transform.stream.StreamResult; | |||||
import javax.xml.transform.stream.StreamSource; | import javax.xml.transform.stream.StreamSource; | ||||
import org.xml.sax.SAXException; | |||||
import org.apache.fop.apps.FOPException; | import org.apache.fop.apps.FOPException; | ||||
import org.apache.fop.apps.FOUserAgent; | import org.apache.fop.apps.FOUserAgent; | ||||
import org.apache.fop.apps.Fop; | import org.apache.fop.apps.Fop; | ||||
import org.apache.fop.apps.FopFactory; | import org.apache.fop.apps.FopFactory; | ||||
import org.apache.fop.apps.MimeConstants; | 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.ExampleObj2XML; | ||||
import embedding.model.ProjectMember; | import embedding.model.ProjectMember; | ||||
/** | /** | ||||
* Example for the intermediate format that demonstrates the concatenation of two documents | * 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. | * files. | ||||
*/ | */ | ||||
public class ExampleConcat { | public class ExampleConcat { | ||||
* Converts an XSL-FO document to an intermediate file. | * Converts an XSL-FO document to an intermediate file. | ||||
* @param src the source file | * @param src the source file | ||||
* @param xslt the stylesheet 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 IOException In case of an I/O problem | ||||
* @throws FOPException In case of a FOP problem | * @throws FOPException In case of a FOP problem | ||||
* @throws TransformerException In case of a XSL transformation problem | * @throws TransformerException In case of a XSL transformation problem | ||||
//Create a user agent | //Create a user agent | ||||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | 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 | // Setup output | ||||
OutputStream out = new java.io.FileOutputStream(intermediate); | OutputStream out = new java.io.FileOutputStream(intermediate); | ||||
out = new java.io.BufferedOutputStream(out); | out = new java.io.BufferedOutputStream(out); | ||||
try { | 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) | // on the user agent) | ||||
Fop fop = fopFactory.newFop(null, userAgent, out); | Fop fop = fopFactory.newFop(null, userAgent, out); | ||||
/** | /** | ||||
* Concatenates an array of intermediate files to a single PDF file. | * 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 | * @param pdffile the target PDF file | ||||
* @throws IOException In case of an I/O problem | * @throws IOException In case of an I/O problem | ||||
* @throws TransformerException In case of a XSL transformation problem | * @throws TransformerException In case of a XSL transformation problem | ||||
* @throws SAXException In case of an XML-related 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) | public void concatToPDF(File[] files, File pdffile) | ||||
throws IOException, TransformerException, SAXException { | |||||
throws IOException, TransformerException, SAXException, IFException { | |||||
// Setup output | // Setup output | ||||
OutputStream out = new java.io.FileOutputStream(pdffile); | OutputStream out = new java.io.FileOutputStream(pdffile); | ||||
out = new java.io.BufferedOutputStream(out); | out = new java.io.BufferedOutputStream(out); | ||||
try { | try { | ||||
//Setup fonts and user agent | |||||
FontInfo fontInfo = new FontInfo(); | |||||
//Setup user agent | |||||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | 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 | //Iterate over all intermediate files | ||||
AreaTreeParser parser = new AreaTreeParser(); | |||||
for (int i = 0; i < files.length; i++) { | for (int i = 0; i < files.length; i++) { | ||||
Source src = new StreamSource(files[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 { | } finally { | ||||
out.close(); | out.close(); | ||||
} | } | ||||
*/ | */ | ||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
try { | try { | ||||
System.out.println("FOP ExampleConcat\n"); | |||||
System.out.println("FOP ExampleConcat (for the Intermediate Format)\n"); | |||||
//Setup directories | //Setup directories | ||||
File baseDir = new File("."); | File baseDir = new File("."); | ||||
//Setup output file | //Setup output file | ||||
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl"); | File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl"); | ||||
File[] files = new File[] { | 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++) { | for (int i = 0; i < files.length; i++) { | ||||
System.out.println("Intermediate file " + (i + 1) + ": " | System.out.println("Intermediate file " + (i + 1) + ": " | ||||
+ files[i].getCanonicalPath()); | + files[i].getCanonicalPath()); |
import javax.xml.transform.TransformerException; | import javax.xml.transform.TransformerException; | ||||
import javax.xml.transform.TransformerFactory; | import javax.xml.transform.TransformerFactory; | ||||
import javax.xml.transform.sax.SAXResult; | import javax.xml.transform.sax.SAXResult; | ||||
import javax.xml.transform.stream.StreamResult; | |||||
import javax.xml.transform.stream.StreamSource; | import javax.xml.transform.stream.StreamSource; | ||||
import org.xml.sax.SAXException; | |||||
import org.apache.fop.apps.FOUserAgent; | import org.apache.fop.apps.FOUserAgent; | ||||
import org.apache.fop.apps.FopFactory; | import org.apache.fop.apps.FopFactory; | ||||
import org.apache.fop.apps.MimeConstants; | 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.ExampleObj2XML; | ||||
import embedding.model.ProjectTeam; | import embedding.model.ProjectTeam; | ||||
/** | /** | ||||
* Stamps an intermediate file and renders it to a PDF file. | * 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 stampSheet the stylesheet that does the stamping | ||||
* @param pdffile the target PDF file | * @param pdffile the target PDF file | ||||
* @throws IOException In case of an I/O problem | * @throws IOException In case of an I/O problem | ||||
* @throws TransformerException In case of a XSL transformation problem | * @throws TransformerException In case of a XSL transformation problem | ||||
* @throws SAXException In case of an XML-related 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 | // Setup output | ||||
OutputStream out = new java.io.FileOutputStream(pdffile); | OutputStream out = new java.io.FileOutputStream(pdffile); | ||||
out = new java.io.BufferedOutputStream(out); | out = new java.io.BufferedOutputStream(out); | ||||
try { | try { | ||||
//Setup fonts and user agent | |||||
FontInfo fontInfo = new FontInfo(); | |||||
//user agent | |||||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | 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); | Source xslt = new StreamSource(stampSheet); | ||||
//Setup Transformer for XSLT processing | //Setup Transformer for XSLT processing | ||||
Transformer transformer = tFactory.newTransformer(xslt); | Transformer transformer = tFactory.newTransformer(xslt); | ||||
//Send XSLT result to AreaTreeParser | //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 | //Start XSLT transformation and area tree parsing | ||||
transformer.transform(src, res); | transformer.transform(src, res); | ||||
//Signal the end of the processing. The renderer can finalize the target document. | |||||
treeModel.endDocument(); | |||||
} finally { | } finally { | ||||
out.close(); | out.close(); | ||||
} | } | ||||
*/ | */ | ||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
try { | try { | ||||
System.out.println("FOP ExampleConcat\n"); | |||||
System.out.println("FOP ExampleConcat (for the Intermediate Format)\n"); | |||||
//Setup directories | //Setup directories | ||||
File baseDir = new File("."); | File baseDir = new File("."); | ||||
//Setup output file | //Setup output file | ||||
File xsltfile = new File(baseDir, "xml/xslt/projectteam2fo.xsl"); | 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("Stamp XSLT: " + stampxsltfile.getCanonicalPath()); | ||||
System.out.println("PDF Output File: " + pdffile.getCanonicalPath()); | System.out.println("PDF Output File: " + pdffile.getCanonicalPath()); | ||||
System.out.println(); | System.out.println(); | ||||
ExampleConcat concatapp = new ExampleConcat(); | ExampleConcat concatapp = new ExampleConcat(); | ||||
concatapp.convertToIntermediate( | concatapp.convertToIntermediate( | ||||
team1.getSourceForProjectTeam(), | team1.getSourceForProjectTeam(), | ||||
new StreamSource(xsltfile), atfile); | |||||
new StreamSource(xsltfile), iffile); | |||||
//Stamp document and produce a PDF from the intermediate format | //Stamp document and produce a PDF from the intermediate format | ||||
ExampleStamp app = new ExampleStamp(); | ExampleStamp app = new ExampleStamp(); | ||||
app.stampToPDF(atfile, stampxsltfile, pdffile); | |||||
app.stampToPDF(iffile, stampxsltfile, pdffile); | |||||
System.out.println("Success!"); | System.out.println("Success!"); | ||||
<?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> |
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import javax.xml.transform.ErrorListener; | |||||
import javax.xml.transform.Source; | import javax.xml.transform.Source; | ||||
import javax.xml.transform.Transformer; | import javax.xml.transform.Transformer; | ||||
import javax.xml.transform.TransformerException; | import javax.xml.transform.TransformerException; | ||||
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; | import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; | ||||
import org.apache.xmlgraphics.image.loader.util.ImageUtil; | import org.apache.xmlgraphics.image.loader.util.ImageUtil; | ||||
import org.apache.fop.util.DefaultErrorListener; | |||||
import org.apache.fop.util.UnclosableInputStream; | import org.apache.fop.util.UnclosableInputStream; | ||||
/** | /** | ||||
InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src)); | InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src)); | ||||
try { | 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(); | Element rootEl = planDoc.getDocumentElement(); | ||||
if (!PlanElementMapping.NAMESPACE.equals(rootEl.getNamespaceURI())) { | |||||
if (!PlanElementMapping.NAMESPACE.equals( | |||||
rootEl.getNamespaceURI())) { | |||||
in.reset(); | in.reset(); | ||||
return null; | return null; | ||||
} | } | ||||
//Have to render the plan to know its size | |||||
PlanRenderer pr = new PlanRenderer(); | |||||
Document svgDoc = pr.createSVGDocument(planDoc); | Document svgDoc = pr.createSVGDocument(planDoc); | ||||
float width = pr.getWidth(); | float width = pr.getWidth(); | ||||
float height = pr.getHeight(); | float height = pr.getHeight(); | ||||
} | } | ||||
} | } | ||||
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; | |||||
} | |||||
} | } |
import org.w3c.dom.Element; | import org.w3c.dom.Element; | ||||
import org.apache.batik.dom.svg.SVGDOMImplementation; | import org.apache.batik.dom.svg.SVGDOMImplementation; | ||||
import org.apache.fop.svg.SVGUtilities; | import org.apache.fop.svg.SVGUtilities; | ||||
/** | /** | ||||
String title = ""; | String title = ""; | ||||
DOMImplementation impl = | |||||
SVGDOMImplementation.getDOMImplementation(); | |||||
DOMImplementation impl | |||||
= SVGDOMImplementation.getDOMImplementation(); | |||||
Document doc = impl.createDocument(SVG_NAMESPACE, "svg", null); | Document doc = impl.createDocument(SVG_NAMESPACE, "svg", null); | ||||
Element svgRoot = doc.getDocumentElement(); | 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", | svgRoot.setAttributeNS(null, "style", | ||||
"font-size:" + 8 | "font-size:" + 8 | ||||
+ ";font-family:" | + ";font-family:" | ||||
java.awt.Font.PLAIN, (int)fontSize); | java.awt.Font.PLAIN, (int)fontSize); | ||||
if (bord) { | 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"); | border.setAttributeNS(null, "style", "stroke:black;fill:none"); | ||||
svgRoot.appendChild(border); | svgRoot.appendChild(border); | ||||
} | } |
</header> | </header> | ||||
<body> | <body> | ||||
<note> | <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> | </note> | ||||
<section id="introduction"> | <section id="introduction"> | ||||
<title>Introduction</title> | <title>Introduction</title> | ||||
<p> | <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>. | <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> | ||||
<p> | <p> | ||||
The intermediate format can be used to generate intermediate documents that are modified | The intermediate format can be used to generate intermediate documents that are modified | ||||
to a single output file. | to a single output file. | ||||
</p> | </p> | ||||
</section> | </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"> | <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> | <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> | ||||
<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> | ||||
<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> | </p> | ||||
<source><![CDATA[ | <source><![CDATA[ | ||||
FopFactory fopFactory = FopFactory.newInstance(); | FopFactory fopFactory = FopFactory.newInstance(); | ||||
AreaTreeModel treeModel = new RenderPagesModel(userAgent, | AreaTreeModel treeModel = new RenderPagesModel(userAgent, | ||||
MimeConstants.MIME_PDF, fontInfo, out); | 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(); | AreaTreeParser parser = new AreaTreeParser(); | ||||
Source src = new StreamSource(myIFFile); | Source src = new StreamSource(myIFFile); | ||||
parser.parse(src, treeModel, userAgent); | parser.parse(src, treeModel, userAgent); | ||||
out.close(); | out.close(); | ||||
}]]></source> | }]]></source> | ||||
<p> | <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 | 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 | 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 | applies to the AreaTreeModel instance, in this case an instance of a subclass called | ||||
is now finished. | is now finished. | ||||
</p> | </p> | ||||
<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 | 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. | specify a "mimic renderer" by inserting a MIME type between "-at" and the output file. | ||||
</p> | </p> | ||||
<title>Concatenating Documents</title> | <title>Concatenating Documents</title> | ||||
<p> | <p> | ||||
This initial example is obviously not very useful. It would be faster to create the PDF file | 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 | same AreaTreeModel instance which essentially concatenates all the input document to one single | ||||
output document. | output document. | ||||
</p> | </p> | ||||
<section id="modifying"> | <section id="modifying"> | ||||
<title>Modifying Documents</title> | <title>Modifying Documents</title> | ||||
<p> | <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 | 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 | 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. | later time. You're invited to help us with that. | ||||
</p> | </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> | ||||
<section id="advanced"> | <section id="advanced"> | ||||
<title>Advanced Use</title> | <title>Advanced Use</title> | ||||
<p> | <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 | 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 | 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 | do custom serialization (to a W3C DOM, for example) and/or to directly modify the area tree using | ||||
</p> | </p> | ||||
</section> | </section> | ||||
</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> | </body> | ||||
</document> | </document> |
<document xmlns="http://xmlgraphics.apache.org/fop/intermediate" | <document xmlns="http://xmlgraphics.apache.org/fop/intermediate" | ||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
xsi:schemaLocation="http://xmlgraphics.apache.org/fop/intermediate fop-intermediate-format-ng.xsd" | 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> | <header> | ||||
<x:xmpmeta xmlns:x="adobe:ns:meta/"> | <x:xmpmeta xmlns:x="adobe:ns:meta/"> | ||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> | <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> | ||||
</header> | </header> | ||||
<page-sequence id="ps1"> | <page-sequence id="ps1"> | ||||
<page index="1" name="1"> | |||||
<page index="0" name="1" width="595275" height="841889"> | |||||
<page-header> | <page-header> | ||||
<ps:ps-setup-code xmlns:ps="apache:fop:extensions:postscript">%FOPTestPSSetupCode: General | <ps:ps-setup-code xmlns:ps="apache:fop:extensions:postscript">%FOPTestPSSetupCode: General | ||||
setup code here!</ps:ps-setup-code> | setup code here!</ps:ps-setup-code> | ||||
<content> | <content> | ||||
<!-- Note: this is not actual content that is supposed to make any sense. | <!-- 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. --> | 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" | <font family="Helvetica" style="normal" weight="400" variant="normal" size="12000" | ||||
color="black"/> | 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"/> | <image xlink:href="myimage.svg" x="0" y="0" width="20000" height="20000"/> | ||||
</box> | |||||
</box> | |||||
</viewport> | |||||
</viewport> | |||||
</content> | </content> | ||||
<page-trailer> | <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-trailer> | ||||
</page> | </page> | ||||
</page-sequence> | </page-sequence> | ||||
<trailer/> | |||||
</document> | </document> |
targetNamespace="http://xmlgraphics.apache.org/fop/intermediate" | targetNamespace="http://xmlgraphics.apache.org/fop/intermediate" | ||||
xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate"> | xmlns:mf="http://xmlgraphics.apache.org/fop/intermediate"> | ||||
<xs:include schemaLocation="fop-intermediate-format-ng-datatypes.xsd"/> | <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:complexType name="contentType"> | ||||
<xs:choice maxOccurs="unbounded" minOccurs="0"> | <xs:choice maxOccurs="unbounded" minOccurs="0"> | ||||
<xs:element name="box"> | |||||
<xs:element name="viewport"> | |||||
<xs:complexType> | <xs:complexType> | ||||
<xs:complexContent> | <xs:complexContent> | ||||
<xs:extension base="mf:contentType"> | <xs:extension base="mf:contentType"> | ||||
<xs:attribute name="transform" type="xs:string"/> | <xs:attribute name="transform" type="xs:string"/> | ||||
<xs:attributeGroup ref="mf:sizeAtts"/> | <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:extension> | ||||
</xs:complexContent> | </xs:complexContent> | ||||
</xs:complexType> | </xs:complexType> | ||||
<xs:attribute name="variant" type="mf:fontVariantType"/> | <xs:attribute name="variant" type="mf:fontVariantType"/> | ||||
<xs:attribute name="weight" type="mf:fontWeightType"/> | <xs:attribute name="weight" type="mf:fontWeightType"/> | ||||
<xs:attribute name="stretch" type="mf:fontStretchType"/> | <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:attribute name="color" type="mf:colorType"/> | ||||
</xs:complexType> | </xs:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:complexType> | <xs:complexType> | ||||
<xs:simpleContent> | <xs:simpleContent> | ||||
<xs:extension base="xs:string"> | <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:simpleType> | ||||
<xs:list itemType="xs:integer"/> | |||||
<xs:list itemType="mf:lengthType"/> | |||||
</xs:simpleType> | </xs:simpleType> | ||||
</xs:attribute> | </xs:attribute> | ||||
<xs:attribute ref="xml:space"/> | |||||
</xs:extension> | </xs:extension> | ||||
</xs:simpleContent> | </xs:simpleContent> | ||||
</xs:complexType> | </xs:complexType> | ||||
</xs:element> | </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:complexType> | ||||
<xs:attribute name="d" type="mf:pathDataType" use="required"/> | |||||
<xs:attributeGroup ref="mf:fillStrokeAtts"/> | |||||
<xs:attributeGroup ref="mf:rectAtts"/> | |||||
</xs:complexType> | </xs:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:element name="clip-rect"> | |||||
<xs:element name="rect"> | |||||
<xs:complexType> | <xs:complexType> | ||||
<xs:attributeGroup ref="mf:rectAtts"/> | <xs:attributeGroup ref="mf:rectAtts"/> | ||||
<xs:attributeGroup ref="mf:fillAtts"/> | |||||
</xs:complexType> | </xs:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:element name="draw-rect"> | |||||
<xs:element name="line"> | |||||
<xs:complexType> | <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:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:element name="draw-border-line"> | |||||
<xs:element name="border-rect"> | |||||
<xs:complexType> | <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:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:element name="image"> | <xs:element name="image"> | ||||
<xs:extension base="xs:anyType"> | <xs:extension base="xs:anyType"> | ||||
<!-- Either use element content with any namespace or xlink:href --> | <!-- Either use element content with any namespace or xlink:href --> | ||||
<xs:attributeGroup ref="mf:rectAtts"/> | <xs:attributeGroup ref="mf:rectAtts"/> | ||||
<xs:anyAttribute namespace="http://www.w3.org/1999/xlink" processContents="skip"/> | |||||
<xs:attributeGroup ref="mf:foreignAtts"/> | |||||
</xs:extension> | </xs:extension> | ||||
</xs:complexContent> | </xs:complexContent> | ||||
</xs:complexType> | </xs:complexType> | ||||
</xs:choice> | </xs:choice> | ||||
</xs:complexType> | </xs:complexType> | ||||
<xs:attributeGroup name="sizeAtts"> | <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> | ||||
<xs:attributeGroup name="rectAtts"> | <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 ref="mf:sizeAtts"/> | ||||
</xs:attributeGroup> | </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="fill" type="xs:string" default="none"/> | ||||
<xs:attribute name="stroke" 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:attributeGroup> | ||||
</xs:schema> | </xs:schema> |
<xs:simpleType name="colorType"> | <xs:simpleType name="colorType"> | ||||
<xs:restriction base="xs:string"/> | <xs:restriction base="xs:string"/> | ||||
</xs:simpleType> | </xs:simpleType> | ||||
<xs:simpleType name="pathDataType"> | |||||
<xs:restriction base="xs:string"/> | |||||
<xs:simpleType name="lengthType"> | |||||
<xs:restriction base="xs:int"/> | |||||
</xs:simpleType> | </xs:simpleType> | ||||
<xs:simpleType name="fontStyleType"> | <xs:simpleType name="fontStyleType"> | ||||
<xs:restriction base="xs:string"> | <xs:restriction base="xs:string"> | ||||
<xs:enumeration value="outset"/> | <xs:enumeration value="outset"/> | ||||
</xs:restriction> | </xs:restriction> | ||||
</xs:simpleType> | </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> | </xs:schema> |
<?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> |
<!-- $Id$ --> | <!-- $Id$ --> | ||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" | <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" | ||||
targetNamespace="http://xmlgraphics.apache.org/fop/intermediate" | 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="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-datatypes.xsd"/> | ||||
<xs:include schemaLocation="fop-intermediate-format-ng-content.xsd"/> | <xs:include schemaLocation="fop-intermediate-format-ng-content.xsd"/> | ||||
<xs:element name="document"> | <xs:element name="document"> | ||||
<xs:complexType> | <xs:complexType> | ||||
<xs:sequence> | <xs:sequence> | ||||
<xs:element ref="mf:header"/> | <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:sequence> | ||||
</xs:complexType> | </xs:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:element name="header"> | <xs:element name="header"> | ||||
<xs:complexType> | <xs:complexType> | ||||
<xs:choice minOccurs="0" maxOccurs="unbounded"> | <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:choice> | ||||
</xs:complexType> | </xs:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:element name="bookmark-tree"> | |||||
<xs:element name="trailer"> | |||||
<xs:complexType> | <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:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:element name="page-sequence"> | <xs:element name="page-sequence"> | ||||
<xs:complexType> | <xs:complexType> | ||||
<xs:sequence> | <xs:sequence> | ||||
<xs:element ref="mf:page"/> | |||||
<xs:element ref="mf:page" minOccurs="1" maxOccurs="unbounded"/> | |||||
</xs:sequence> | </xs:sequence> | ||||
<xs:attribute name="id" type="xs:ID"/> | <xs:attribute name="id" type="xs:ID"/> | ||||
<xs:attributeGroup ref="mf:foreignAtts"/> | |||||
</xs:complexType> | </xs:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:element name="page"> | <xs:element name="page"> | ||||
<xs:complexType> | <xs:complexType> | ||||
<xs:sequence> | <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="content" type="mf:contentType"/> | ||||
<xs:element name="page-trailer" minOccurs="0"> | <xs:element name="page-trailer" minOccurs="0"> | ||||
<xs:complexType> | <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:complexType> | ||||
</xs:element> | </xs:element> | ||||
</xs:sequence> | </xs:sequence> | ||||
<xs:attribute name="index" type="xs:nonNegativeInteger" use="required"/> | <xs:attribute name="index" type="xs:nonNegativeInteger" use="required"/> | ||||
<xs:attribute name="name" type="xs:string"/> | <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:complexType> | ||||
</xs:element> | </xs:element> | ||||
<xs:complexType name="anyContent"> | |||||
<xs:choice minOccurs="0" maxOccurs="unbounded"> | |||||
<xs:any namespace="##other" processContents="lax"/> | |||||
</xs:choice> | |||||
</xs:complexType> | |||||
</xs:schema> | </xs:schema> |
<?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> |
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 |
org.apache.fop.render.awt.AWTRendererMaker | org.apache.fop.render.awt.AWTRendererMaker | ||||
org.apache.fop.render.print.PrintRendererMaker | org.apache.fop.render.print.PrintRendererMaker | ||||
org.apache.fop.render.afp.AFPRendererMaker | org.apache.fop.render.afp.AFPRendererMaker | ||||
org.apache.fop.render.pcl.PCLRendererMaker | |||||
org.apache.fop.render.pcl.PCLRendererMaker |
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 |
org.apache.fop.image.loader.batik.ImageConverterSVG2G2D | org.apache.fop.image.loader.batik.ImageConverterSVG2G2D | ||||
org.apache.fop.image.loader.batik.ImageConverterG2D2SVG | |||||
org.apache.fop.image.loader.batik.ImageConverterWMF2G2D | org.apache.fop.image.loader.batik.ImageConverterWMF2G2D |
import org.apache.xmlgraphics.java2d.TextHandler; | import org.apache.xmlgraphics.java2d.TextHandler; | ||||
import org.apache.xmlgraphics.ps.ImageEncodingHelper; | import org.apache.xmlgraphics.ps.ImageEncodingHelper; | ||||
import org.apache.xmlgraphics.util.MimeConstants; | import org.apache.xmlgraphics.util.MimeConstants; | ||||
import org.apache.xmlgraphics.util.UnitConv; | |||||
import org.apache.fop.afp.goca.GraphicsSetLineType; | import org.apache.fop.afp.goca.GraphicsSetLineType; | ||||
import org.apache.fop.afp.modca.GraphicsObject; | import org.apache.fop.afp.modca.GraphicsObject; | ||||
this.gc = gc; | 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. | * Apply the stroke to the AFP graphics object. | ||||
* This takes the java stroke and outputs the appropriate settings | * This takes the java stroke and outputs the appropriate settings | ||||
// set line width | // set line width | ||||
float lineWidth = basicStroke.getLineWidth(); | 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!) | // set line type/style (note: this is an approximation at best!) | ||||
float[] dashArray = basicStroke.getDashArray(); | float[] dashArray = basicStroke.getDashArray(); | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, | public void addNativeImage(org.apache.xmlgraphics.image.loader.Image image, | ||||
float x, float y, float width, float height) { | 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); | + ",x=" + x + ",y=" + y + ",width=" + width + ",height=" + height); | ||||
} | } | ||||
package org.apache.fop.afp; | package org.apache.fop.afp; | ||||
import java.awt.Point; | |||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.afp.fonts.AFPPageFonts; | import org.apache.fop.afp.fonts.AFPPageFonts; | ||||
import org.apache.fop.util.AbstractPaintingState; | import org.apache.fop.util.AbstractPaintingState; | ||||
private int resolution = 240; // 240 dpi | private int resolution = 240; // 240 dpi | ||||
/** the current page */ | /** the current page */ | ||||
private AFPPagePaintingState pagePaintingState = new AFPPagePaintingState(); | |||||
private transient AFPPagePaintingState pagePaintingState = new AFPPagePaintingState(); | |||||
// /** reference orientation */ | // /** reference orientation */ | ||||
// private int orientation = 0; | // private int orientation = 0; | ||||
return this.unitConv; | 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} */ | /** {@inheritDoc} */ | ||||
public Object clone() { | public Object clone() { | ||||
AFPPaintingState paintingState = (AFPPaintingState)super.clone(); | AFPPaintingState paintingState = (AFPPaintingState)super.clone(); |
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.net.URI; | |||||
import java.net.URISyntaxException; | |||||
import java.util.Map; | 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.AbstractNamedAFPObject; | ||||
import org.apache.fop.afp.modca.AbstractPageObject; | import org.apache.fop.afp.modca.AbstractPageObject; | ||||
import org.apache.fop.afp.modca.IncludeObject; | 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.PageSegment; | ||||
import org.apache.fop.afp.modca.Registry; | import org.apache.fop.afp.modca.Registry; | ||||
import org.apache.fop.afp.modca.ResourceGroup; | 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 | * Manages the creation and storage of document resources | ||||
*/ | */ | ||||
public class AFPResourceManager { | public class AFPResourceManager { | ||||
/** logging instance */ | |||||
private static Log log = LogFactory.getLog(AFPResourceManager.class); | |||||
/** The AFP datastream (document tree) */ | /** The AFP datastream (document tree) */ | ||||
private DataStream dataStream; | private DataStream dataStream; | ||||
/** Maintain a reference count of instream objects for referencing purposes */ | /** Maintain a reference count of instream objects for referencing purposes */ | ||||
private int instreamObjectCount = 0; | 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>*/; | = new java.util.HashMap()/*<AFPResourceInfo,String>*/; | ||||
private Map pageSegmentMap = new java.util.HashMap(); | private Map pageSegmentMap = new java.util.HashMap(); | ||||
AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo(); | AFPResourceInfo resourceInfo = dataObjectInfo.getResourceInfo(); | ||||
updateResourceInfoUri(resourceInfo); | updateResourceInfoUri(resourceInfo); | ||||
String objectName = (String)includableObjectsMap.get(resourceInfo); | |||||
String objectName = (String)includeNameMap.get(resourceInfo); | |||||
if (objectName != null) { | if (objectName != null) { | ||||
// an existing data resource so reference it by adding an include to the current page | // an existing data resource so reference it by adding an include to the current page | ||||
includeObject(dataObjectInfo, objectName); | includeObject(dataObjectInfo, objectName); | ||||
useInclude &= resourceGroup != null; | useInclude &= resourceGroup != null; | ||||
if (useInclude) { | 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 { | } else { | ||||
// not to be included so inline data object directly into the current page | // not to be included so inline data object directly into the current page | ||||
private void includeObject(AFPDataObjectInfo dataObjectInfo, | private void includeObject(AFPDataObjectInfo dataObjectInfo, | ||||
String objectName) { | 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, | private void includePageSegment(AFPDataObjectInfo dataObjectInfo, | ||||
String pageSegmentName) { | String pageSegmentName) { | ||||
currentPage.createIncludePageSegment(pageSegmentName, x, y, createHardPageSegments); | 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 | * Sets resource level defaults. The existing defaults over merged with the ones passed in | ||||
* as parameter. | * as parameter. | ||||
public AFPResourceLevelDefaults getResourceLevelDefaults() { | public AFPResourceLevelDefaults getResourceLevelDefaults() { | ||||
return this.resourceLevelDefaults; | return this.resourceLevelDefaults; | ||||
} | } | ||||
} | |||||
} |
* @return a point on the current page | * @return a point on the current page | ||||
*/ | */ | ||||
private Point getPoint(int x, int y) { | 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); | |||||
} | } | ||||
/** | /** |
*/ | */ | ||||
public abstract CharacterSet getCharacterSet(int size); | 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} */ | /** {@inheritDoc} */ |
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.UnsupportedEncodingException; | 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 java.util.Map; | ||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.afp.AFPConstants; | import org.apache.fop.afp.AFPConstants; | ||||
import org.apache.fop.afp.util.StringUtils; | import org.apache.fop.afp.util.StringUtils; | ||||
/** The encoding used for the code page */ | /** The encoding used for the code page */ | ||||
protected String encoding; | protected String encoding; | ||||
/** The charset encoder corresponding to this encoding */ | |||||
private CharsetEncoder encoder; | |||||
/** The character set relating to the font */ | /** The character set relating to the font */ | ||||
protected String name; | protected String name; | ||||
} | } | ||||
this.codePage = codePage; | this.codePage = codePage; | ||||
this.encoding = encoding; | this.encoding = encoding; | ||||
this.encoder = Charset.forName(encoding).newEncoder(); | |||||
this.encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); | |||||
this.path = path; | this.path = path; | ||||
this.characterSetOrientations = new java.util.HashMap(4); | this.characterSetOrientations = new java.util.HashMap(4); | ||||
return c; | 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. | * Map a Unicode character to a code point in the font. | ||||
* The code tables are already converted to Unicode therefore | * The code tables are already converted to Unicode therefore | ||||
* @return the mapped character | * @return the mapped character | ||||
*/ | */ | ||||
public char mapChar(char c) { | public char mapChar(char c) { | ||||
//TODO This is not strictly correct but we'll let it be for the moment | |||||
return c; | return c; | ||||
} | } | ||||
*/ | */ | ||||
public class CharacterSetOrientation { | 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 | * The ascender height for the character set | ||||
*/ | */ | ||||
private int capHeight; | 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 | * The height of lowercase letters | ||||
* @return the widths of all characters | * @return the widths of all characters | ||||
*/ | */ | ||||
public int[] getWidths() { | 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; | return arr; | ||||
} | } | ||||
* @return the widths of the character | * @return the widths of the character | ||||
*/ | */ | ||||
public int getWidth(int characterIndex) { | public int getWidth(int characterIndex) { | ||||
if (characterIndex >= chars.length) { | |||||
if (characterIndex >= charsWidths.length) { | |||||
throw new IllegalArgumentException("Invalid character index: " | throw new IllegalArgumentException("Invalid character index: " | ||||
+ characterIndex + ", maximum is " + (chars.length - 1)); | |||||
+ characterIndex + ", maximum is " + (charsWidths.length - 1)); | |||||
} | } | ||||
return chars[characterIndex]; | |||||
return charsWidths[characterIndex]; | |||||
} | } | ||||
/** | /** | ||||
* @param width the widths of the character | * @param width the widths of the character | ||||
*/ | */ | ||||
public void setWidth(int character, int width) { | public void setWidth(int character, int width) { | ||||
if (character >= chars.length) { | |||||
if (character >= charsWidths.length) { | |||||
// Increase the size of the array if necessary | // 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; | |||||
} | } | ||||
return getWidths(1000); | return getWidths(1000); | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
public boolean hasChar(char c) { | |||||
return charSet.hasChar(c); | |||||
} | |||||
/** | /** | ||||
* Map a Unicode character to a code point in the font. | * Map a Unicode character to a code point in the font. | ||||
* @param c character to map | * @param c character to map | ||||
public String getEncodingName() { | public String getEncodingName() { | ||||
return charSet.getEncoding(); | return charSet.getEncoding(); | ||||
} | } | ||||
} | } |
return getWidths(1000); | return getWidths(1000); | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
public boolean hasChar(char c) { | |||||
return charSet.hasChar(c); | |||||
} | |||||
/** | /** | ||||
* Map a Unicode character to a code point in the font. | * Map a Unicode character to a code point in the font. | ||||
* @param c character to map | * @param c character to map |
* page has a set of data objects associated with it. Each page within a | * 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 | * document is independent from any other page, and each must establish its own | ||||
* environment parameters. | * environment parameters. | ||||
* | |||||
* <p> | |||||
* The page is the level in the document component hierarchy that is used for | * 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 | * 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 | * the page envelope in the data stream are presented when the page is | ||||
* directs the placement and orientation of the data on the page. In addition, | * directs the placement and orientation of the data on the page. In addition, | ||||
* each page contains layout information that specifies the measurement units, | * each page contains layout information that specifies the measurement units, | ||||
* page width, and page depth. | * page width, and page depth. | ||||
* | |||||
* <p> | |||||
* A page is initiated by a begin page structured field and terminated by an end | * 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 | * page structured field. Structured fields that define objects and active | ||||
* environment groups or that specify attributes of the page may be encountered | * environment groups or that specify attributes of the page may be encountered | ||||
* in page state. | * in page state. | ||||
* | |||||
*/ | */ | ||||
public abstract class AbstractPageObject extends AbstractNamedAFPObject implements Completable { | public abstract class AbstractPageObject extends AbstractNamedAFPObject implements Completable { | ||||
* | * | ||||
* @return the presentation text object | * @return the presentation text object | ||||
*/ | */ | ||||
private PresentationTextObject getPresentationTextObject() { | |||||
public PresentationTextObject getPresentationTextObject() { | |||||
if (currentPresentationTextObject == null) { | if (currentPresentationTextObject == null) { | ||||
PresentationTextObject presentationTextObject | PresentationTextObject presentationTextObject | ||||
= factory.createPresentationTextObject(); | = factory.createPresentationTextObject(); |
} | } | ||||
/** | /** | ||||
* 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 | * @param fill true if the following shape is to be filled | ||||
*/ | */ | ||||
public void setFill(boolean fill) { | 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) { | public void setPatternSymbol(byte patternSymbol) { | ||||
if (patternSymbol != graphicsState.patternSymbol) { | if (patternSymbol != graphicsState.patternSymbol) { | ||||
*/ | */ | ||||
public void newSegment() { | public void newSegment() { | ||||
getData().newSegment(); | getData().newSegment(); | ||||
graphicsState.lineWidth = 0; //Looks like a new segment invalidates the graphics state | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
} | } | ||||
/** the internal graphics state */ | /** the internal graphics state */ | ||||
private class GraphicsState { | |||||
private static class GraphicsState { | |||||
/** the current color */ | /** the current color */ | ||||
private Color color; | private Color color; | ||||
/* | |||||
* 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); | |||||
} | |||||
} | |||||
} |
package org.apache.fop.afp.modca; | package org.apache.fop.afp.modca; | ||||
import java.awt.Color; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.io.UnsupportedEncodingException; | |||||
import org.apache.commons.io.output.ByteArrayOutputStream; | 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; | import org.apache.fop.afp.util.BinaryUtils; | ||||
/** | /** | ||||
* that position them - modal control sequences that adjust the positions by | * that position them - modal control sequences that adjust the positions by | ||||
* small amounts - other functions causing text to be presented with differences | * small amounts - other functions causing text to be presented with differences | ||||
* in appearance. | * in appearance. | ||||
* | |||||
* <p> | |||||
* The graphic characters are expected to conform to a coded font representation | * 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 | * 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 | * character in the coded font. The units of measure for linear displacements | ||||
* are derived from the PresentationTextDescriptor or from the hierarchical | * are derived from the PresentationTextDescriptor or from the hierarchical | ||||
* defaults. | * defaults. | ||||
* | |||||
* <p> | |||||
* In addition to graphic character code points, Presentation Text data can | * In addition to graphic character code points, Presentation Text data can | ||||
* contain embedded control sequences. These are strings of two or more bytes | * 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 | * which signal an alternate mode of processing for the content of the current | ||||
* Presentation Text data. | * 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.*/ | /** the maximum size of the presentation text data.*/ | ||||
private static final int MAX_SIZE = 8192; | private static final int MAX_SIZE = 8192; | ||||
/** the AFP data relating to this presentation text data. */ | /** the AFP data relating to this presentation text data. */ | ||||
private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); | 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. | * Default constructor for the PresentationTextData. | ||||
*/ | */ | ||||
this(false); | this(false); | ||||
} | } | ||||
private static final int HEADER_LENGTH = 9; | |||||
/** | /** | ||||
* Constructor for the PresentationTextData, the boolean flag indicate | * Constructor for the PresentationTextData, the boolean flag indicate | ||||
* whether the control sequence prefix should be set to indicate the start | * whether the control sequence prefix should be set to indicate the start | ||||
0x00, // Reserved | 0x00, // Reserved | ||||
0x00, // Reserved | 0x00, // Reserved | ||||
}; | }; | ||||
baos.write(data, 0, 9); | |||||
baos.write(data, 0, HEADER_LENGTH); | |||||
if (controlInd) { | if (controlInd) { | ||||
baos.write(new byte[] {0x2B, (byte) 0xD3}, 0, 2); | baos.write(new byte[] {0x2B, (byte) 0xD3}, 0, 2); | ||||
} | } | ||||
/** | /** | ||||
* 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} */ | /** {@inheritDoc} */ | ||||
public void writeToStream(OutputStream os) throws IOException { | public void writeToStream(OutputStream os) throws IOException { | ||||
assert getBytesAvailable() >= 0; | |||||
byte[] data = baos.toByteArray(); | byte[] data = baos.toByteArray(); | ||||
byte[] size = BinaryUtils.convert(data.length - 1, 2); | byte[] size = BinaryUtils.convert(data.length - 1, 2); | ||||
data[1] = size[0]; | data[1] = size[0]; | ||||
os.write(data); | 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); | |||||
} | |||||
} | } |
import org.apache.fop.afp.AFPLineDataInfo; | import org.apache.fop.afp.AFPLineDataInfo; | ||||
import org.apache.fop.afp.AFPTextDataInfo; | 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 | * The Presentation Text object is the data object used in document processing | ||||
* collection of the graphic characters and control codes is called Presentation | * collection of the graphic characters and control codes is called Presentation | ||||
* Text, and the object that contains the Presentation Text is called the | * Text, and the object that contains the Presentation Text is called the | ||||
* PresentationText object. | * PresentationText object. | ||||
* <p> | |||||
* The content for this object can be created using {@link PtocaBuilder}. | |||||
*/ | */ | ||||
public class PresentationTextObject extends AbstractNamedAFPObject { | public class PresentationTextObject extends AbstractNamedAFPObject { | ||||
*/ | */ | ||||
private List/*<PresentationTextData>*/ presentationTextDataList = null; | private List/*<PresentationTextData>*/ presentationTextDataList = null; | ||||
private PtocaBuilder builder = new DefaultBuilder(); | |||||
/** | /** | ||||
* Construct a new PresentationTextObject for the specified name argument, | * Construct a new PresentationTextObject for the specified name argument, | ||||
* the name should be an 8 character identifier. | * the name should be an 8 character identifier. | ||||
* @throws UnsupportedEncodingException thrown if character encoding is not supported | * @throws UnsupportedEncodingException thrown if character encoding is not supported | ||||
*/ | */ | ||||
public void createTextData(AFPTextDataInfo textDataInfo) throws UnsupportedEncodingException { | 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) { | if (currentPresentationTextData == null) { | ||||
startPresentationTextData(); | startPresentationTextData(); | ||||
} | } | ||||
try { | try { | ||||
currentPresentationTextData.createTextData(textDataInfo); | |||||
} catch (MaximumSizeExceededException msee) { | |||||
endPresentationTextData(); | |||||
createTextData(textDataInfo); | |||||
producer.produce(builder); | |||||
} catch (UnsupportedEncodingException e) { | } catch (UnsupportedEncodingException e) { | ||||
endPresentationTextData(); | endPresentationTextData(); | ||||
throw e; | 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(); | |||||
} | } | ||||
} | } | ||||
* @param lineDataInfo the line data information. | * @param lineDataInfo the line data information. | ||||
*/ | */ | ||||
public void createLineData(AFPLineDataInfo lineDataInfo) { | public void createLineData(AFPLineDataInfo lineDataInfo) { | ||||
if (currentPresentationTextData == null) { | |||||
startPresentationTextData(); | |||||
} | |||||
try { | try { | ||||
currentPresentationTextData.createLineData(lineDataInfo); | |||||
} catch (MaximumSizeExceededException msee) { | |||||
endPresentationTextData(); | |||||
createLineData(lineDataInfo); | |||||
createControlSequences(new LineDataInfoProducer(lineDataInfo)); | |||||
} catch (UnsupportedEncodingException e) { | |||||
handleUnexpectedIOError(e); //Won't happen for lines | |||||
} | } | ||||
} | } | ||||
startPresentationTextData(); | startPresentationTextData(); | ||||
} | } | ||||
try { | try { | ||||
currentPresentationTextData.endControlSequence(); | |||||
} catch (MaximumSizeExceededException msee) { | |||||
builder.endChainedControlSequence(); | |||||
} catch (IOException ioe) { | |||||
endPresentationTextData(); | 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} */ | /** {@inheritDoc} */ | ||||
public String toString() { | public String toString() { | ||||
if (presentationTextDataList != null) { | if (presentationTextDataList != null) { | ||||
return presentationTextDataList.toString(); | return presentationTextDataList.toString(); | ||||
} | } | ||||
return null; | |||||
return super.toString(); | |||||
} | } | ||||
} | } |
/* | |||||
* 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; | |||||
} | |||||
} |
/* | |||||
* 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); | |||||
} | |||||
} |
/* | |||||
* 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; | |||||
} |
/* | |||||
* 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; | |||||
} |
/* | |||||
* 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); | |||||
} | |||||
} |
<!-- | |||||
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> |
package org.apache.fop.afp.svg; | package org.apache.fop.afp.svg; | ||||
import org.apache.fop.svg.AbstractFOPImageElementBridge; | |||||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | 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 | * An AFP specific implementation of a Batik SVGImageElementBridge | ||||
*/ | */ | ||||
public class AFPImageElementBridge extends AbstractFOPImageElementBridge { | public class AFPImageElementBridge extends AbstractFOPImageElementBridge { | ||||
private final ImageFlavor[] supportedFlavors = new ImageFlavor[] | private final ImageFlavor[] supportedFlavors = new ImageFlavor[] | ||||
{ImageFlavor.RAW_JPEG, | |||||
ImageFlavor.RAW_CCITTFAX, | |||||
{//ImageFlavor.RAW_JPEG, | |||||
//ImageFlavor.RAW_CCITTFAX, | |||||
ImageFlavor.GRAPHICS2D, | ImageFlavor.GRAPHICS2D, | ||||
ImageFlavor.XML_DOM}; | |||||
BatikImageFlavors.SVG_DOM}; | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
protected ImageFlavor[] getSupportedFlavours() { | protected ImageFlavor[] getSupportedFlavours() { |
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.afp.AFPGraphics2D; | import org.apache.fop.afp.AFPGraphics2D; | ||||
import org.apache.fop.afp.AFPPaintingState; | import org.apache.fop.afp.AFPPaintingState; | ||||
import org.apache.fop.afp.fonts.AFPFont; | import org.apache.fop.afp.fonts.AFPFont; | ||||
* @return a font reference | * @return a font reference | ||||
*/ | */ | ||||
private int registerPageFont(AFPPageFonts pageFonts, String internalFontName, int fontSize) { | private int registerPageFont(AFPPageFonts pageFonts, String internalFontName, int fontSize) { | ||||
FontInfo fontInfo = getFontInfo(); | |||||
AFPFont afpFont = (AFPFont)fontInfo.getFonts().get(internalFontName); | AFPFont afpFont = (AFPFont)fontInfo.getFonts().get(internalFontName); | ||||
// register if necessary | // register if necessary | ||||
AFPFontAttributes afpFontAttributes = pageFonts.registerFont( | AFPFontAttributes afpFontAttributes = pageFonts.registerFont( | ||||
* {@inheritDoc} | * {@inheritDoc} | ||||
*/ | */ | ||||
public void drawString(Graphics2D g, String str, float x, float y) throws IOException { | 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); | fontReference = registerPageFont(pageFonts, internalFontName, fontSize); | ||||
graphicsObj.setCharacterSet(fontReference); | |||||
// add the character string | |||||
graphicsObj.addString(str, Math.round(x), Math.round(y)); | |||||
} else { | } 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)); | |||||
} | } | ||||
/** | /** |
package org.apache.fop.afp.svg; | 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.AbstractFOPTextPainter; | ||||
import org.apache.fop.svg.FOPTextHandler; | import org.apache.fop.svg.FOPTextHandler; | ||||
super(nativeTextHandler); | super(nativeTextHandler); | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
protected boolean isSupportedGraphics2D(Graphics2D g2d) { | |||||
return g2d instanceof AFPGraphics2D; | |||||
} | |||||
} | } |
/* | |||||
* 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; | |||||
} | |||||
} | |||||
} |
/* | |||||
* 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; | |||||
} |
/* | |||||
* 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(); | |||||
} | |||||
} |
import org.apache.fop.render.Renderer; | import org.apache.fop.render.Renderer; | ||||
import org.apache.fop.render.RendererFactory; | import org.apache.fop.render.RendererFactory; | ||||
import org.apache.fop.render.XMLHandlerRegistry; | import org.apache.fop.render.XMLHandlerRegistry; | ||||
import org.apache.fop.render.intermediate.IFDocumentHandler; | |||||
/** | /** | ||||
* This is the user agent for FOP. | * This is the user agent for FOP. | ||||
private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; | private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION; | ||||
private Map rendererOptions = new java.util.HashMap(); | private Map rendererOptions = new java.util.HashMap(); | ||||
private File outputFile = null; | private File outputFile = null; | ||||
private IFDocumentHandler documentHandlerOverride = null; | |||||
private Renderer rendererOverride = null; | private Renderer rendererOverride = null; | ||||
private FOEventHandler foEventHandlerOverride = null; | private FOEventHandler foEventHandlerOverride = null; | ||||
private boolean locatorEnabled = true; // true by default (for error messages). | private boolean locatorEnabled = true; // true by default (for error messages). | ||||
protected String author = null; | protected String author = null; | ||||
/** Title of the document. */ | /** Title of the document. */ | ||||
protected String title = null; | protected String title = null; | ||||
/** Subject of the document. */ | |||||
protected String subject = null; | |||||
/** Set of keywords applicable to this document. */ | /** Set of keywords applicable to this document. */ | ||||
protected String keywords = null; | protected String keywords = null; | ||||
// ---------------------------------------------- rendering-run dependent stuff | // ---------------------------------------------- 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 | * Sets an explicit renderer to use which overrides the one defined by the | ||||
* render type setting. | * render type setting. | ||||
return title; | 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. | * Sets the keywords for the document. | ||||
* @param keywords for the document | * @param keywords for the document |
import org.apache.fop.fonts.FontManager; | import org.apache.fop.fonts.FontManager; | ||||
import org.apache.fop.hyphenation.HyphenationTreeResolver; | import org.apache.fop.hyphenation.HyphenationTreeResolver; | ||||
import org.apache.fop.layoutmgr.LayoutManagerMaker; | import org.apache.fop.layoutmgr.LayoutManagerMaker; | ||||
import org.apache.fop.render.ImageHandlerRegistry; | |||||
import org.apache.fop.render.RendererFactory; | import org.apache.fop.render.RendererFactory; | ||||
import org.apache.fop.render.XMLHandlerRegistry; | import org.apache.fop.render.XMLHandlerRegistry; | ||||
import org.apache.fop.util.ColorSpaceCache; | import org.apache.fop.util.ColorSpaceCache; | ||||
/** Registry for XML handlers */ | /** Registry for XML handlers */ | ||||
private XMLHandlerRegistry xmlHandlers; | private XMLHandlerRegistry xmlHandlers; | ||||
/** Registry for image handlers */ | |||||
private ImageHandlerRegistry imageHandlers; | |||||
/** The registry for ElementMapping instances */ | /** The registry for ElementMapping instances */ | ||||
private ElementMappingRegistry elementMappingRegistry; | private ElementMappingRegistry elementMappingRegistry; | ||||
this.imageManager = new ImageManager(this); | this.imageManager = new ImageManager(this); | ||||
this.rendererFactory = new RendererFactory(); | this.rendererFactory = new RendererFactory(); | ||||
this.xmlHandlers = new XMLHandlerRegistry(); | this.xmlHandlers = new XMLHandlerRegistry(); | ||||
this.imageHandlers = new ImageHandlerRegistry(); | |||||
this.ignoredNamespaces = new java.util.HashSet(); | this.ignoredNamespaces = new java.util.HashSet(); | ||||
} | } | ||||
return this.xmlHandlers; | return this.xmlHandlers; | ||||
} | } | ||||
/** @return the image handler registry */ | |||||
public ImageHandlerRegistry getImageHandlerRegistry() { | |||||
return this.imageHandlers; | |||||
} | |||||
/** @return the element mapping registry */ | /** @return the element mapping registry */ | ||||
public ElementMappingRegistry getElementMappingRegistry() { | public ElementMappingRegistry getElementMappingRegistry() { | ||||
return this.elementMappingRegistry; | return this.elementMappingRegistry; |
String MIME_FOP_PRINT = "application/X-fop-print"; | String MIME_FOP_PRINT = "application/X-fop-print"; | ||||
/** Apache FOP's area tree XML */ | /** Apache FOP's area tree XML */ | ||||
String MIME_FOP_AREA_TREE = "application/X-fop-areatree"; | String MIME_FOP_AREA_TREE = "application/X-fop-areatree"; | ||||
/** Apache FOP's intermediate format XML */ | |||||
String MIME_FOP_IF = "application/X-fop-intermediate-format"; | |||||
} | } |
import javax.xml.transform.sax.SAXTransformerFactory; | import javax.xml.transform.sax.SAXTransformerFactory; | ||||
import javax.xml.transform.sax.TransformerHandler; | 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.Log; | ||||
import org.apache.commons.logging.LogFactory; | 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.apps.FOUserAgent; | ||||
import org.apache.fop.area.Trait.Background; | import org.apache.fop.area.Trait.Background; | ||||
import org.apache.fop.area.Trait.InternalLink; | import org.apache.fop.area.Trait.InternalLink; | ||||
import org.apache.fop.util.ContentHandlerFactoryRegistry; | import org.apache.fop.util.ContentHandlerFactoryRegistry; | ||||
import org.apache.fop.util.ConversionUtils; | import org.apache.fop.util.ConversionUtils; | ||||
import org.apache.fop.util.DefaultErrorListener; | 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 | * This is a parser for the area tree XML (intermediate format) which is used to reread an area | ||||
delegate.startDocument(); | delegate.startDocument(); | ||||
delegate.startElement(uri, localName, qName, attributes); | delegate.startElement(uri, localName, qName, attributes); | ||||
} else { | } else { | ||||
lastAttributes = attributes; | |||||
lastAttributes = new AttributesImpl(attributes); | |||||
boolean handled = true; | boolean handled = true; | ||||
if ("".equals(uri)) { | if ("".equals(uri)) { | ||||
Maker maker = (Maker)makers.get(localName); | Maker maker = (Maker)makers.get(localName); | ||||
if (currentPageViewport != null) { | if (currentPageViewport != null) { | ||||
throw new IllegalStateException("currentPageViewport must be 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 key = attributes.getValue("key"); | ||||
String pageNumberString = attributes.getValue("formatted-nr"); | String pageNumberString = attributes.getValue("formatted-nr"); | ||||
String pageMaster = attributes.getValue("simple-page-master-name"); | 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, | currentPageViewport = new PageViewport(viewArea, | ||||
pageNumber, pageNumberString, | pageNumber, pageNumberString, | ||||
pageMaster, blank); | pageMaster, blank); | ||||
if (rv != null) { | if (rv != null) { | ||||
throw new IllegalStateException("Current RegionViewport must be null"); | throw new IllegalStateException("Current RegionViewport must be null"); | ||||
} | } | ||||
Rectangle2D viewArea = getAttributeAsRectangle2D(attributes, "rect"); | |||||
Rectangle2D viewArea = XMLUtil.getAttributeAsRectangle2D(attributes, "rect"); | |||||
rv = new RegionViewport(viewArea); | rv = new RegionViewport(viewArea); | ||||
transferForeignObjects(attributes, rv); | transferForeignObjects(attributes, rv); | ||||
rv.setClip(getAttributeAsBoolean(attributes, "clipped", false)); | |||||
rv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false)); | |||||
setAreaAttributes(attributes, rv); | setAreaAttributes(attributes, rv); | ||||
setTraits(attributes, rv, SUBSET_COMMON); | setTraits(attributes, rv, SUBSET_COMMON); | ||||
setTraits(attributes, rv, SUBSET_BOX); | setTraits(attributes, rv, SUBSET_BOX); | ||||
throw new IllegalStateException("Current BodyRegion must be null"); | throw new IllegalStateException("Current BodyRegion must be null"); | ||||
} | } | ||||
String regionName = attributes.getValue("name"); | 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(); | RegionViewport rv = getCurrentRegionViewport(); | ||||
body = new BodyRegion(Constants.FO_REGION_BODY, | body = new BodyRegion(Constants.FO_REGION_BODY, | ||||
regionName, rv, columnCount, columnGap); | regionName, rv, columnCount, columnGap); | ||||
transferForeignObjects(attributes, body); | transferForeignObjects(attributes, body); | ||||
body.setCTM(getAttributeAsCTM(attributes, "ctm")); | body.setCTM(getAttributeAsCTM(attributes, "ctm")); | ||||
setAreaAttributes(attributes, body); | setAreaAttributes(attributes, body); | ||||
setTraits(attributes, body, SUBSET_BORDER_PADDING); | |||||
rv.setRegionReference(body); | rv.setRegionReference(body); | ||||
currentPageViewport.getPage().setRegionViewport( | currentPageViewport.getPage().setRegionViewport( | ||||
Constants.FO_REGION_BODY, rv); | Constants.FO_REGION_BODY, rv); | ||||
private class SpanMaker extends AbstractMaker { | private class SpanMaker extends AbstractMaker { | ||||
public void startElement(Attributes attributes) { | 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(); | BodyRegion body = getCurrentBodyRegion(); | ||||
Span span = new Span(columnCount, | Span span = new Span(columnCount, | ||||
body.getColumnGap(), ipd); | body.getColumnGap(), ipd); | ||||
public void startElement(Attributes attributes) { | public void startElement(Attributes attributes) { | ||||
Footnote fn = getCurrentBodyRegion().getFootnote(); | Footnote fn = getCurrentBodyRegion().getFootnote(); | ||||
transferForeignObjects(attributes, fn); | transferForeignObjects(attributes, fn); | ||||
fn.setTop(getAttributeAsInteger(attributes, "top-offset", 0)); | |||||
fn.setTop(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0)); | |||||
areaStack.push(fn); | areaStack.push(fn); | ||||
} | } | ||||
private class BlockMaker extends AbstractMaker { | private class BlockMaker extends AbstractMaker { | ||||
public void startElement(Attributes attributes) { | public void startElement(Attributes attributes) { | ||||
boolean isViewport = getAttributeAsBoolean(attributes, | |||||
boolean isViewport = XMLUtil.getAttributeAsBoolean(attributes, | |||||
"is-viewport-area", false); | "is-viewport-area", false); | ||||
Block block; | Block block; | ||||
if (isViewport) { | if (isViewport) { | ||||
BlockViewport bv = new BlockViewport(); | BlockViewport bv = new BlockViewport(); | ||||
bv.setClip(getAttributeAsBoolean(attributes, "clipped", false)); | |||||
bv.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clipped", false)); | |||||
bv.setCTM(getAttributeAsCTM(attributes, "ctm")); | bv.setCTM(getAttributeAsCTM(attributes, "ctm")); | ||||
if (bv.getPositioning() != BlockViewport.RELATIVE) { | if (bv.getPositioning() != BlockViewport.RELATIVE) { | ||||
bv.setXOffset( | bv.setXOffset( | ||||
getAttributeAsInteger(attributes, "left-position", 0)); | |||||
XMLUtil.getAttributeAsInt(attributes, "left-position", 0)); | |||||
bv.setYOffset( | bv.setYOffset( | ||||
getAttributeAsInteger(attributes, "top-position", 0)); | |||||
XMLUtil.getAttributeAsInt(attributes, "top-position", 0)); | |||||
} | } | ||||
block = bv; | block = bv; | ||||
} else { | } else { | ||||
block.setPositioning(Block.STACK); | block.setPositioning(Block.STACK); | ||||
} | } | ||||
if (attributes.getValue("left-offset") != null) { | 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) { | if (attributes.getValue("top-offset") != null) { | ||||
block.setYOffset(getAttributeAsInteger(attributes, "top-offset", 0)); | |||||
block.setYOffset(XMLUtil.getAttributeAsInt(attributes, "top-offset", 0)); | |||||
} | } | ||||
transferForeignObjects(attributes, block); | transferForeignObjects(attributes, block); | ||||
setAreaAttributes(attributes, block); | setAreaAttributes(attributes, block); | ||||
public void startElement(Attributes attributes) { | public void startElement(Attributes attributes) { | ||||
InlineArea inl = new InlineArea(); | InlineArea inl = new InlineArea(); | ||||
transferForeignObjects(attributes, inl); | transferForeignObjects(attributes, inl); | ||||
inl.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||||
inl.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||||
setAreaAttributes(attributes, inl); | setAreaAttributes(attributes, inl); | ||||
setTraits(attributes, inl, SUBSET_COMMON); | setTraits(attributes, inl, SUBSET_COMMON); | ||||
setTraits(attributes, inl, SUBSET_BOX); | setTraits(attributes, inl, SUBSET_BOX); | ||||
public void startElement(Attributes attributes) { | public void startElement(Attributes attributes) { | ||||
InlineParent ip = new InlineParent(); | InlineParent ip = new InlineParent(); | ||||
transferForeignObjects(attributes, ip); | transferForeignObjects(attributes, ip); | ||||
ip.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||||
ip.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||||
setAreaAttributes(attributes, ip); | setAreaAttributes(attributes, ip); | ||||
setTraits(attributes, ip, SUBSET_COMMON); | setTraits(attributes, ip, SUBSET_COMMON); | ||||
setTraits(attributes, ip, SUBSET_BOX); | setTraits(attributes, ip, SUBSET_BOX); | ||||
public void startElement(Attributes attributes) { | public void startElement(Attributes attributes) { | ||||
InlineBlockParent ibp = new InlineBlockParent(); | InlineBlockParent ibp = new InlineBlockParent(); | ||||
transferForeignObjects(attributes, ibp); | transferForeignObjects(attributes, ibp); | ||||
ibp.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||||
ibp.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||||
setAreaAttributes(attributes, ibp); | setAreaAttributes(attributes, ibp); | ||||
setTraits(attributes, ibp, SUBSET_COMMON); | setTraits(attributes, ibp, SUBSET_COMMON); | ||||
setTraits(attributes, ibp, SUBSET_BOX); | setTraits(attributes, ibp, SUBSET_BOX); | ||||
setTraits(attributes, text, SUBSET_BOX); | setTraits(attributes, text, SUBSET_BOX); | ||||
setTraits(attributes, text, SUBSET_COLOR); | setTraits(attributes, text, SUBSET_COLOR); | ||||
setTraits(attributes, text, SUBSET_FONT); | 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)); | "tlsadjust", 0)); | ||||
text.setTextWordSpaceAdjust(getAttributeAsInteger(attributes, | |||||
text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes, | |||||
"twsadjust", 0)); | "twsadjust", 0)); | ||||
Area parent = (Area)areaStack.peek(); | Area parent = (Area)areaStack.peek(); | ||||
parent.addChildArea(text); | parent.addChildArea(text); | ||||
private class WordMaker extends AbstractMaker { | private class WordMaker extends AbstractMaker { | ||||
public void endElement() { | public void endElement() { | ||||
int offset = getAttributeAsInteger(lastAttributes, "offset", 0); | |||||
int offset = XMLUtil.getAttributeAsInt(lastAttributes, "offset", 0); | |||||
int[] letterAdjust | int[] letterAdjust | ||||
= ConversionUtils.toIntArray( | = ConversionUtils.toIntArray( | ||||
lastAttributes.getValue("letter-adjust"), "\\s"); | lastAttributes.getValue("letter-adjust"), "\\s"); | ||||
private class SpaceMaker extends AbstractMaker { | private class SpaceMaker extends AbstractMaker { | ||||
public void endElement() { | 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 | //TODO the isAdjustable parameter is currently not used/implemented | ||||
if (content.position() > 0) { | if (content.position() > 0) { | ||||
content.flip(); | content.flip(); | ||||
boolean adjustable = getAttributeAsBoolean(lastAttributes, "adj", true); | |||||
boolean adjustable = XMLUtil.getAttributeAsBoolean(lastAttributes, "adj", true); | |||||
SpaceArea space = new SpaceArea(content.charAt(0), offset, adjustable); | SpaceArea space = new SpaceArea(content.charAt(0), offset, adjustable); | ||||
AbstractTextArea text = getCurrentText(); | AbstractTextArea text = getCurrentText(); | ||||
space.setParentArea(text); | space.setParentArea(text); | ||||
setTraits(attributes, leader, SUBSET_BOX); | setTraits(attributes, leader, SUBSET_BOX); | ||||
setTraits(attributes, leader, SUBSET_COLOR); | setTraits(attributes, leader, SUBSET_COLOR); | ||||
setTraits(attributes, leader, SUBSET_FONT); | setTraits(attributes, leader, SUBSET_FONT); | ||||
leader.setOffset(getAttributeAsInteger(attributes, "offset", 0)); | |||||
leader.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); | |||||
String ruleStyle = attributes.getValue("ruleStyle"); | String ruleStyle = attributes.getValue("ruleStyle"); | ||||
if (ruleStyle != null) { | if (ruleStyle != null) { | ||||
leader.setRuleStyle(ruleStyle); | leader.setRuleStyle(ruleStyle); | ||||
} | } | ||||
leader.setRuleThickness( | leader.setRuleThickness( | ||||
getAttributeAsInteger(attributes, "ruleThickness", 0)); | |||||
XMLUtil.getAttributeAsInt(attributes, "ruleThickness", 0)); | |||||
Area parent = (Area)areaStack.peek(); | Area parent = (Area)areaStack.peek(); | ||||
parent.addChildArea(leader); | parent.addChildArea(leader); | ||||
} | } | ||||
setTraits(attributes, viewport, SUBSET_COMMON); | setTraits(attributes, viewport, SUBSET_COMMON); | ||||
setTraits(attributes, viewport, SUBSET_BOX); | setTraits(attributes, viewport, SUBSET_BOX); | ||||
setTraits(attributes, viewport, SUBSET_COLOR); | 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(); | Area parent = (Area)areaStack.peek(); | ||||
parent.addChildArea(viewport); | parent.addChildArea(viewport); | ||||
areaStack.push(viewport); | areaStack.push(viewport); | ||||
public void startElement(Attributes attributes) { | public void startElement(Attributes attributes) { | ||||
String title = attributes.getValue("title"); | String title = attributes.getValue("title"); | ||||
boolean showChildren = getAttributeAsBoolean(attributes, "show-children", false); | |||||
boolean showChildren = XMLUtil.getAttributeAsBoolean( | |||||
attributes, "show-children", false); | |||||
String[] linkdata | String[] linkdata | ||||
= InternalLink.parseXMLAttribute(attributes.getValue("internal-link")); | = InternalLink.parseXMLAttribute(attributes.getValue("internal-link")); | ||||
PageViewport pv = (PageViewport) pageViewportsByKey.get(linkdata[0]); | PageViewport pv = (PageViewport) pageViewportsByKey.get(linkdata[0]); | ||||
transferForeignObjects(attributes, reg); | transferForeignObjects(attributes, reg); | ||||
reg.setCTM(getAttributeAsCTM(attributes, "ctm")); | reg.setCTM(getAttributeAsCTM(attributes, "ctm")); | ||||
setAreaAttributes(attributes, reg); | setAreaAttributes(attributes, reg); | ||||
setTraits(attributes, reg, SUBSET_BORDER_PADDING); | |||||
rv.setRegionReference(reg); | rv.setRegionReference(reg); | ||||
currentPageViewport.getPage().setRegionViewport( | currentPageViewport.getPage().setRegionViewport( | ||||
side, rv); | side, rv); | ||||
Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END, | Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END, | ||||
Trait.START_INDENT, Trait.END_INDENT, | Trait.START_INDENT, Trait.END_INDENT, | ||||
Trait.IS_REFERENCE_AREA, Trait.IS_VIEWPORT_AREA}; | 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) { | private void setTraits(Attributes attributes, Area area, Object[] traitSubset) { | ||||
for (int i = traitSubset.length; --i >= 0;) { | for (int i = traitSubset.length; --i >= 0;) { | ||||
if (repeat != null) { | if (repeat != null) { | ||||
bkg.setRepeat(repeat); | bkg.setRepeat(repeat); | ||||
} | } | ||||
bkg.setHoriz(getAttributeAsInteger(attributes, | |||||
bkg.setHoriz(XMLUtil.getAttributeAsInt(attributes, | |||||
"bkg-horz-offset", 0)); | "bkg-horz-offset", 0)); | ||||
bkg.setVertical(getAttributeAsInteger(attributes, | |||||
bkg.setVertical(XMLUtil.getAttributeAsInt(attributes, | |||||
"bkg-vert-offset", 0)); | "bkg-vert-offset", 0)); | ||||
} | } | ||||
area.addTrait(trait, bkg); | area.addTrait(trait, bkg); | ||||
String fontName = attributes.getValue("font-name"); | String fontName = attributes.getValue("font-name"); | ||||
if (fontName != null) { | if (fontName != null) { | ||||
String fontStyle = attributes.getValue("font-style"); | String fontStyle = attributes.getValue("font-style"); | ||||
int fontWeight = getAttributeAsInteger( | |||||
int fontWeight = XMLUtil.getAttributeAsInt( | |||||
attributes, "font-weight", Font.WEIGHT_NORMAL); | attributes, "font-weight", Font.WEIGHT_NORMAL); | ||||
area.addTrait(trait, | area.addTrait(trait, | ||||
FontInfo.createFontKey(fontName, fontStyle, fontWeight)); | FontInfo.createFontKey(fontName, fontStyle, fontWeight)); | ||||
} | } | ||||
} | } | ||||
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) { | private static CTM getAttributeAsCTM(Attributes attributes, String name) { | ||||
String s = attributes.getValue(name).trim(); | String s = attributes.getValue(name).trim(); | ||||
if (s.startsWith("[") && s.endsWith("]")) { | if (s.startsWith("[") && s.endsWith("]")) { | ||||
} | } | ||||
} | } | ||||
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) { | private static void transferForeignObjects(Attributes atts, AreaTreeObject ato) { | ||||
for (int i = 0, c = atts.getLength(); i < c; i++) { | for (int i = 0, c = atts.getLength(); i < c; i++) { | ||||
String ns = atts.getURI(i); | String ns = atts.getURI(i); |
} | } | ||||
// set borders and padding traits | // set borders and padding traits | ||||
// (a little extensions wrt what prescribed by the specs at 6.4.14) | // (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()); | setRegionReferencePosition(rr, r, rvp.getViewArea()); | ||||
rvp.setRegionReference(rr); | rvp.setRegionReference(rr); | ||||
setRegionViewport(r.getNameId(), rvp); | setRegionViewport(r.getNameId(), rvp); | ||||
FODimension reldims = new FODimension(0, 0); | FODimension reldims = new FODimension(0, 0); | ||||
rr.setCTM(CTM.getCTMandRelDims(r.getReferenceOrientation(), | rr.setCTM(CTM.getCTMandRelDims(r.getReferenceOrientation(), | ||||
r.getWritingMode(), absRegVPRect, reldims)); | 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()); | |||||
} | } | ||||
/** | /** |
blocks.add(child); | 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 | * Set the Coordinate Transformation Matrix which transforms content | ||||
* coordinates in this region reference area which are specified in | * coordinates in this region reference area which are specified in |
import javax.xml.transform.Result; | import javax.xml.transform.Result; | ||||
import javax.xml.transform.sax.SAXResult; | import javax.xml.transform.sax.SAXResult; | ||||
import org.xml.sax.SAXException; | |||||
import org.apache.fop.apps.FOPException; | import org.apache.fop.apps.FOPException; | ||||
import org.apache.fop.apps.FOUserAgent; | import org.apache.fop.apps.FOUserAgent; | ||||
import org.apache.fop.area.AreaTreeModel; | import org.apache.fop.area.AreaTreeModel; | ||||
import org.apache.fop.area.AreaTreeParser; | import org.apache.fop.area.AreaTreeParser; | ||||
import org.apache.fop.area.RenderPagesModel; | import org.apache.fop.area.RenderPagesModel; | ||||
import org.apache.fop.fonts.FontInfo; | 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 { | public class AreaTreeInputHandler extends InputHandler { | ||||
import javax.swing.UIManager; | import javax.swing.UIManager; | ||||
import org.xml.sax.SAXException; | |||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.Version; | import org.apache.fop.Version; | ||||
import org.apache.fop.apps.FOPException; | import org.apache.fop.apps.FOPException; | ||||
import org.apache.fop.apps.FOUserAgent; | import org.apache.fop.apps.FOUserAgent; | ||||
import org.apache.fop.pdf.PDFXMode; | import org.apache.fop.pdf.PDFXMode; | ||||
import org.apache.fop.render.Renderer; | import org.apache.fop.render.Renderer; | ||||
import org.apache.fop.render.awt.AWTRenderer; | 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.pdf.PDFRenderer; | ||||
import org.apache.fop.render.print.PagesMode; | import org.apache.fop.render.print.PagesMode; | ||||
import org.apache.fop.render.print.PrintRenderer; | import org.apache.fop.render.print.PrintRenderer; | ||||
import org.apache.fop.render.xml.XMLRenderer; | import org.apache.fop.render.xml.XMLRenderer; | ||||
import org.apache.fop.util.CommandLineLogger; | import org.apache.fop.util.CommandLineLogger; | ||||
import org.xml.sax.SAXException; | |||||
/** | /** | ||||
* Options parses the commandline arguments | * Options parses the commandline arguments | ||||
public static final int XSLT_INPUT = 2; | public static final int XSLT_INPUT = 2; | ||||
/** input: Area Tree XML file */ | /** input: Area Tree XML file */ | ||||
public static final int AREATREE_INPUT = 3; | public static final int AREATREE_INPUT = 3; | ||||
/** input: Intermediate Format XML file */ | |||||
public static final int IF_INPUT = 4; | |||||
/** input: Image file */ | /** input: Image file */ | ||||
public static final int IMAGE_INPUT = 4; | |||||
public static final int IMAGE_INPUT = 5; | |||||
/* show configuration information */ | /* show configuration information */ | ||||
private Boolean showConfiguration = Boolean.FALSE; | private Boolean showConfiguration = Boolean.FALSE; | ||||
private File xmlfile = null; | private File xmlfile = null; | ||||
/* area tree input file */ | /* area tree input file */ | ||||
private File areatreefile = null; | private File areatreefile = null; | ||||
/* intermediate format input file */ | |||||
private File iffile = null; | |||||
/* area tree input file */ | /* area tree input file */ | ||||
private File imagefile = null; | private File imagefile = null; | ||||
/* output file */ | /* output file */ | ||||
//Make sure the prepared XMLRenderer is used | //Make sure the prepared XMLRenderer is used | ||||
foUserAgent.setRendererOverride(xmlRenderer); | 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; | return true; | ||||
} | } | ||||
i = i + parseXMLInputOption(args, i); | i = i + parseXMLInputOption(args, i); | ||||
} else if (args[i].equals("-atin")) { | } else if (args[i].equals("-atin")) { | ||||
i = i + parseAreaTreeInputOption(args, i); | i = i + parseAreaTreeInputOption(args, i); | ||||
} else if (args[i].equals("-ifin")) { | |||||
i = i + parseIFInputOption(args, i); | |||||
} else if (args[i].equals("-imagein")) { | } else if (args[i].equals("-imagein")) { | ||||
i = i + parseImageInputOption(args, i); | i = i + parseImageInputOption(args, i); | ||||
} else if (args[i].equals("-awt")) { | } else if (args[i].equals("-awt")) { | ||||
i = i + parseCustomOutputOption(args, i); | i = i + parseCustomOutputOption(args, i); | ||||
} else if (args[i].equals("-at")) { | } else if (args[i].equals("-at")) { | ||||
i = i + parseAreaTreeOption(args, i); | i = i + parseAreaTreeOption(args, i); | ||||
} else if (args[i].equals("-if")) { | |||||
i = i + parseIntermediateFormatOption(args, i); | |||||
} else if (args[i].equals("-v")) { | } else if (args[i].equals("-v")) { | ||||
printVersion(); | printVersion(); | ||||
return false; | return false; | ||||
} | } | ||||
private int parseFOInputOption(String[] args, int i) throws FOPException { | private int parseFOInputOption(String[] args, int i) throws FOPException { | ||||
inputmode = FO_INPUT; | |||||
setInputFormat(FO_INPUT); | |||||
if ((i + 1 == args.length) | if ((i + 1 == args.length) | ||||
|| (isOption(args[i + 1]))) { | || (isOption(args[i + 1]))) { | ||||
throw new FOPException("you must specify the fo file for the '-fo' option"); | throw new FOPException("you must specify the fo file for the '-fo' option"); | ||||
} | } | ||||
private int parseXSLInputOption(String[] args, int i) throws FOPException { | private int parseXSLInputOption(String[] args, int i) throws FOPException { | ||||
inputmode = XSLT_INPUT; | |||||
setInputFormat(XSLT_INPUT); | |||||
if ((i + 1 == args.length) | if ((i + 1 == args.length) | ||||
|| (isOption(args[i + 1]))) { | || (isOption(args[i + 1]))) { | ||||
throw new FOPException("you must specify the stylesheet " | throw new FOPException("you must specify the stylesheet " | ||||
} | } | ||||
private int parseXMLInputOption(String[] args, int i) throws FOPException { | private int parseXMLInputOption(String[] args, int i) throws FOPException { | ||||
inputmode = XSLT_INPUT; | |||||
setInputFormat(XSLT_INPUT); | |||||
if ((i + 1 == args.length) | if ((i + 1 == args.length) | ||||
|| (isOption(args[i + 1]))) { | || (isOption(args[i + 1]))) { | ||||
throw new FOPException("you must specify the input file " | throw new FOPException("you must specify the input file " | ||||
} | } | ||||
} | } | ||||
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 { | private int parseAreaTreeInputOption(String[] args, int i) throws FOPException { | ||||
inputmode = AREATREE_INPUT; | |||||
setInputFormat(AREATREE_INPUT); | |||||
if ((i + 1 == args.length) | if ((i + 1 == args.length) | ||||
|| (isOption(args[i + 1]))) { | || (isOption(args[i + 1]))) { | ||||
throw new FOPException("you must specify the Area Tree file for the '-atin' option"); | throw new FOPException("you must specify the Area Tree file for the '-atin' option"); | ||||
} | } | ||||
} | } | ||||
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 { | private int parseImageInputOption(String[] args, int i) throws FOPException { | ||||
inputmode = IMAGE_INPUT; | |||||
setInputFormat(IMAGE_INPUT); | |||||
if ((i + 1 == args.length) | if ((i + 1 == args.length) | ||||
|| (isOption(args[i + 1]))) { | || (isOption(args[i + 1]))) { | ||||
throw new FOPException("you must specify the image file for the '-imagein' option"); | throw new FOPException("you must specify the image file for the '-imagein' option"); | ||||
} | } | ||||
} | } | ||||
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 | * checks whether all necessary information has been given in a consistent way | ||||
*/ | */ | ||||
throw new FOPException( | throw new FOPException( | ||||
"FO output mode is only available if you use -xml and -xsl"); | "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()) { | if (fofile != null && !fofile.exists()) { | ||||
throw new FileNotFoundException("Error: fo file " | throw new FileNotFoundException("Error: fo file " | ||||
+ fofile.getAbsolutePath() | + fofile.getAbsolutePath() | ||||
throw new FOPException( | throw new FOPException( | ||||
"Area Tree Output is not available if Area Tree is used as input!"); | "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()) { | if (areatreefile != null && !areatreefile.exists()) { | ||||
throw new FileNotFoundException("Error: area tree file " | throw new FileNotFoundException("Error: area tree file " | ||||
+ areatreefile.getAbsolutePath() | + areatreefile.getAbsolutePath() | ||||
+ " not found "); | + " not found "); | ||||
} | } | ||||
} else if (inputmode == IMAGE_INPUT) { | |||||
} else if (inputmode == IF_INPUT) { | |||||
if (outputmode.equals(MimeConstants.MIME_XSL_FO)) { | if (outputmode.equals(MimeConstants.MIME_XSL_FO)) { | ||||
throw new FOPException( | throw new FOPException( | ||||
"FO output mode is only available if you use -xml and -xsl"); | "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()) { | if (imagefile != null && !imagefile.exists()) { | ||||
throw new FileNotFoundException("Error: image file " | throw new FileNotFoundException("Error: image file " | ||||
return new InputHandler(fofile); | return new InputHandler(fofile); | ||||
case AREATREE_INPUT: | case AREATREE_INPUT: | ||||
return new AreaTreeInputHandler(areatreefile); | return new AreaTreeInputHandler(areatreefile); | ||||
case IF_INPUT: | |||||
return new IFInputHandler(iffile); | |||||
case XSLT_INPUT: | case XSLT_INPUT: | ||||
return new InputHandler(xmlfile, xsltfile, xsltParams); | return new InputHandler(xmlfile, xsltfile, xsltParams); | ||||
case IMAGE_INPUT: | case IMAGE_INPUT: | ||||
+ " -fo infile xsl:fo input file \n" | + " -fo infile xsl:fo input file \n" | ||||
+ " -xml infile xml input file, must be used together with -xsl \n" | + " -xml infile xml input file, must be used together with -xsl \n" | ||||
+ " -atin infile area tree input file \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" | + " -imagein infile image input file (piping through stdin not supported)\n" | ||||
+ " -xsl stylesheet xslt stylesheet \n \n" | + " -xsl stylesheet xslt stylesheet \n \n" | ||||
+ " -param name value <value> to use for parameter <name> in xslt stylesheet\n" | + " -param name value <value> to use for parameter <name> in xslt stylesheet\n" | ||||
+ " -at [mime] out representation of area tree as XML (outfile req'd) \n" | + " -at [mime] out representation of area tree as XML (outfile req'd) \n" | ||||
+ " specify optional mime output to allow AT to be converted\n" | + " specify optional mime output to allow AT to be converted\n" | ||||
+ " to final format later\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" | + " -print input file will be rendered and sent to the printer \n" | ||||
+ " see options with \"-print help\" \n" | + " see options with \"-print help\" \n" | ||||
+ " -out mime outfile input will be rendered using the given MIME type\n" | + " -out mime outfile input will be rendered using the given MIME type\n" | ||||
} | } | ||||
log.info("xslt stylesheet: " + xsltfile.toString()); | log.info("xslt stylesheet: " + xsltfile.toString()); | ||||
break; | 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: | default: | ||||
log.info("unknown input type"); | log.info("unknown input type"); | ||||
} | } | ||||
} else { | } else { | ||||
log.info("output file: " + outfile.toString()); | 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 { | } else { | ||||
log.info(outputmode); | log.info(outputmode); | ||||
if (this.useStdOut) { | if (this.useStdOut) { |
/* | |||||
* 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); | |||||
} | |||||
} | |||||
} |
import org.apache.fop.apps.FOPException; | import org.apache.fop.apps.FOPException; | ||||
import org.apache.fop.datatypes.Length; | import org.apache.fop.datatypes.Length; | ||||
import org.apache.fop.util.XMLConstants; | |||||
import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener; | import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener; | ||||
/** | /** | ||||
*/ | */ | ||||
public abstract class XMLObj extends FONode implements 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 | // temp reference for attributes | ||||
private Attributes attr = null; | private Attributes attr = null; | ||||
private static HashMap ns = new HashMap(); | private static HashMap ns = new HashMap(); | ||||
static { | static { | ||||
ns.put("xlink", "http://www.w3.org/1999/xlink"); | |||||
ns.put(XMLConstants.XLINK_PREFIX, XMLConstants.XLINK_NAMESPACE); | |||||
} | } | ||||
/** | /** | ||||
} else { | } else { | ||||
String pref = qname.substring(0, idx); | String pref = qname.substring(0, idx); | ||||
String tail = qname.substring(idx + 1); | String tail = qname.substring(idx + 1); | ||||
if (pref.equals("xmlns")) { | |||||
if (pref.equals(XMLConstants.XMLNS_PREFIX)) { | |||||
ns.put(tail, rf); | ns.put(tail, rf); | ||||
} else { | } else { | ||||
element.setAttributeNS((String)ns.get(pref), tail, rf); | element.setAttributeNS((String)ns.get(pref), tail, rf); | ||||
element = doc.getDocumentElement(); | element = doc.getDocumentElement(); | ||||
buildTopLevel(doc, element); | 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()); | getNamespaceURI()); | ||||
} | } | ||||
protected boolean loaded = false; | protected boolean loaded = false; | ||||
/** true if the font will be embedded, false if it will be referenced only. */ | /** true if the font will be embedded, false if it will be referenced only. */ | ||||
protected boolean embedded = true; | protected boolean embedded = true; | ||||
/** true if kerning information shall be loaded if available. */ | |||||
protected boolean useKerning = true; | |||||
/** | /** | ||||
* Default constructor. | * Default constructor. | ||||
* @param fontFileURI the URI to the PFB file of a Type 1 font | * @param fontFileURI the URI to the PFB file of a Type 1 font | ||||
* @param embedded indicates whether the font is embedded or referenced | * @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 | * @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.fontFileURI = fontFileURI; | ||||
this.embedded = embedded; | this.embedded = embedded; | ||||
this.useKerning = useKerning; | |||||
this.resolver = resolver; | this.resolver = resolver; | ||||
} | } | ||||
*/ | */ | ||||
public static CustomFont loadFont(File fontFile, String subFontName, | public static CustomFont loadFont(File fontFile, String subFontName, | ||||
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException { | 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); | |||||
} | } | ||||
/** | /** | ||||
* @throws IOException In case of an I/O error | * @throws IOException In case of an I/O error | ||||
*/ | */ | ||||
public static CustomFont loadFont(URL fontUrl, String subFontName, | 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); | |||||
} | } | ||||
/** | /** | ||||
* @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) | * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) | ||||
* @param embedded indicates whether the font is embedded or referenced | * @param embedded indicates whether the font is embedded or referenced | ||||
* @param encodingMode the requested encoding mode | * @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 | * @param resolver the font resolver to use when resolving URIs | ||||
* @return the newly loaded font | * @return the newly loaded font | ||||
* @throws IOException In case of an I/O error | * @throws IOException In case of an I/O error | ||||
*/ | */ | ||||
public static CustomFont loadFont(String fontFileURI, String subFontName, | 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(); | fontFileURI = fontFileURI.trim(); | ||||
boolean type1 = isType1(fontFileURI); | boolean type1 = isType1(fontFileURI); | ||||
FontLoader loader; | FontLoader loader; | ||||
throw new IllegalArgumentException( | throw new IllegalArgumentException( | ||||
"CID encoding mode not supported for Type 1 fonts"); | "CID encoding mode not supported for Type 1 fonts"); | ||||
} | } | ||||
loader = new Type1FontLoader(fontFileURI, embedded, resolver); | |||||
loader = new Type1FontLoader(fontFileURI, embedded, useKerning, resolver); | |||||
} else { | } else { | ||||
loader = new TTFFontLoader(fontFileURI, subFontName, embedded, encodingMode, resolver); | |||||
loader = new TTFFontLoader(fontFileURI, subFontName, | |||||
embedded, encodingMode, useKerning, resolver); | |||||
} | } | ||||
return loader.getFont(); | return loader.getFont(); | ||||
} | } |
throw new RuntimeException("Cannot load font. No font URIs available."); | throw new RuntimeException("Cannot load font. No font URIs available."); | ||||
} | } | ||||
realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName, | realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName, | ||||
this.embedded, this.encodingMode, resolver); | |||||
this.embedded, this.encodingMode, useKerning, resolver); | |||||
} | } | ||||
if (realFont instanceof FontDescriptor) { | if (realFont instanceof FontDescriptor) { | ||||
realFontDescriptor = (FontDescriptor) realFont; | realFontDescriptor = (FontDescriptor) realFont; |
} | } | ||||
try { | try { | ||||
TTFFontLoader ttfLoader = new TTFFontLoader( | TTFFontLoader ttfLoader = new TTFFontLoader( | ||||
fontFileURI, fontName, true, EncodingMode.AUTO, resolver); | |||||
fontFileURI, fontName, true, EncodingMode.AUTO, true, resolver); | |||||
customFont = ttfLoader.getFont(); | customFont = ttfLoader.getFont(); | ||||
if (this.eventListener != null) { | if (this.eventListener != null) { | ||||
customFont.setEventListener(this.eventListener); | customFont.setEventListener(this.eventListener); |
* @param resolver the FontResolver for font URI resolution | * @param resolver the FontResolver for font URI resolution | ||||
*/ | */ | ||||
public TTFFontLoader(String fontFileURI, FontResolver resolver) { | public TTFFontLoader(String fontFileURI, FontResolver resolver) { | ||||
this(fontFileURI, null, true, EncodingMode.AUTO, resolver); | |||||
this(fontFileURI, null, true, EncodingMode.AUTO, true, resolver); | |||||
} | } | ||||
/** | /** | ||||
* TrueType fonts) | * TrueType fonts) | ||||
* @param embedded indicates whether the font is embedded or referenced | * @param embedded indicates whether the font is embedded or referenced | ||||
* @param encodingMode the requested encoding mode | * @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 | * @param resolver the FontResolver for font URI resolution | ||||
*/ | */ | ||||
public TTFFontLoader(String fontFileURI, String subFontName, | 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.subFontName = subFontName; | ||||
this.encodingMode = encodingMode; | this.encodingMode = encodingMode; | ||||
if (this.encodingMode == EncodingMode.AUTO) { | if (this.encodingMode == EncodingMode.AUTO) { | ||||
copyWidthsSingleByte(ttf); | copyWidthsSingleByte(ttf); | ||||
} | } | ||||
copyKerning(ttf, isCid); | |||||
if (useKerning) { | |||||
copyKerning(ttf, isCid); | |||||
} | |||||
if (this.embedded && ttf.isEmbeddable()) { | if (this.embedded && ttf.isEmbeddable()) { | ||||
returnFont.setEmbedFileName(this.fontFileURI); | returnFont.setEmbedFileName(this.fontFileURI); | ||||
} | } |
* Constructs a new Type 1 font loader. | * Constructs a new Type 1 font loader. | ||||
* @param fontFileURI the URI to the PFB file of a Type 1 font | * @param fontFileURI the URI to the PFB file of a Type 1 font | ||||
* @param embedded indicates whether the font is embedded or referenced | * @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 | * @param resolver the font resolver used to resolve URIs | ||||
* @throws IOException In case of an I/O error | * @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) { | private String getPFMURI(String pfbURI) { | ||||
singleFont.setWidth(chm.getCharCode(), (int)Math.round(chm.getWidthX())); | singleFont.setWidth(chm.getCharCode(), (int)Math.round(chm.getWidthX())); | ||||
} | } | ||||
} | } | ||||
returnFont.replaceKerningMap(afm.createXKerningMapEncoded()); | |||||
if (useKerning) { | |||||
returnFont.replaceKerningMap(afm.createXKerningMapEncoded()); | |||||
} | |||||
} else { | } else { | ||||
returnFont.setFlags(pfm.getFlags()); | returnFont.setFlags(pfm.getFlags()); | ||||
returnFont.setFirstChar(pfm.getFirstChar()); | returnFont.setFirstChar(pfm.getFirstChar()); | ||||
for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) { | for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) { | ||||
singleFont.setWidth(i, pfm.getCharWidth(i)); | singleFont.setWidth(i, pfm.getCharWidth(i)); | ||||
} | } | ||||
returnFont.replaceKerningMap(pfm.getKerning()); | |||||
if (useKerning) { | |||||
returnFont.replaceKerningMap(pfm.getKerning()); | |||||
} | |||||
} | } | ||||
} | } | ||||
/* | |||||
* 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); | |||||
} |
/* | |||||
* 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; | |||||
} | |||||
} |
import org.apache.batik.bridge.UnitProcessor; | import org.apache.batik.bridge.UnitProcessor; | ||||
import org.apache.batik.bridge.UserAgent; | import org.apache.batik.bridge.UserAgent; | ||||
import org.apache.batik.dom.svg.SAXSVGDocumentFactory; | import org.apache.batik.dom.svg.SAXSVGDocumentFactory; | ||||
import org.apache.batik.dom.svg.SVGDOMImplementation; | |||||
import org.apache.batik.dom.svg.SVGOMDocument; | import org.apache.batik.dom.svg.SVGOMDocument; | ||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
//The whole image had to be loaded for this, so keep it | //The whole image had to be loaded for this, so keep it | ||||
ImageXMLDOM xmlImage = new ImageXMLDOM(info, | ImageXMLDOM xmlImage = new ImageXMLDOM(info, | ||||
doc, SVGDOMImplementation.SVG_NAMESPACE_URI); | |||||
doc, BatikImageFlavors.SVG_DOM); | |||||
info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, xmlImage); | info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, xmlImage); | ||||
return info; | return info; | ||||
} | } |
package org.apache.fop.pdf; | 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 | * 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 { | public class PDFNumber extends PDFObject { | ||||
return doubleOut(doubleDown, 6); | 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. | * Output a double value to a string suitable for PDF. | ||||
* In this method it is possible to set the maximum | * In this method it is possible to set the maximum | ||||
* @return the value as a string | * @return the value as a string | ||||
*/ | */ | ||||
public static String doubleOut(double doubleDown, int dec) { | 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} */ | /** {@inheritDoc} */ |
* @return true if the new paint changes the current paint | * @return true if the new paint changes the current paint | ||||
*/ | */ | ||||
public boolean setPaint(Paint p) { | public boolean setPaint(Paint p) { | ||||
Paint paint = ((PDFData)getData()).paint; | |||||
PDFData data = getPDFData(); | |||||
Paint paint = data.paint; | |||||
if (paint == null) { | if (paint == null) { | ||||
if (p != null) { | if (p != null) { | ||||
((PDFData)getData()).paint = p; | |||||
data.paint = p; | |||||
return true; | return true; | ||||
} | } | ||||
} else if (!paint.equals(p)) { | } else if (!paint.equals(p)) { | ||||
((PDFData)getData()).paint = p; | |||||
data.paint = p; | |||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
* @return true if the clip will change the current clip. | * @return true if the clip will change the current clip. | ||||
*/ | */ | ||||
public boolean checkClip(Shape cl) { | public boolean checkClip(Shape cl) { | ||||
Shape clip = ((PDFData)getData()).clip; | |||||
Shape clip = getPDFData().clip; | |||||
if (clip == null) { | if (clip == null) { | ||||
if (cl != null) { | if (cl != null) { | ||||
return true; | return true; | ||||
* @param cl the new clip in the current state | * @param cl the new clip in the current state | ||||
*/ | */ | ||||
public void setClip(Shape cl) { | public void setClip(Shape cl) { | ||||
Shape clip = ((PDFData)getData()).clip; | |||||
PDFData data = getPDFData(); | |||||
Shape clip = data.clip; | |||||
if (clip != null) { | if (clip != null) { | ||||
Area newClip = new Area(clip); | Area newClip = new Area(clip); | ||||
newClip.intersect(new Area(cl)); | newClip.intersect(new Area(cl)); | ||||
((PDFData)getData()).clip = new GeneralPath(newClip); | |||||
data.clip = new GeneralPath(newClip); | |||||
} else { | } 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. | * Get the current stack level. | ||||
* | * | ||||
newState.addValues(state); | newState.addValues(state); | ||||
} | } | ||||
} | } | ||||
if (((PDFData)getData()).gstate != null) { | |||||
newState.addValues(((PDFData)getData()).gstate); | |||||
if (getPDFData().gstate != null) { | |||||
newState.addValues(getPDFData().gstate); | |||||
} | } | ||||
return newState; | return newState; | ||||
} | } | ||||
getStateStack().add(copy); | getStateStack().add(copy); | ||||
} | } | ||||
private PDFData getPDFData() { | |||||
return (PDFData)getData(); | |||||
} | |||||
private class PDFData extends org.apache.fop.util.AbstractPaintingState.AbstractData { | private class PDFData extends org.apache.fop.util.AbstractPaintingState.AbstractData { | ||||
private static final long serialVersionUID = 3527950647293177764L; | private static final long serialVersionUID = 3527950647293177764L; | ||||
private Paint paint = null; | private Paint paint = null; | ||||
private Paint backPaint = 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 Shape clip = null; | ||||
private PDFGState gstate = null; | private PDFGState gstate = null; | ||||
//text state | |||||
private float characterSpacing = 0f; | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public Object clone() { | public Object clone() { | ||||
PDFData obj = (PDFData)super.clone(); | PDFData obj = (PDFData)super.clone(); | ||||
obj.paint = this.paint; | obj.paint = this.paint; | ||||
obj.backPaint = 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.clip = this.clip; | ||||
obj.gstate = this.gstate; | obj.gstate = this.gstate; | ||||
obj.characterSpacing = this.characterSpacing; | |||||
return obj; | return obj; | ||||
} | } | ||||
return super.toString() | return super.toString() | ||||
+ ", paint=" + paint | + ", paint=" + paint | ||||
+ ", backPaint=" + backPaint | + ", backPaint=" + backPaint | ||||
+ ", lineCap=" + lineCap | |||||
+ ", miterLimit=" + miterLimit | |||||
+ ", text=" + text | |||||
+ ", dashOffset=" + dashOffset | |||||
//+ ", lineCap=" + lineCap | |||||
//+ ", miterLimit=" + miterLimit | |||||
//+ ", dashOffset=" + dashOffset | |||||
+ ", clip=" + clip | + ", clip=" + clip | ||||
+ ", gstate=" + gstate; | + ", gstate=" + gstate; | ||||
} | } |
*/ | */ | ||||
public class PDFReference implements PDFWritable { | public class PDFReference implements PDFWritable { | ||||
private String indirectReference; | |||||
private int objectNumber; | |||||
private int generation; | |||||
private Reference objReference; | private Reference objReference; | ||||
* @param obj the object to be referenced | * @param obj the object to be referenced | ||||
*/ | */ | ||||
public PDFReference(PDFObject obj) { | public PDFReference(PDFObject obj) { | ||||
this.indirectReference = obj.referencePDF(); | |||||
this.objectNumber = obj.getObjectNumber(); | |||||
this.generation = obj.getGeneration(); | |||||
this.objReference = new SoftReference(obj); | this.objReference = new SoftReference(obj); | ||||
} | } | ||||
if (ref == null) { | if (ref == null) { | ||||
throw new NullPointerException("ref must not be 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]); | |||||
} | } | ||||
/** | /** | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 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} */ | /** {@inheritDoc} */ | ||||
public String toString() { | public String toString() { | ||||
return this.indirectReference; | |||||
return getObjectNumber() + " " + getGeneration() + " R"; | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ |
* @param adjust the glyph adjust value in thousands of text unit space. | * @param adjust the glyph adjust value in thousands of text unit space. | ||||
*/ | */ | ||||
public void adjustGlyphTJ(double adjust) { | 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(PDFNumber.doubleOut(adjust, DEC - 4)); | ||||
bufTJ.append(" "); | bufTJ.append(" "); | ||||
bufTJ.append(startText); | bufTJ.append(startText); |
* @return the action to place next to /A within a Link | * @return the action to place next to /A within a Link | ||||
*/ | */ | ||||
public String getAction() { | public String getAction() { | ||||
if (hasObjectNumber()) { | |||||
return referencePDF(); | |||||
} else { | |||||
return getDictString(); | |||||
} | |||||
} | |||||
private String getDictString() { | |||||
return "<< /URI (" + uri + ")\n/S /URI >>"; | return "<< /URI (" + uri + ")\n/S /URI >>"; | ||||
} | } | ||||
/** | |||||
* {@inheritDoc} | |||||
*/ | |||||
/** {@inheritDoc} */ | |||||
public String toPDFString() { | 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"); | |||||
} | } | ||||
} | } |
import org.apache.batik.gvt.GraphicsNode; | import org.apache.batik.gvt.GraphicsNode; | ||||
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | ||||
import org.apache.xmlgraphics.util.QName; | |||||
import org.apache.fop.apps.FOUserAgent; | import org.apache.fop.apps.FOUserAgent; | ||||
import org.apache.fop.events.EventBroadcaster; | 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.BatikUtil; | ||||
import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl; | import org.apache.fop.image.loader.batik.Graphics2DImagePainterImpl; | ||||
import org.apache.fop.render.RendererContext.RendererContextWrapper; | import org.apache.fop.render.RendererContext.RendererContextWrapper; | ||||
*/ | */ | ||||
public abstract class AbstractGenericSVGHandler implements XMLHandler, RendererContextConstants { | 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} */ | /** {@inheritDoc} */ | ||||
public void handleXML(RendererContext context, | public void handleXML(RendererContext context, | ||||
Document doc, String ns) throws Exception { | Document doc, String ns) throws Exception { | ||||
} | } | ||||
/** | /** | ||||
* 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 ctx the batik bridge context | ||||
* @param doc the document | * @param doc the document | ||||
* @return a built GVT root tree | * @return a built GVT root tree |
/* | |||||
* 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); | |||||
} | |||||
} |
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.xmlgraphics.image.loader.Image; | import org.apache.xmlgraphics.image.loader.Image; | ||||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | import org.apache.xmlgraphics.image.loader.ImageFlavor; | ||||
import org.apache.xmlgraphics.util.Service; | import org.apache.xmlgraphics.util.Service; | ||||
private static final Comparator HANDLER_COMPARATOR = new Comparator() { | private static final Comparator HANDLER_COMPARATOR = new Comparator() { | ||||
public int compare(Object o1, Object o2) { | 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(); | return h1.getPriority() - h2.getPriority(); | ||||
} | } | ||||
}; | }; | ||||
*/ | */ | ||||
public void addHandler(String classname) { | public void addHandler(String classname) { | ||||
try { | try { | ||||
ImageHandler handlerInstance | |||||
= (ImageHandler)Class.forName(classname).newInstance(); | |||||
ImageHandlerBase handlerInstance | |||||
= (ImageHandlerBase)Class.forName(classname).newInstance(); | |||||
addHandler(handlerInstance); | addHandler(handlerInstance); | ||||
} catch (ClassNotFoundException e) { | } catch (ClassNotFoundException e) { | ||||
throw new IllegalArgumentException("Could not find " | throw new IllegalArgumentException("Could not find " | ||||
* Add an image handler. The handler itself is inspected to find out what it supports. | * Add an image handler. The handler itself is inspected to find out what it supports. | ||||
* @param handler the ImageHandler instance | * @param handler the ImageHandler instance | ||||
*/ | */ | ||||
public synchronized void addHandler(ImageHandler handler) { | |||||
public synchronized void addHandler(ImageHandlerBase handler) { | |||||
this.handlers.put(handler.getSupportedImageClass(), handler); | this.handlers.put(handler.getSupportedImageClass(), handler); | ||||
//Sorted insert | //Sorted insert | ||||
ListIterator iter = this.handlerList.listIterator(); | ListIterator iter = this.handlerList.listIterator(); | ||||
while (iter.hasNext()) { | while (iter.hasNext()) { | ||||
ImageHandler h = (ImageHandler)iter.next(); | |||||
ImageHandlerBase h = (ImageHandlerBase)iter.next(); | |||||
if (getHandlerComparator().compare(handler, h) < 0) { | if (getHandlerComparator().compare(handler, h) < 0) { | ||||
iter.previous(); | iter.previous(); | ||||
break; | break; | ||||
* @param img the Image to be handled | * @param img the Image to be handled | ||||
* @return the ImageHandler responsible for handling the image or null if none is available | * @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()); | return getHandler(img.getClass()); | ||||
} | } | ||||
* @param imageClass the Image subclass for which to get a handler | * @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 | * @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; | Class cl = imageClass; | ||||
while (cl != null) { | while (cl != null) { | ||||
handler = (ImageHandler)handlers.get(cl); | |||||
handler = (ImageHandlerBase)handlers.get(cl); | |||||
if (handler != null) { | if (handler != null) { | ||||
break; | break; | ||||
} | } | ||||
List flavors = new java.util.ArrayList(); | List flavors = new java.util.ArrayList(); | ||||
Iterator iter = this.handlerList.iterator(); | Iterator iter = this.handlerList.iterator(); | ||||
while (iter.hasNext()) { | while (iter.hasNext()) { | ||||
ImageFlavor[] f = ((ImageHandler)iter.next()).getSupportedImageFlavors(); | |||||
ImageFlavor[] f = ((ImageHandlerBase)iter.next()).getSupportedImageFlavors(); | |||||
for (int i = 0; i < f.length; i++) { | for (int i = 0; i < f.length; i++) { | ||||
flavors.add(f[i]); | flavors.add(f[i]); | ||||
} | } | ||||
Iterator providers = Service.providers(imageHandlerClass); | Iterator providers = Service.providers(imageHandlerClass); | ||||
if (providers != null) { | if (providers != null) { | ||||
while (providers.hasNext()) { | while (providers.hasNext()) { | ||||
ImageHandler handler = (ImageHandler)providers.next(); | |||||
ImageHandlerBase handler = (ImageHandlerBase)providers.next(); | |||||
try { | try { | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug("Dynamically adding ImageHandler: " | log.debug("Dynamically adding ImageHandler: " |
} | } | ||||
} | } | ||||
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"); | = new QName(ExtensionElementMapping.URI, "fox:transform"); | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ |
// Java | // Java | ||||
import java.awt.Rectangle; | import java.awt.Rectangle; | ||||
import java.awt.geom.AffineTransform; | |||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
private Set warnedXMLHandlers; | private Set warnedXMLHandlers; | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public abstract void setupFontInfo(FontInfo fontInfo); | |||||
public abstract void setupFontInfo(FontInfo fontInfo) throws FOPException; | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public void setUserAgent(FOUserAgent agent) { | public void setUserAgent(FOUserAgent agent) { | ||||
public String getMimeType() { | public String getMimeType() { | ||||
return null; | 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); | |||||
} | |||||
} | } |
import org.apache.avalon.framework.configuration.ConfigurationException; | import org.apache.avalon.framework.configuration.ConfigurationException; | ||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.apps.FOUserAgent; | import org.apache.fop.apps.FOUserAgent; | ||||
/** | /** | ||||
* @param mimeType the MIME type of the renderer | * @param mimeType the MIME type of the renderer | ||||
* @return the requested configuration subtree, null if there's no configuration | * @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(); | Configuration cfg = userAgent.getFactory().getUserConfig(); | ||||
if (cfg == null) { | if (cfg == null) { | ||||
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { |
/* | |||||
* 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); | |||||
} | |||||
} | |||||
} | |||||
public interface Graphics2DImagePainter | public interface Graphics2DImagePainter | ||||
extends org.apache.xmlgraphics.java2d.Graphics2DImagePainter { | extends org.apache.xmlgraphics.java2d.Graphics2DImagePainter { | ||||
} | |||||
} |
* Paints an image at the given position. | * Paints an image at the given position. | ||||
* @param image the image which will be painted | * @param image the image which will be painted | ||||
* @param context the renderer context for the current renderer | * @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 | * @throws IOException In case of an I/O error while writing the output format | ||||
*/ | */ | ||||
void paintImage(RenderedImage image, | void paintImage(RenderedImage image, |
package org.apache.fop.render; | 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; | |||||
} | } |
/* | |||||
* 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(); | |||||
} |
/* | |||||
* 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); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
/* | |||||
* 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); | |||||
} | |||||
} |
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | 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.Area; | ||||
import org.apache.fop.area.Trait; | import org.apache.fop.area.Trait; | ||||
import org.apache.fop.fonts.CustomFontCollection; | import org.apache.fop.fonts.CustomFontCollection; | ||||
import org.apache.fop.fonts.FontResolver; | import org.apache.fop.fonts.FontResolver; | ||||
import org.apache.fop.fonts.FontTriplet; | import org.apache.fop.fonts.FontTriplet; | ||||
import org.apache.fop.fonts.base14.Base14FontCollection; | import org.apache.fop.fonts.base14.Base14FontCollection; | ||||
import org.w3c.dom.Document; | |||||
/** Abstract base class of "Print" type renderers. */ | /** Abstract base class of "Print" type renderers. */ | ||||
public abstract class PrintRenderer extends AbstractRenderer { | public abstract class PrintRenderer extends AbstractRenderer { | ||||
return this.embedFontInfoList; | 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; | this.fontInfo = inFontInfo; | ||||
FontManager fontManager = userAgent.getFactory().getFontManager(); | FontManager fontManager = userAgent.getFactory().getFontManager(); | ||||
FontCollection[] fontCollections = new FontCollection[] { | FontCollection[] fontCollections = new FontCollection[] { | ||||
*/ | */ | ||||
protected String getInternalFontNameForArea(Area area) { | protected String getInternalFontNameForArea(Area area) { | ||||
FontTriplet triplet = (FontTriplet)area.getTrait(Trait.FONT); | 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; | |||||
} | } | ||||
/** | /** |
import org.apache.fop.apps.FOPException; | import org.apache.fop.apps.FOPException; | ||||
import org.apache.fop.apps.FOUserAgent; | import org.apache.fop.apps.FOUserAgent; | ||||
import org.apache.fop.apps.FopFactory; | import org.apache.fop.apps.FopFactory; | ||||
import org.apache.fop.fonts.CustomFontCollection; | |||||
import org.apache.fop.fonts.EmbedFontInfo; | import org.apache.fop.fonts.EmbedFontInfo; | ||||
import org.apache.fop.fonts.EncodingMode; | import org.apache.fop.fonts.EncodingMode; | ||||
import org.apache.fop.fonts.FontCache; | import org.apache.fop.fonts.FontCache; | ||||
import org.apache.fop.fonts.FontCollection; | |||||
import org.apache.fop.fonts.FontEventAdapter; | import org.apache.fop.fonts.FontEventAdapter; | ||||
import org.apache.fop.fonts.FontEventListener; | import org.apache.fop.fonts.FontEventListener; | ||||
import org.apache.fop.fonts.FontInfo; | import org.apache.fop.fonts.FontInfo; | ||||
import org.apache.fop.fonts.FontUtil; | import org.apache.fop.fonts.FontUtil; | ||||
import org.apache.fop.fonts.autodetect.FontFileFinder; | import org.apache.fop.fonts.autodetect.FontFileFinder; | ||||
import org.apache.fop.fonts.autodetect.FontInfoFinder; | 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; | import org.apache.fop.util.LogUtil; | ||||
/** | /** | ||||
* Base Print renderer configurator (mostly handles font configuration) | * Base Print renderer configurator (mostly handles font configuration) | ||||
*/ | */ | ||||
public class PrintRendererConfigurator extends AbstractRendererConfigurator | public class PrintRendererConfigurator extends AbstractRendererConfigurator | ||||
implements RendererConfigurator { | |||||
implements RendererConfigurator, IFDocumentHandlerConfigurator { | |||||
/** logger instance */ | /** logger instance */ | ||||
protected static Log log = LogFactory.getLog(PrintRendererConfigurator.class); | protected static Log log = LogFactory.getLog(PrintRendererConfigurator.class); | ||||
PrintRenderer printRenderer = (PrintRenderer)renderer; | PrintRenderer printRenderer = (PrintRenderer)renderer; | ||||
FontResolver fontResolver = printRenderer.getFontResolver(); | 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(); | FopFactory factory = userAgent.getFactory(); | ||||
FontManager fontManager = factory.getFontManager(); | FontManager fontManager = factory.getFontManager(); | ||||
if (fontResolver == null) { | if (fontResolver == null) { | ||||
boolean strict = factory.validateUserConfigStrictly(); | boolean strict = factory.validateUserConfigStrictly(); | ||||
FontCache fontCache = fontManager.getFontCache(); | FontCache fontCache = fontManager.getFontCache(); | ||||
FontEventListener listener = new FontEventAdapter( | |||||
renderer.getUserAgent().getEventBroadcaster()); | |||||
List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontListFromConfiguration(cfg, | List/*<EmbedFontInfo>*/ embedFontInfoList = buildFontListFromConfiguration(cfg, | ||||
fontResolver, strict, fontManager, listener); | fontResolver, strict, fontManager, listener); | ||||
if (fontCache != null && fontCache.hasChanged()) { | if (fontCache != null && fontCache.hasChanged()) { | ||||
fontCache.save(); | fontCache.save(); | ||||
} | } | ||||
printRenderer.addFontList(embedFontInfoList); | |||||
return embedFontInfoList; | |||||
} | } | ||||
/** | /** | ||||
return embedFontInfo; | 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); | |||||
} | |||||
} | } |
* Set up the given FontInfo. | * Set up the given FontInfo. | ||||
* | * | ||||
* @param fontInfo The font information | * @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> | * Reports if out of order rendering is supported. <p> |
import java.util.Map; | import java.util.Map; | ||||
import org.apache.fop.apps.FOUserAgent; | 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 | * The Render Context for external handlers. This provides a rendering context | ||||
* render target. | * render target. | ||||
*/ | */ | ||||
public class RendererContext { | 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 String mime; | ||||
private final AbstractRenderer renderer; | private final AbstractRenderer renderer; |
import org.apache.fop.apps.FOUserAgent; | import org.apache.fop.apps.FOUserAgent; | ||||
import org.apache.fop.area.AreaTreeHandler; | import org.apache.fop.area.AreaTreeHandler; | ||||
import org.apache.fop.fo.FOEventHandler; | 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. | * Factory for FOEventHandlers and Renderers. | ||||
private Map rendererMakerMapping = new java.util.HashMap(); | private Map rendererMakerMapping = new java.util.HashMap(); | ||||
private Map eventHandlerMakerMapping = new java.util.HashMap(); | private Map eventHandlerMakerMapping = new java.util.HashMap(); | ||||
private Map documentHandlerMakerMapping = new java.util.HashMap(); | |||||
/** | /** | ||||
* Main constructor. | * Main constructor. | ||||
public RendererFactory() { | public RendererFactory() { | ||||
discoverRenderers(); | discoverRenderers(); | ||||
discoverFOEventHandlers(); | discoverFOEventHandlers(); | ||||
discoverDocumentHandlers(); | |||||
} | } | ||||
/** | /** | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 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 | * Add a new RendererMaker. If another maker has already been registered for a | ||||
* particular MIME type, this call overwrites the existing one. | * particular MIME type, this call overwrites the existing one. | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 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. | * Returns a RendererMaker which handles the given MIME type. | ||||
* @param mime the requested output format | * @param mime the requested output format | ||||
return maker; | 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 | * Creates a Renderer object based on render-type desired | ||||
* @param userAgent the user agent for access to configuration | * @param userAgent the user agent for access to configuration | ||||
*/ | */ | ||||
public Renderer createRenderer(FOUserAgent userAgent, String outputFormat) | public Renderer createRenderer(FOUserAgent userAgent, String outputFormat) | ||||
throws FOPException { | throws FOPException { | ||||
if (userAgent.getRendererOverride() != null) { | |||||
if (userAgent.getDocumentHandlerOverride() != null) { | |||||
return createRendererForDocumentHandler(userAgent.getDocumentHandlerOverride()); | |||||
} else if (userAgent.getRendererOverride() != null) { | |||||
return userAgent.getRendererOverride(); | return userAgent.getRendererOverride(); | ||||
} else { | } else { | ||||
AbstractRendererMaker maker = getRendererMaker(outputFormat); | 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. | * Creates FOEventHandler instances based on the desired output. | ||||
return userAgent.getFOEventHandlerOverride(); | return userAgent.getFOEventHandlerOverride(); | ||||
} else { | } else { | ||||
AbstractFOEventHandlerMaker maker = getFOEventHandlerMaker(outputFormat); | AbstractFOEventHandlerMaker maker = getFOEventHandlerMaker(outputFormat); | ||||
if (maker == null) { | |||||
if (maker != null) { | |||||
return maker.makeFOEventHandler(userAgent, out); | |||||
} else { | |||||
AbstractRendererMaker rendMaker = getRendererMaker(outputFormat); | 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 { | } 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( | throw new FOPException( | ||||
"OutputStream has not been set"); | "OutputStream has not been set"); | ||||
} | } | ||||
//Found a Renderer so we need to construct an AreaTreeHandler. | //Found a Renderer so we need to construct an AreaTreeHandler. | ||||
return new AreaTreeHandler(userAgent, outputFormat, out); | 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 | * @return an array of all supported MIME types | ||||
*/ | */ | ||||
while (iter.hasNext()) { | while (iter.hasNext()) { | ||||
lst.add(((String)iter.next())); | lst.add(((String)iter.next())); | ||||
} | } | ||||
iter = this.documentHandlerMakerMapping.keySet().iterator(); | |||||
while (iter.hasNext()) { | |||||
lst.add(((String)iter.next())); | |||||
} | |||||
Collections.sort(lst); | Collections.sort(lst); | ||||
return (String[])lst.toArray(new String[lst.size()]); | return (String[])lst.toArray(new String[lst.size()]); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 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); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | } |
/* | |||||
* 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); | |||||
} |
/* | |||||
* 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); | |||||
} |
/* | |||||
* 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); | |||||
} | |||||
} |
/* | |||||
* 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; | |||||
} | |||||
} |
<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en"/> |
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.xmlgraphics.util.QName; | |||||
import org.apache.fop.afp.AFPResourceInfo; | import org.apache.fop.afp.AFPResourceInfo; | ||||
import org.apache.fop.afp.AFPResourceLevel; | import org.apache.fop.afp.AFPResourceLevel; | ||||
import org.apache.fop.render.afp.extensions.AFPElementMapping; | import org.apache.fop.render.afp.extensions.AFPElementMapping; | ||||
import org.apache.xmlgraphics.util.QName; | |||||
/** | /** | ||||
* Parses any AFP foreign attributes | * Parses any AFP foreign attributes | ||||
private static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); | private static final Log log = LogFactory.getLog("org.apache.xmlgraphics.afp"); | ||||
/** the resource-name attribute */ | /** 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 */ | /** 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 */ | /** 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 | * Main constructor | ||||
public AFPResourceInfo getResourceInfo(Map/*<QName, String>*/ foreignAttributes) { | public AFPResourceInfo getResourceInfo(Map/*<QName, String>*/ foreignAttributes) { | ||||
AFPResourceInfo resourceInfo = new AFPResourceInfo(); | AFPResourceInfo resourceInfo = new AFPResourceInfo(); | ||||
if (foreignAttributes != null && !foreignAttributes.isEmpty()) { | 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) { | if (resourceName != null) { | ||||
resourceInfo.setName(resourceName); | resourceInfo.setName(resourceName); | ||||
} | } | ||||
public AFPResourceLevel getResourceLevel(Map/*<QName, String>*/ foreignAttributes) { | public AFPResourceLevel getResourceLevel(Map/*<QName, String>*/ foreignAttributes) { | ||||
AFPResourceLevel resourceLevel = null; | AFPResourceLevel resourceLevel = null; | ||||
if (foreignAttributes != null && !foreignAttributes.isEmpty()) { | 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); | resourceLevel = AFPResourceLevel.valueOf(levelString); | ||||
// if external get resource group file attributes | // if external get resource group file attributes | ||||
if (resourceLevel != null && resourceLevel.isExternal()) { | if (resourceLevel != null && resourceLevel.isExternal()) { | ||||
QName resourceGroupFileKey = new QName(AFPElementMapping.NAMESPACE, | |||||
RESOURCE_GROUP_FILE); | |||||
String resourceGroupFile | String resourceGroupFile | ||||
= (String)foreignAttributes.get(resourceGroupFileKey); | |||||
= (String)foreignAttributes.get(RESOURCE_GROUP_FILE); | |||||
if (resourceGroupFile == null) { | if (resourceGroupFile == null) { | ||||
String msg = RESOURCE_GROUP_FILE + " not specified"; | String msg = RESOURCE_GROUP_FILE + " not specified"; | ||||
log.error(msg); | log.error(msg); |
package org.apache.fop.render.afp; | package org.apache.fop.render.afp; | ||||
import java.awt.Point; | import java.awt.Point; | ||||
import java.awt.Rectangle; | |||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.apache.fop.afp.AFPPaintingState; | import org.apache.fop.afp.AFPPaintingState; | ||||
import org.apache.fop.afp.AFPResourceInfo; | import org.apache.fop.afp.AFPResourceInfo; | ||||
import org.apache.fop.afp.AFPUnitConverter; | import org.apache.fop.afp.AFPUnitConverter; | ||||
import org.apache.fop.render.ImageHandler; | |||||
import org.apache.fop.render.ImageHandlerBase; | |||||
/** | /** | ||||
* A base abstract AFP image handler | * 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 X = 0; | ||||
private static final int Y = 1; | private static final int Y = 1; | ||||
AFPDataObjectInfo dataObjectInfo = createDataObjectInfo(); | AFPDataObjectInfo dataObjectInfo = createDataObjectInfo(); | ||||
// set resource information | // 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(); | Point origin = rendererImageInfo.getOrigin(); | ||||
Rectangle2D position = rendererImageInfo.getPosition(); | 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 rendererContext | ||||
= (AFPRendererContext)rendererImageInfo.getRendererContext(); | = (AFPRendererContext)rendererImageInfo.getRendererContext(); | ||||
AFPInfo afpInfo = rendererContext.getInfo(); | AFPInfo afpInfo = rendererContext.getInfo(); | ||||
AFPPaintingState paintingState = afpInfo.getPaintingState(); | 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(); | 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.setX(coords[X]); | ||||
objectAreaInfo.setY(coords[Y]); | objectAreaInfo.setY(coords[Y]); | ||||
int width = Math.round(unitConv.mpt2units((float)position.getWidth())); | |||||
int width = Math.round(unitConv.mpt2units(targetRect.width)); | |||||
objectAreaInfo.setWidth(width); | objectAreaInfo.setWidth(width); | ||||
int height = Math.round(unitConv.mpt2units((float)position.getHeight())); | |||||
int height = Math.round(unitConv.mpt2units(targetRect.height)); | |||||
objectAreaInfo.setHeight(height); | objectAreaInfo.setHeight(height); | ||||
int resolution = paintingState.getResolution(); | int resolution = paintingState.getResolution(); | ||||
objectAreaInfo.setWidthRes(resolution); | objectAreaInfo.setWidthRes(resolution); | ||||
objectAreaInfo.setRotation(paintingState.getRotation()); | objectAreaInfo.setRotation(paintingState.getRotation()); | ||||
dataObjectInfo.setObjectAreaInfo(objectAreaInfo); | |||||
return dataObjectInfo; | |||||
return objectAreaInfo; | |||||
} | } | ||||
/** | /** |
package org.apache.fop.render.afp; | package org.apache.fop.render.afp; | ||||
import java.awt.Rectangle; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import org.apache.xmlgraphics.image.loader.Image; | |||||
import org.apache.xmlgraphics.image.loader.ImageFlavor; | import org.apache.xmlgraphics.image.loader.ImageFlavor; | ||||
import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; | import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; | ||||
import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; | ||||
import org.apache.fop.afp.AFPGraphicsObjectInfo; | import org.apache.fop.afp.AFPGraphicsObjectInfo; | ||||
import org.apache.fop.afp.AFPPaintingState; | import org.apache.fop.afp.AFPPaintingState; | ||||
import org.apache.fop.afp.AFPResourceInfo; | import org.apache.fop.afp.AFPResourceInfo; | ||||
import org.apache.fop.afp.AFPResourceManager; | |||||
import org.apache.fop.afp.modca.ResourceObject; | 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. | * 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[] { | private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { | ||||
ImageFlavor.GRAPHICS2D | ImageFlavor.GRAPHICS2D | ||||
AFPGraphicsObjectInfo graphicsObjectInfo | AFPGraphicsObjectInfo graphicsObjectInfo | ||||
= (AFPGraphicsObjectInfo)super.generateDataObjectInfo(rendererImageInfo); | = (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) | // set mime type (unsupported by MOD:CA registry) | ||||
graphicsObjectInfo.setMimeType(MimeConstants.MIME_AFP_GOCA); | graphicsObjectInfo.setMimeType(MimeConstants.MIME_AFP_GOCA); | ||||
// set g2d | // set g2d | ||||
boolean textAsShapes = false; | boolean textAsShapes = false; | ||||
AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes); | AFPGraphics2D g2d = afpInfo.createGraphics2D(textAsShapes); | ||||
graphicsObjectInfo.setGraphics2D(g2d); | graphicsObjectInfo.setGraphics2D(g2d); | ||||
} | } | ||||
} | } | ||||
private void setDefaultResourceLevel(AFPGraphicsObjectInfo graphicsObjectInfo, | |||||
AFPResourceManager resourceManager) { | |||||
AFPResourceInfo resourceInfo = graphicsObjectInfo.getResourceInfo(); | |||||
if (!resourceInfo.levelChanged()) { | |||||
resourceInfo.setLevel(resourceManager.getResourceLevelDefaults() | |||||
.getDefaultResourceLevel(ResourceObject.TYPE_GRAPHIC)); | |||||
} | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public int getPriority() { | public int getPriority() { | ||||
return 200; | return 200; | ||||
protected AFPDataObjectInfo createDataObjectInfo() { | protected AFPDataObjectInfo createDataObjectInfo() { | ||||
return new AFPGraphicsObjectInfo(); | 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; | |||||
} | |||||
} | } |
package org.apache.fop.render.afp; | 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.AFPDataObjectInfo; | ||||
import org.apache.fop.afp.AFPImageObjectInfo; | 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). | * AFPImageHandler implementation which handles CCITT encoded images (CCITT fax group 3/4). | ||||
}; | }; | ||||
/** {@inheritDoc} */ | /** {@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(); | int compression = ccitt.getCompression(); | ||||
imageObjectInfo.setCompression(compression); | imageObjectInfo.setCompression(compression); | ||||
imageObjectInfo.setBitsPerPixel(1); | 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} */ | /** {@inheritDoc} */ | ||||
return FLAVORS; | 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; | |||||
} | |||||
} | } |
package org.apache.fop.render.afp; | 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.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.xmlgraphics.image.loader.impl.ImageRawStream; | ||||
import org.apache.fop.afp.AFPDataObjectInfo; | |||||
import org.apache.fop.render.RenderingContext; | |||||
/** | /** | ||||
* AFPImageHandler implementation which handles raw stream images. | * AFPImageHandler implementation which handles raw stream images. | ||||
*/ | */ | ||||
protected AFPDataObjectInfo createDataObjectInfo() { | protected AFPDataObjectInfo createDataObjectInfo() { | ||||
return new AFPDataObjectInfo(); | 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; | |||||
} | |||||
} | } |
package org.apache.fop.render.afp; | package org.apache.fop.render.afp; | ||||
import java.awt.Dimension; | import java.awt.Dimension; | ||||
import java.awt.Rectangle; | |||||
import java.awt.image.ColorModel; | import java.awt.image.ColorModel; | ||||
import java.awt.image.RenderedImage; | import java.awt.image.RenderedImage; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | 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.ImageFlavor; | ||||
import org.apache.xmlgraphics.image.loader.ImageInfo; | import org.apache.xmlgraphics.image.loader.ImageInfo; | ||||
import org.apache.xmlgraphics.image.loader.ImageSize; | import org.apache.xmlgraphics.image.loader.ImageSize; | ||||
import org.apache.fop.afp.AFPObjectAreaInfo; | import org.apache.fop.afp.AFPObjectAreaInfo; | ||||
import org.apache.fop.afp.AFPPaintingState; | import org.apache.fop.afp.AFPPaintingState; | ||||
import org.apache.fop.afp.AFPResourceInfo; | import org.apache.fop.afp.AFPResourceInfo; | ||||
import org.apache.fop.afp.AFPResourceManager; | |||||
import org.apache.fop.afp.modca.ResourceObject; | 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; | import org.apache.fop.util.bitmap.BitmapImageUtil; | ||||
/** | /** | ||||
* PDFImageHandler implementation which handles RenderedImage instances. | * PDFImageHandler implementation which handles RenderedImage instances. | ||||
*/ | */ | ||||
public class AFPImageHandlerRenderedImage extends AFPImageHandler { | |||||
public class AFPImageHandlerRenderedImage extends AFPImageHandler implements ImageHandler { | |||||
/** logging instance */ | /** logging instance */ | ||||
private static Log log = LogFactory.getLog(AFPImageHandlerRenderedImage.class); | private static Log log = LogFactory.getLog(AFPImageHandlerRenderedImage.class); | ||||
= (AFPRendererContext)rendererImageInfo.getRendererContext(); | = (AFPRendererContext)rendererImageInfo.getRendererContext(); | ||||
AFPInfo afpInfo = rendererContext.getInfo(); | 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(); | 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 resolution = paintingState.getResolution(); | ||||
int maxPixelSize = paintingState.getBitsPerPixel(); | int maxPixelSize = paintingState.getBitsPerPixel(); | ||||
if (paintingState.isColorImages()) { | if (paintingState.isColorImages()) { | ||||
maxPixelSize *= 3; //RGB only at the moment | maxPixelSize *= 3; //RGB only at the moment | ||||
} | } | ||||
ImageRendered imageRendered = (ImageRendered) rendererImageInfo.img; | |||||
RenderedImage renderedImage = imageRendered.getRenderedImage(); | RenderedImage renderedImage = imageRendered.getRenderedImage(); | ||||
ImageInfo imageInfo = rendererImageInfo.getImageInfo(); | |||||
ImageInfo imageInfo = imageRendered.getInfo(); | |||||
ImageSize intrinsicSize = imageInfo.getSize(); | ImageSize intrinsicSize = imageInfo.getSize(); | ||||
boolean useFS10 = (maxPixelSize == 1) || BitmapImageUtil.isMonochromeImage(renderedImage); | boolean useFS10 = (maxPixelSize == 1) || BitmapImageUtil.isMonochromeImage(renderedImage); | ||||
boolean usePageSegments = useFS10 | boolean usePageSegments = useFS10 | ||||
&& !resourceInfo.getLevel().isInline(); | |||||
&& !imageObjectInfo.getResourceInfo().getLevel().isInline(); | |||||
ImageSize effIntrinsicSize = intrinsicSize; | ImageSize effIntrinsicSize = intrinsicSize; | ||||
if (usePageSegments) { | if (usePageSegments) { | ||||
//Resize, optionally resample and convert image | //Resize, optionally resample and convert image | ||||
Dimension resampledDim = new Dimension( | 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.setCreatePageSegment(true); | ||||
imageObjectInfo.getResourceInfo().setImageDimension(resampledDim); | imageObjectInfo.getResourceInfo().setImageDimension(resampledDim); | ||||
int dataWidth = renderedImage.getWidth(); | int dataWidth = renderedImage.getWidth(); | ||||
imageObjectInfo.setDataWidth(dataWidth); | imageObjectInfo.setDataWidth(dataWidth); | ||||
//TODO To reduce AFP file size, investigate using a compression scheme. | |||||
//Currently, all image data is uncompressed. | |||||
ColorModel cm = renderedImage.getColorModel(); | ColorModel cm = renderedImage.getColorModel(); | ||||
if (log.isTraceEnabled()) { | if (log.isTraceEnabled()) { | ||||
log.trace("ColorModel: " + cm); | log.trace("ColorModel: " + cm); | ||||
return imageObjectInfo; | 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} */ | /** {@inheritDoc} */ | ||||
protected AFPDataObjectInfo createDataObjectInfo() { | protected AFPDataObjectInfo createDataObjectInfo() { | ||||
return new AFPImageObjectInfo(); | return new AFPImageObjectInfo(); | ||||
return FLAVORS; | 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; | |||||
} | |||||
} | } |