https://svn.eu.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r687576 | maxberger | 2008-08-21 07:25:40 +0100 (Thu, 21 Aug 2008) | 1 line Included patched retroweaver which does not modify Boolean.valueOf ........ r687657 | jeremias | 2008-08-21 09:51:50 +0100 (Thu, 21 Aug 2008) | 1 line Added an FAQ entry about the element mismatch error message. ........ r687786 | jeremias | 2008-08-21 16:49:13 +0100 (Thu, 21 Aug 2008) | 1 line Added some performance statistics to MemoryEater. ........ r688078 | jeremias | 2008-08-22 14:02:37 +0100 (Fri, 22 Aug 2008) | 1 line Final statistics output after the test with average speed indication. ........ r688087 | jeremias | 2008-08-22 15:16:58 +0100 (Fri, 22 Aug 2008) | 2 lines Merge from branch https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-0_95: Fixed text stroking in SVG when the stroke-width is zero. ........ r688139 | maxberger | 2008-08-22 19:08:36 +0100 (Fri, 22 Aug 2008) | 1 line minor spelling mistakes ........ r688508 | maxberger | 2008-08-24 14:12:02 +0100 (Sun, 24 Aug 2008) | 2 lines Moved DataURIResolver from FOP to commons; use new URIResolver registry ........ r688633 | jeremias | 2008-08-25 07:42:44 +0100 (Mon, 25 Aug 2008) | 2 lines Fixed memory leak in property cache (not cleaning stale PropertyCache$CacheEntry instances). Special thanks to Andreas Delmelle for his help! ........ r688652 | maxberger | 2008-08-25 09:19:13 +0100 (Mon, 25 Aug 2008) | 1 line Re-added moved class as deprecated ........ r688653 | jeremias | 2008-08-25 09:23:31 +0100 (Mon, 25 Aug 2008) | 1 line Added a page on metadata (partly ported from the FOP Wiki). ........ r688660 | jeremias | 2008-08-25 09:41:29 +0100 (Mon, 25 Aug 2008) | 2 lines Fixed example. Thanks for noticing, Pascal Sancho! ........ r688664 | jeremias | 2008-08-25 09:59:27 +0100 (Mon, 25 Aug 2008) | 1 line Minor documentation improvements, most notably a comment about keep-together="always". ........ r688666 | maxberger | 2008-08-25 10:00:27 +0100 (Mon, 25 Aug 2008) | 1 line CommonURIResolver is no longer a singleton ........ r688674 | jeremias | 2008-08-25 10:15:22 +0100 (Mon, 25 Aug 2008) | 1 line Hmm, I missed the redirects for the 0.95 release. ........ r688698 | jeremias | 2008-08-25 12:24:15 +0100 (Mon, 25 Aug 2008) | 2 lines Merge from 0.95 branch: Fixed jar-sources target. ........ r688994 | acumiskey | 2008-08-26 09:34:45 +0100 (Tue, 26 Aug 2008) | 1 line Deprecate UnitConv now that it resides only in xmlgraphics commons. ........ r689000 | acumiskey | 2008-08-26 09:59:31 +0100 (Tue, 26 Aug 2008) | 1 line Forgot to add deprecated public statics. ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AFPGOCAResources@689005 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_0
@@ -474,7 +474,6 @@ list of possible build targets. | |||
<pathelement location="${java14.jce.lib}"/> | |||
<pathelement location="${ant.home}/lib/ant.jar"/> | |||
<path refid="libs-build-classpath"/> | |||
<path refid="libs-build-tools-classpath"/> | |||
</path> | |||
<!-- If we decide to use retroweaver for the actual weaving, the mkdir and | |||
destdir= will have to be removed. Also, the weaving task would additionally | |||
@@ -555,9 +554,6 @@ list of possible build targets. | |||
<fileset dir="${src.java.dir}"> | |||
<patternset refid="java-only"/> | |||
</fileset> | |||
<fileset dir="${src.java.version.dir}"> | |||
<patternset refid="java-only"/> | |||
</fileset> | |||
<fileset dir="${basedir}"> | |||
<include name="LICENSE"/> | |||
<include name="NOTICE"/> |
@@ -1,28 +1,38 @@ | |||
# redirect moved files | |||
RedirectMatch Permanent ^/fop/anttask(.*) http://xmlgraphics.apache.org/fop/0.94/anttask$1 | |||
RedirectMatch Permanent ^/fop/compiling(.*) http://xmlgraphics.apache.org/fop/0.94/compiling$1 | |||
RedirectMatch Permanent ^/fop/configuration(.*) http://xmlgraphics.apache.org/fop/0.94/configuration$1 | |||
RedirectMatch Permanent ^/fop/embedding(.*) http://xmlgraphics.apache.org/fop/0.94/embedding$1 | |||
RedirectMatch Permanent ^/fop/extensions(.*) http://xmlgraphics.apache.org/fop/0.94/extensions$1 | |||
RedirectMatch Permanent ^/fop/fonts(.*) http://xmlgraphics.apache.org/fop/0.94/fonts$1 | |||
RedirectMatch Permanent ^/fop/graphics(.*) http://xmlgraphics.apache.org/fop/0.94/graphics$1 | |||
RedirectMatch Permanent ^/fop/hyphenation(.*) http://xmlgraphics.apache.org/fop/0.94/hyphenation$1 | |||
RedirectMatch Permanent ^/fop/intermediate(.*) http://xmlgraphics.apache.org/fop/0.94/intermediate$1 | |||
RedirectMatch Permanent ^/fop/output(.*) http://xmlgraphics.apache.org/fop/0.94/output$1 | |||
RedirectMatch Permanent ^/fop/pdfa(.*) http://xmlgraphics.apache.org/fop/0.94/pdfa$1 | |||
RedirectMatch Permanent ^/fop/pdfencryption(.*) http://xmlgraphics.apache.org/fop/0.94/pdfencryption$1 | |||
RedirectMatch Permanent ^/fop/pdfx(.*) http://xmlgraphics.apache.org/fop/0.94/pdfx$1 | |||
RedirectMatch Permanent ^/fop/running(.*) http://xmlgraphics.apache.org/fop/0.94/running$1 | |||
RedirectMatch Permanent ^/fop/servlets(.*) http://xmlgraphics.apache.org/fop/0.94/servlets$1 | |||
RedirectMatch Permanent ^/fop/upgrading(.*) http://xmlgraphics.apache.org/fop/0.94/upgrading$1 | |||
RedirectMatch Permanent ^/fop/anttask(.*) http://xmlgraphics.apache.org/fop/0.95/anttask$1 | |||
RedirectMatch Permanent ^/fop/compiling(.*) http://xmlgraphics.apache.org/fop/0.95/compiling$1 | |||
RedirectMatch Permanent ^/fop/configuration(.*) http://xmlgraphics.apache.org/fop/0.95/configuration$1 | |||
RedirectMatch Permanent ^/fop/embedding(.*) http://xmlgraphics.apache.org/fop/0.95/embedding$1 | |||
RedirectMatch Permanent ^/fop/extensions(.*) http://xmlgraphics.apache.org/fop/0.95/extensions$1 | |||
RedirectMatch Permanent ^/fop/fonts(.*) http://xmlgraphics.apache.org/fop/0.95/fonts$1 | |||
RedirectMatch Permanent ^/fop/graphics(.*) http://xmlgraphics.apache.org/fop/0.95/graphics$1 | |||
RedirectMatch Permanent ^/fop/hyphenation(.*) http://xmlgraphics.apache.org/fop/0.95/hyphenation$1 | |||
RedirectMatch Permanent ^/fop/intermediate(.*) http://xmlgraphics.apache.org/fop/0.95/intermediate$1 | |||
RedirectMatch Permanent ^/fop/output(.*) http://xmlgraphics.apache.org/fop/0.95/output$1 | |||
RedirectMatch Permanent ^/fop/pdfa(.*) http://xmlgraphics.apache.org/fop/0.95/pdfa$1 | |||
RedirectMatch Permanent ^/fop/pdfencryption(.*) http://xmlgraphics.apache.org/fop/0.95/pdfencryption$1 | |||
RedirectMatch Permanent ^/fop/pdfx(.*) http://xmlgraphics.apache.org/fop/0.95/pdfx$1 | |||
RedirectMatch Permanent ^/fop/running(.*) http://xmlgraphics.apache.org/fop/0.95/running$1 | |||
RedirectMatch Permanent ^/fop/servlets(.*) http://xmlgraphics.apache.org/fop/0.95/servlets$1 | |||
RedirectMatch Permanent ^/fop/upgrading(.*) http://xmlgraphics.apache.org/fop/0.95/upgrading$1 | |||
# redirect to versioned documentation | |||
Redirect Temp /fop/stable http://xmlgraphics.apache.org/fop/0.94 | |||
# Current stable release | |||
Redirect Temp /fop/stable http://xmlgraphics.apache.org/fop/0.95 | |||
# Current unstable release (or trunk if no beta is the latest release) | |||
Redirect Temp /fop/unstable http://xmlgraphics.apache.org/fop/trunk | |||
# Latest release | |||
Redirect Temp /fop/current http://xmlgraphics.apache.org/fop/0.95 | |||
Redirect Temp /fop/unstable http://xmlgraphics.apache.org/fop/0.95 | |||
Redirect Temp /fop/latest http://xmlgraphics.apache.org/fop/trunk | |||
Redirect Temp /fop/maintenance http://xmlgraphics.apache.org/fop/0.93 | |||
Redirect Temp /fop/previous http://xmlgraphics.apache.org/fop/0.93 | |||
Redirect Temp /fop/0.90alpha1 http://xmlgraphics.apache.org/fop/0.93 | |||
Redirect Temp /fop/0.91beta http://xmlgraphics.apache.org/fop/0.93 | |||
Redirect Temp /fop/0.92beta http://xmlgraphics.apache.org/fop/0.93 | |||
Redirect Temp /fop/latest http://xmlgraphics.apache.org/fop/0.95 | |||
# Previous stable release | |||
Redirect Temp /fop/previous http://xmlgraphics.apache.org/fop/0.94 | |||
# Old releases | |||
Redirect Temp /fop/maintenance http://xmlgraphics.apache.org/fop/0.94 | |||
Redirect Temp /fop/0.90alpha1 http://xmlgraphics.apache.org/fop/0.94 | |||
Redirect Temp /fop/0.91beta http://xmlgraphics.apache.org/fop/0.94 | |||
Redirect Temp /fop/0.92beta http://xmlgraphics.apache.org/fop/0.94 | |||
Redirect Temp /fop/0.93 http://xmlgraphics.apache.org/fop/0.94 |
@@ -0,0 +1,243 @@ | |||
<?xml version="1.0" 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$ --> | |||
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V2.0//EN" "document-v20.dtd"> | |||
<document> | |||
<header> | |||
<title>Metadata</title> | |||
</header> | |||
<body> | |||
<section id="overview"> | |||
<title>Overview</title> | |||
<p> | |||
Document metadata is an important tool for categorizing and finding documents. | |||
Various formats support different kinds of metadata representation and to | |||
different levels. One of the more popular and flexible means of representing | |||
document or object metadata is | |||
<a href="http://www.adobe.com/products/xmp/">XMP (eXtensible Metadata Platform, specified by Adobe)</a>. | |||
PDF 1.4 introduced the use of XMP. The XMP specification lists recommendation for | |||
embedding XMP metdata in other document and image formats. Given its flexibility it makes | |||
sense to make use this approach in the XSL-FO context. Unfortunately, unlike SVG which | |||
also refers to XMP, XSL-FO doesn't recommend a preferred way of specifying document and | |||
object metadata. Therefore, there's no portable way to represent metadata in XSL-FO | |||
documents. Each implementation does it differently. | |||
</p> | |||
</section> | |||
<section id="xmp-in-fo"> | |||
<title>Embedding XMP in an XSL-FO document</title> | |||
<p> | |||
As noted above, there's no officially recommended way to embed metadata in XSL-FO. | |||
Apache FOP supports embedding XMP in XSL-FO. Currently, only support for document-level | |||
metadata is implemented. Object-level metadata will be implemented when there's | |||
interest. | |||
</p> | |||
<p> | |||
Document-level metadata can be specified in the <code>fo:declarations</code> element. | |||
XMP specification recommends to use <code>x:xmpmeta</code>, <code>rdf:RDF</code>, and | |||
<code>rdf:Description</code> elements as shown in example below. Both | |||
<code>x:xmpmeta</code> and <code>rdf:RDF</code> elements are recognized as the top-level | |||
element introducing an XMP fragment (as per the XMP specification). | |||
</p> | |||
<section id="xmp-example"> | |||
<title>Example</title> | |||
<source><![CDATA[[..] | |||
</fo:layout-master-set> | |||
<fo:declarations> | |||
<x:xmpmeta xmlns:x="adobe:ns:meta/"> | |||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> | |||
<rdf:Description rdf:about="" | |||
xmlns:dc="http://purl.org/dc/elements/1.1/"> | |||
<!-- Dublin Core properties go here --> | |||
<dc:title>Document title</dc:title> | |||
<dc:creator>Document author</dc:creator> | |||
<dc:description>Document subject</dc:description> | |||
</rdf:Description> | |||
<rdf:Description rdf:about="" | |||
xmlns:xmp="http://ns.adobe.com/xap/1.0/"> | |||
<!-- XMP properties go here --> | |||
<xmp:CreatorTool>Tool used to make the PDF</xmp:CreatorTool> | |||
</rdf:Description> | |||
</rdf:RDF> | |||
</x:xmpmeta> | |||
</fo:declarations> | |||
<fo:page-sequence ... | |||
[..]]]></source> | |||
<note> | |||
<code>fo:declarations</code> <strong>must</strong> be declared after | |||
<code>fo:layout-master-set</code> and before the first <code>page-sequence</code>. | |||
</note> | |||
</section> | |||
</section> | |||
<section id="xmp-impl-in-fop"> | |||
<title>Implementation in Apache FOP</title> | |||
<p> | |||
Currently, XMP support is only available for PDF output. | |||
</p> | |||
<p> | |||
Originally, you could set some metadata information through FOP's FOUserAgent by | |||
using its set*() methods (like setTitle(String) or setAuthor(String). These values are | |||
directly used to set value in the PDF Info object. Since PDF 1.4, adding metadata as an | |||
XMP document to a PDF is possible. That means that there are now two mechanisms in PDF | |||
that hold metadata. | |||
</p> | |||
<p> | |||
Apache FOP now synchronizes the Info and the Metadata object in PDF, i.e. when you | |||
set the title and the author through the FOUserAgent, the two values will end up in | |||
the (old) Info object and in the new Metadata object as XMP content. If instead of | |||
FOUserAgent, you embed XMP metadata in the XSL-FO document (as shown above), the | |||
XMP metadata will be used as-is in the PDF Metadata object and some values from the | |||
XMP metadata will be copied to the Info object to maintain backwards-compatibility | |||
for PDF readers that don't support XMP metadata. | |||
</p> | |||
<p> | |||
The mapping between the Info and the Metadata object used by Apache FOP comes from | |||
the <a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=38920">PDF/A-1 specification</a>. | |||
For convenience, here's the mapping table: | |||
</p> | |||
<table> | |||
<tr> | |||
<th colspan="2">Document information dictionary</th> | |||
<th colspan="3">XMP</th> | |||
</tr> | |||
<tr> | |||
<th>Entry</th> | |||
<th>PDF type</th> | |||
<th>Property</th> | |||
<th>XMP type</th> | |||
<th>Category</th> | |||
</tr> | |||
<tr> | |||
<td>Title</td> | |||
<td>text string</td> | |||
<td>dc:title</td> | |||
<td>Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Author</td> | |||
<td>text string</td> | |||
<td>dc:creator</td> | |||
<td>seq Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Subject</td> | |||
<td>text string</td> | |||
<td>dc:description["x-default"]</td> | |||
<td>Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Keywords</td> | |||
<td>text string</td> | |||
<td>pdf:Keywords</td> | |||
<td>Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Creator</td> | |||
<td>text string</td> | |||
<td>xmp:CreatorTool</td> | |||
<td>Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Producer</td> | |||
<td>text string</td> | |||
<td>pdf:Producer</td> | |||
<td>Text</td> | |||
<td>Internal</td> | |||
</tr> | |||
<tr> | |||
<td>CreationDate</td> | |||
<td>date</td> | |||
<td>xmp:CreationDate</td> | |||
<td>Date</td> | |||
<td>Internal</td> | |||
</tr> | |||
<tr> | |||
<td>ModDate</td> | |||
<td>date</td> | |||
<td>xmp:ModifyDate</td> | |||
<td>Date</td> | |||
<td>Internal</td> | |||
</tr> | |||
</table> | |||
<note> | |||
"Internal" in the Category column means that the user should not set this value. | |||
It is set by the application. | |||
</note> | |||
<note> | |||
The "Subject" used to be mapped to <code>dc:subject</code> in the initial publication of | |||
PDF/A-1 (ISO 19005-1). In the | |||
<a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=45613">Technical Corrigendum 1</a> | |||
this was changed to map to <code>dc:description["x-default"]</code>. | |||
</note> | |||
<section id="namespaces"> | |||
<title>Namespaces</title> | |||
<p> | |||
Metadata is made of property sets where each property set uses a different namespace URI. | |||
</p> | |||
<p> | |||
The following is a listing of namespaces that Apache FOP recognizes and acts upon, | |||
mostly to synchronize the XMP metadata with the PDF Info dictionary: | |||
</p> | |||
<table> | |||
<tr> | |||
<th>Set/Schema</th> | |||
<th>Namespace Prefix</th> | |||
<th>Namespace URI</th> | |||
</tr> | |||
<tr> | |||
<td>Dublin Core</td> | |||
<td>dc</td> | |||
<td>http://purl.org/dc/elements/1.1/</td> | |||
</tr> | |||
<tr> | |||
<td>XMP Basic</td> | |||
<td>xmp</td> | |||
<td>http://ns.adobe.com/xap/1.0/</td> | |||
</tr> | |||
<tr> | |||
<td>Adobe PDF Schema</td> | |||
<td>pdf</td> | |||
<td>http://ns.adobe.com/pdf/1.3/</td> | |||
</tr> | |||
</table> | |||
<p> | |||
Please refer to the <a href="http://partners.adobe.com/public/developer/en/xmp/sdk/XMPspecification.pdf">XMP Specification</a> | |||
for information on other metadata namespaces. | |||
</p> | |||
<p> | |||
Property sets (Namespaces) not listed here are simply passed through to the final | |||
document (if supported). That is useful if you want to specify a custom metadata | |||
schema. | |||
</p> | |||
</section> | |||
</section> | |||
<section id="links"> | |||
<title>Links</title> | |||
<ul> | |||
<li><a href="http://www.adobe.com/products/xmp/">Adobe's Extensible Metadata Platform (XMP) website</a></li> | |||
<li><a href="http://partners.adobe.com/public/developer/en/xmp/sdk/XMPspecification.pdf">Adobe XMP Specification</a></li> | |||
<li><a href="http://partners.adobe.com/public/developer/en/xmp/sdk/XMPspecification.pdf">Adobe XMP Specification</a></li> | |||
<li><a href="http://dublincore.org/">http://dublincore.org/</a></li> | |||
</ul> | |||
</section> | |||
</body> | |||
</document> |
@@ -28,9 +28,6 @@ | |||
<body> | |||
<section id="overview"> | |||
<title>Overview</title> | |||
<warning> | |||
Support for PDF/A is available beginning with version 0.92. | |||
</warning> | |||
<p> | |||
PDF/A is a standard which turns PDF into an "electronic document file | |||
format for long-term preservation". PDF/A-1 is the first part of the |
@@ -385,6 +385,47 @@ | |||
</p> | |||
</answer> | |||
</faq> | |||
<faq id="saxexception-mismatch"> | |||
<question>I get a SAXException: Mismatch: page-sequence vs. root | |||
(or similar).</question> | |||
<answer> | |||
<p> | |||
The full exception usually looks similar to this: | |||
</p> | |||
<source>Mismatch: page-sequence (http://www.w3.org/1999/XSL/Format) vs. root | |||
(http://www.w3.org/1999/XSL/Format)</source> | |||
<p> | |||
This exception is usually a follow-up error after another exception. Sometimes | |||
the original exception gets swallowed by Xalan's default <code>ErrorListener</code> | |||
(should be fixed in the latest Xalan release). | |||
</p> | |||
<p> | |||
The work-around is to set an explicit <code>ErrorListener</code> on the | |||
<code>Transformer</code>. The <code>ErrorListener</code> can be as simple as this: | |||
</p> | |||
<source><![CDATA[ | |||
import javax.xml.transform.ErrorListener; | |||
import javax.xml.transform.TransformerException; | |||
public class DefaultErrorListener implements ErrorListener { | |||
public void warning(TransformerException exc) { | |||
System.err.println(exc.toString()); | |||
} | |||
public void error(TransformerException exc) | |||
throws TransformerException { | |||
throw exc; | |||
} | |||
public void fatalError(TransformerException exc) | |||
throws TransformerException { | |||
throw exc; | |||
} | |||
}]]></source> | |||
</answer> | |||
</faq> | |||
</part> | |||
<part id="part-output"> | |||
<title>Problems with FOP output</title> | |||
@@ -551,8 +592,10 @@ Check the following:</p> | |||
text flows into adjacent cells/block, obscuring stuff there.</question> | |||
<answer> | |||
<p> | |||
Clipping as specified by the <code>overflow="hidden"</code> is not yet | |||
implemented. If you have long words overflowing table cells, try to | |||
Since the <code>overflow</code> property doesn't apply to table-cell, you | |||
can wrap the cell content in a block-container and specify | |||
<code>overflow="hidden"</code> there. Alternatively, | |||
if you have long words overflowing table cells, try to | |||
get them hyphenated. Artificial names like product identifications or | |||
long numbers usually aren't hyphenated. You can try special processing | |||
at XSLT level, like | |||
@@ -574,6 +617,15 @@ Check the following:</p> | |||
<link href="http://www.mulberrytech.com/xsl/xsl-list/">XSL list | |||
archive</link> for how to perform these tasks. | |||
</p> | |||
<p> | |||
If your text is not hyphenated at all and overflows the cell, please check | |||
if you've specified <code>keep-together="always"</code> on the table-cell | |||
or one of its parent elements. <code>keep-together="always"</code> implicitely | |||
also sets <code>keep-together.within-line="always"</code> which forbids FOP | |||
to break the text into multiple lines. This is important as FOP supports inline-level | |||
keeps since version 0.94. It's a good idea not to use the shorthand | |||
<code>keep-together="always"</code> at all! | |||
</p> | |||
</answer> | |||
</faq> | |||
<faq id="row-height-constraint"> |
@@ -123,6 +123,7 @@ | |||
<fonts label="Fonts" href="fonts.html"/> | |||
<hyphenation label="Hyphenation" href="hyphenation.html"/> | |||
<extensions label="Extensions" href="extensions.html"/> | |||
<metadata label="Metadata" href="metadata.html"/> | |||
</features> | |||
</trunk> | |||
@@ -157,6 +158,7 @@ | |||
<hyphenation label="Hyphenation" href="hyphenation.html"/> | |||
<extensions label="Extensions" href="extensions.html"/> | |||
<events label="Events" href="events.html"/> | |||
<metadata label="Metadata" href="metadata.html"/> | |||
</features> | |||
</trunk> |
@@ -0,0 +1,243 @@ | |||
<?xml version="1.0" 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$ --> | |||
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V2.0//EN" "document-v20.dtd"> | |||
<document> | |||
<header> | |||
<title>Metadata</title> | |||
</header> | |||
<body> | |||
<section id="overview"> | |||
<title>Overview</title> | |||
<p> | |||
Document metadata is an important tool for categorizing and finding documents. | |||
Various formats support different kinds of metadata representation and to | |||
different levels. One of the more popular and flexible means of representing | |||
document or object metadata is | |||
<a href="http://www.adobe.com/products/xmp/">XMP (eXtensible Metadata Platform, specified by Adobe)</a>. | |||
PDF 1.4 introduced the use of XMP. The XMP specification lists recommendation for | |||
embedding XMP metdata in other document and image formats. Given its flexibility it makes | |||
sense to make use this approach in the XSL-FO context. Unfortunately, unlike SVG which | |||
also refers to XMP, XSL-FO doesn't recommend a preferred way of specifying document and | |||
object metadata. Therefore, there's no portable way to represent metadata in XSL-FO | |||
documents. Each implementation does it differently. | |||
</p> | |||
</section> | |||
<section id="xmp-in-fo"> | |||
<title>Embedding XMP in an XSL-FO document</title> | |||
<p> | |||
As noted above, there's no officially recommended way to embed metadata in XSL-FO. | |||
Apache FOP supports embedding XMP in XSL-FO. Currently, only support for document-level | |||
metadata is implemented. Object-level metadata will be implemented when there's | |||
interest. | |||
</p> | |||
<p> | |||
Document-level metadata can be specified in the <code>fo:declarations</code> element. | |||
XMP specification recommends to use <code>x:xmpmeta</code>, <code>rdf:RDF</code>, and | |||
<code>rdf:Description</code> elements as shown in example below. Both | |||
<code>x:xmpmeta</code> and <code>rdf:RDF</code> elements are recognized as the top-level | |||
element introducing an XMP fragment (as per the XMP specification). | |||
</p> | |||
<section id="xmp-example"> | |||
<title>Example</title> | |||
<source><![CDATA[[..] | |||
</fo:layout-master-set> | |||
<fo:declarations> | |||
<x:xmpmeta xmlns:x="adobe:ns:meta/"> | |||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> | |||
<rdf:Description rdf:about="" | |||
xmlns:dc="http://purl.org/dc/elements/1.1/"> | |||
<!-- Dublin Core properties go here --> | |||
<dc:title>Document title</dc:title> | |||
<dc:creator>Document author</dc:creator> | |||
<dc:description>Document subject</dc:description> | |||
</rdf:Description> | |||
<rdf:Description rdf:about="" | |||
xmlns:xmp="http://ns.adobe.com/xap/1.0/"> | |||
<!-- XMP properties go here --> | |||
<xmp:CreatorTool>Tool used to make the PDF</xmp:CreatorTool> | |||
</rdf:Description> | |||
</rdf:RDF> | |||
</x:xmpmeta> | |||
</fo:declarations> | |||
<fo:page-sequence ... | |||
[..]]]></source> | |||
<note> | |||
<code>fo:declarations</code> <strong>must</strong> be declared after | |||
<code>fo:layout-master-set</code> and before the first <code>page-sequence</code>. | |||
</note> | |||
</section> | |||
</section> | |||
<section id="xmp-impl-in-fop"> | |||
<title>Implementation in Apache FOP</title> | |||
<p> | |||
Currently, XMP support is only available for PDF output. | |||
</p> | |||
<p> | |||
Originally, you could set some metadata information through FOP's FOUserAgent by | |||
using its set*() methods (like setTitle(String) or setAuthor(String). These values are | |||
directly used to set value in the PDF Info object. Since PDF 1.4, adding metadata as an | |||
XMP document to a PDF is possible. That means that there are now two mechanisms in PDF | |||
that hold metadata. | |||
</p> | |||
<p> | |||
Apache FOP now synchronizes the Info and the Metadata object in PDF, i.e. when you | |||
set the title and the author through the FOUserAgent, the two values will end up in | |||
the (old) Info object and in the new Metadata object as XMP content. If instead of | |||
FOUserAgent, you embed XMP metadata in the XSL-FO document (as shown above), the | |||
XMP metadata will be used as-is in the PDF Metadata object and some values from the | |||
XMP metadata will be copied to the Info object to maintain backwards-compatibility | |||
for PDF readers that don't support XMP metadata. | |||
</p> | |||
<p> | |||
The mapping between the Info and the Metadata object used by Apache FOP comes from | |||
the <a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=38920">PDF/A-1 specification</a>. | |||
For convenience, here's the mapping table: | |||
</p> | |||
<table> | |||
<tr> | |||
<th colspan="2">Document information dictionary</th> | |||
<th colspan="3">XMP</th> | |||
</tr> | |||
<tr> | |||
<th>Entry</th> | |||
<th>PDF type</th> | |||
<th>Property</th> | |||
<th>XMP type</th> | |||
<th>Category</th> | |||
</tr> | |||
<tr> | |||
<td>Title</td> | |||
<td>text string</td> | |||
<td>dc:title</td> | |||
<td>Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Author</td> | |||
<td>text string</td> | |||
<td>dc:creator</td> | |||
<td>seq Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Subject</td> | |||
<td>text string</td> | |||
<td>dc:description["x-default"]</td> | |||
<td>Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Keywords</td> | |||
<td>text string</td> | |||
<td>pdf:Keywords</td> | |||
<td>Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Creator</td> | |||
<td>text string</td> | |||
<td>xmp:CreatorTool</td> | |||
<td>Text</td> | |||
<td>External</td> | |||
</tr> | |||
<tr> | |||
<td>Producer</td> | |||
<td>text string</td> | |||
<td>pdf:Producer</td> | |||
<td>Text</td> | |||
<td>Internal</td> | |||
</tr> | |||
<tr> | |||
<td>CreationDate</td> | |||
<td>date</td> | |||
<td>xmp:CreationDate</td> | |||
<td>Date</td> | |||
<td>Internal</td> | |||
</tr> | |||
<tr> | |||
<td>ModDate</td> | |||
<td>date</td> | |||
<td>xmp:ModifyDate</td> | |||
<td>Date</td> | |||
<td>Internal</td> | |||
</tr> | |||
</table> | |||
<note> | |||
"Internal" in the Category column means that the user should not set this value. | |||
It is set by the application. | |||
</note> | |||
<note> | |||
The "Subject" used to be mapped to <code>dc:subject</code> in the initial publication of | |||
PDF/A-1 (ISO 19005-1). In the | |||
<a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=45613">Technical Corrigendum 1</a> | |||
this was changed to map to <code>dc:description["x-default"]</code>. | |||
</note> | |||
<section id="namespaces"> | |||
<title>Namespaces</title> | |||
<p> | |||
Metadata is made of property sets where each property set uses a different namespace URI. | |||
</p> | |||
<p> | |||
The following is a listing of namespaces that Apache FOP recognizes and acts upon, | |||
mostly to synchronize the XMP metadata with the PDF Info dictionary: | |||
</p> | |||
<table> | |||
<tr> | |||
<th>Set/Schema</th> | |||
<th>Namespace Prefix</th> | |||
<th>Namespace URI</th> | |||
</tr> | |||
<tr> | |||
<td>Dublin Core</td> | |||
<td>dc</td> | |||
<td>http://purl.org/dc/elements/1.1/</td> | |||
</tr> | |||
<tr> | |||
<td>XMP Basic</td> | |||
<td>xmp</td> | |||
<td>http://ns.adobe.com/xap/1.0/</td> | |||
</tr> | |||
<tr> | |||
<td>Adobe PDF Schema</td> | |||
<td>pdf</td> | |||
<td>http://ns.adobe.com/pdf/1.3/</td> | |||
</tr> | |||
</table> | |||
<p> | |||
Please refer to the <a href="http://partners.adobe.com/public/developer/en/xmp/sdk/XMPspecification.pdf">XMP Specification</a> | |||
for information on other metadata namespaces. | |||
</p> | |||
<p> | |||
Property sets (Namespaces) not listed here are simply passed through to the final | |||
document (if supported). That is useful if you want to specify a custom metadata | |||
schema. | |||
</p> | |||
</section> | |||
</section> | |||
<section id="links"> | |||
<title>Links</title> | |||
<ul> | |||
<li><a href="http://www.adobe.com/products/xmp/">Adobe's Extensible Metadata Platform (XMP) website</a></li> | |||
<li><a href="http://partners.adobe.com/public/developer/en/xmp/sdk/XMPspecification.pdf">Adobe XMP Specification</a></li> | |||
<li><a href="http://partners.adobe.com/public/developer/en/xmp/sdk/XMPspecification.pdf">Adobe XMP Specification</a></li> | |||
<li><a href="http://dublincore.org/">http://dublincore.org/</a></li> | |||
</ul> | |||
</section> | |||
</body> | |||
</document> |
@@ -28,9 +28,6 @@ | |||
<body> | |||
<section id="overview"> | |||
<title>Overview</title> | |||
<warning> | |||
Support for PDF/A is available beginning with version 0.92. | |||
</warning> | |||
<p> | |||
PDF/A is a standard which turns PDF into an "electronic document file | |||
format for long-term preservation". PDF/A-1 is the first part of the |
@@ -34,14 +34,12 @@ import javax.xml.transform.stream.StreamSource; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.util.io.Base64EncodeStream; | |||
import org.apache.fop.util.DataURIResolver; | |||
import org.apache.xmlgraphics.util.uri.CommonURIResolver; | |||
/** | |||
* Provides FOP specific URI resolution. This is the default URIResolver | |||
* {@link FOUserAgent} will use unless overidden. | |||
* {@link FOUserAgent} will use unless overridden. | |||
* | |||
* @see javax.xml.transform.URIResolver | |||
*/ | |||
@@ -50,8 +48,8 @@ public class FOURIResolver implements javax.xml.transform.URIResolver { | |||
// log | |||
private Log log = LogFactory.getLog("FOP"); | |||
/** URIResolver for RFC 2397 data URLs */ | |||
private URIResolver dataURIResolver = new DataURIResolver(); | |||
/** Common URIResolver */ | |||
private CommonURIResolver commonURIResolver = new CommonURIResolver(); | |||
/** A user settable URI Resolver */ | |||
private URIResolver uriResolver = null; | |||
@@ -152,7 +150,7 @@ public class FOURIResolver implements javax.xml.transform.URIResolver { | |||
// data URLs can be quite long so evaluate early and don't try to build a File | |||
// (can lead to problems) | |||
source = dataURIResolver.resolve(href, base); | |||
source = commonURIResolver.resolve(href, base); | |||
// Custom uri resolution | |||
if (source == null && uriResolver != null) { |
@@ -33,9 +33,12 @@ import java.lang.ref.WeakReference; | |||
*/ | |||
public final class PropertyCache { | |||
private static final int SEGMENT_COUNT = 32; //0x20 | |||
private static final int INITIAL_BUCKET_COUNT = SEGMENT_COUNT; | |||
/** bitmask to apply to the hash to get to the | |||
* corresponding cache segment */ | |||
private static final int SEGMENT_MASK = 0x1F; | |||
private static final int SEGMENT_MASK = SEGMENT_COUNT - 1; //0x1F | |||
/** | |||
* Indicates whether the cache should be used at all | |||
* Can be controlled by the system property: | |||
@@ -44,13 +47,13 @@ public final class PropertyCache { | |||
private final boolean useCache; | |||
/** the segments array (length = 32) */ | |||
private CacheSegment[] segments = new CacheSegment[SEGMENT_MASK + 1]; | |||
private CacheSegment[] segments = new CacheSegment[SEGMENT_COUNT]; | |||
/** the table of hash-buckets */ | |||
private CacheEntry[] table = new CacheEntry[8]; | |||
private CacheEntry[] table = new CacheEntry[INITIAL_BUCKET_COUNT]; | |||
private Class runtimeType; | |||
final boolean[] votesForRehash = new boolean[SEGMENT_MASK + 1]; | |||
private boolean[] votesForRehash = new boolean[SEGMENT_COUNT]; | |||
/* same hash function as used by java.util.HashMap */ | |||
private static int hash(Object x) { | |||
@@ -72,53 +75,61 @@ public final class PropertyCache { | |||
} | |||
/* Class modeling a cached entry */ | |||
private final class CacheEntry extends WeakReference { | |||
volatile CacheEntry nextEntry; | |||
final int hash; | |||
private static class CacheEntry extends WeakReference { | |||
private volatile CacheEntry nextEntry; | |||
private final int hash; | |||
/* main constructor */ | |||
public CacheEntry(Object p, CacheEntry nextEntry, ReferenceQueue refQueue) { | |||
super(p, refQueue); | |||
this.nextEntry = nextEntry; | |||
this.hash = p.hashCode(); | |||
this.hash = hash(p); | |||
} | |||
/* main constructor */ | |||
public CacheEntry(Object p, CacheEntry nextEntry) { | |||
super(p); | |||
this.nextEntry = nextEntry; | |||
this.hash = hash(p); | |||
} | |||
} | |||
/* Wrapper objects to synchronize on */ | |||
private final class CacheSegment { | |||
private static class CacheSegment { | |||
private int count = 0; | |||
private volatile ReferenceQueue staleEntries = new ReferenceQueue(); | |||
} | |||
private void cleanSegment(int segmentIndex) { | |||
CacheEntry entry; | |||
CacheSegment segment = segments[segmentIndex]; | |||
int bucketIndex; | |||
int oldCount = segment.count; | |||
while ((entry = (CacheEntry) segment.staleEntries.poll()) != null) { | |||
bucketIndex = hash(entry.hash) & (table.length - 1); | |||
/* remove obsolete entry */ | |||
/* 1. move to the corresponding entry */ | |||
/* clean all buckets in this segment */ | |||
for (int bucketIndex = segmentIndex; | |||
bucketIndex < table.length; | |||
bucketIndex += SEGMENT_COUNT) { | |||
CacheEntry prev = null; | |||
CacheEntry e = table[bucketIndex]; | |||
while (e != null | |||
&& e.nextEntry != null | |||
&& e.hash != entry.hash) { | |||
prev = e; | |||
e = e.nextEntry; | |||
CacheEntry entry = table[bucketIndex]; | |||
if (entry == null) { | |||
continue; | |||
} | |||
if (e != null) { | |||
/* 2. remove reference from the chain */ | |||
if (prev == null) { | |||
table[bucketIndex] = e.nextEntry; | |||
do { | |||
if (entry.get() == null) { | |||
if (prev == null) { | |||
table[bucketIndex] = entry.nextEntry; | |||
} else { | |||
prev.nextEntry = entry.nextEntry; | |||
} | |||
segment.count--; | |||
assert segment.count >= 0; | |||
} else { | |||
prev.nextEntry = e.nextEntry; | |||
prev = entry; | |||
} | |||
segment.count--; | |||
} | |||
entry = entry.nextEntry; | |||
} while (entry != null); | |||
} | |||
synchronized (votesForRehash) { | |||
if (oldCount > segment.count) { | |||
votesForRehash[segmentIndex] = false; | |||
@@ -129,7 +140,7 @@ public final class PropertyCache { | |||
/* first time for this segment */ | |||
votesForRehash[segmentIndex] = true; | |||
int voteCount = 0; | |||
for (int i = SEGMENT_MASK + 1; --i >= 0; ) { | |||
for (int i = SEGMENT_MASK + 1; --i >= 0;) { | |||
if (votesForRehash[i]) { | |||
voteCount++; | |||
} | |||
@@ -156,14 +167,15 @@ public final class PropertyCache { | |||
private void put(Object o) { | |||
int hash = hash(o); | |||
CacheSegment segment = segments[hash & SEGMENT_MASK]; | |||
int segmentIndex = hash & SEGMENT_MASK; | |||
CacheSegment segment = segments[segmentIndex]; | |||
synchronized (segment) { | |||
int index = hash & (table.length - 1); | |||
CacheEntry entry = table[index]; | |||
if (entry == null) { | |||
entry = new CacheEntry(o, null, segment.staleEntries); | |||
entry = new CacheEntry(o, null); | |||
table[index] = entry; | |||
segment.count++; | |||
} else { | |||
@@ -171,14 +183,14 @@ public final class PropertyCache { | |||
if (eq(p, o)) { | |||
return; | |||
} else { | |||
CacheEntry newEntry = new CacheEntry(o, entry, segment.staleEntries); | |||
CacheEntry newEntry = new CacheEntry(o, entry); | |||
table[index] = newEntry; | |||
segment.count++; | |||
} | |||
} | |||
if (segment.count > (2 * table.length)) { | |||
cleanSegment(hash & SEGMENT_MASK); | |||
cleanSegment(segmentIndex); | |||
} | |||
} | |||
} | |||
@@ -195,7 +207,7 @@ public final class PropertyCache { | |||
/* try non-synched first */ | |||
for (CacheEntry e = entry; e != null; e = e.nextEntry) { | |||
if (e.hash == o.hashCode() | |||
if (e.hash == hash | |||
&& (q = e.get()) != null | |||
&& eq(q, o)) { | |||
return q; | |||
@@ -209,7 +221,7 @@ public final class PropertyCache { | |||
synchronized (segment) { | |||
entry = table[index]; | |||
for (CacheEntry e = entry; e != null; e = e.nextEntry) { | |||
if (e.hash == o.hashCode() | |||
if (e.hash == hash | |||
&& (q = e.get()) != null | |||
&& eq(q, o)) { | |||
return q; | |||
@@ -235,7 +247,7 @@ public final class PropertyCache { | |||
/* double the amount of buckets */ | |||
int newLength = table.length << 1; | |||
if (newLength > 0) { //no overflow? | |||
/* reset segmentcounts */ | |||
/* reset segment counts */ | |||
for (int i = segments.length; --i >= 0;) { | |||
segments[i].count = 0; | |||
} | |||
@@ -250,8 +262,7 @@ public final class PropertyCache { | |||
if ((o = c.get()) != null) { | |||
hash = c.hash; | |||
idx = hash & newLength; | |||
newTable[idx] = new CacheEntry(o, newTable[idx], | |||
segments[hash & SEGMENT_MASK].staleEntries); | |||
newTable[idx] = new CacheEntry(o, newTable[idx]); | |||
segments[hash & SEGMENT_MASK].count++; | |||
} | |||
} | |||
@@ -313,7 +324,7 @@ public final class PropertyCache { | |||
* @param prop the Property instance to check for | |||
* @return the cached instance | |||
*/ | |||
public final Property fetch(Property prop) { | |||
public Property fetch(Property prop) { | |||
return (Property) fetch((Object) prop); | |||
} | |||
@@ -326,7 +337,7 @@ public final class PropertyCache { | |||
* @param chy the CommonHyphenation instance to check for | |||
* @return the cached instance | |||
*/ | |||
public final CommonHyphenation fetch(CommonHyphenation chy) { | |||
public CommonHyphenation fetch(CommonHyphenation chy) { | |||
return (CommonHyphenation) fetch((Object) chy); | |||
} | |||
@@ -339,7 +350,7 @@ public final class PropertyCache { | |||
* @param cf the CommonFont instance to check for | |||
* @return the cached instance | |||
*/ | |||
public final CommonFont fetch(CommonFont cf) { | |||
public CommonFont fetch(CommonFont cf) { | |||
return (CommonFont) fetch((Object) cf); | |||
} | |||
@@ -352,21 +363,21 @@ public final class PropertyCache { | |||
* @param cbpb the CommonBorderPaddingBackground instance to check for | |||
* @return the cached instance | |||
*/ | |||
public final CommonBorderPaddingBackground fetch(CommonBorderPaddingBackground cbpb) { | |||
public CommonBorderPaddingBackground fetch(CommonBorderPaddingBackground cbpb) { | |||
return (CommonBorderPaddingBackground) fetch((Object) cbpb); | |||
} | |||
/** | |||
* Checks if the given {@link CommonBorderPaddingBackground.BorderInfo} is present in the cache - | |||
* if so, returns a reference to the cached instance. | |||
* Checks if the given {@link CommonBorderPaddingBackground.BorderInfo} is present | |||
* in the cache - if so, returns a reference to the cached instance. | |||
* Otherwise the given object is added to the cache and returned. | |||
* | |||
* @param bi the BorderInfo instance to check for | |||
* @return the cached instance | |||
*/ | |||
public final CommonBorderPaddingBackground.BorderInfo fetch(CommonBorderPaddingBackground.BorderInfo bi) { | |||
public CommonBorderPaddingBackground.BorderInfo fetch( | |||
CommonBorderPaddingBackground.BorderInfo bi) { | |||
return (CommonBorderPaddingBackground.BorderInfo) fetch((Object) bi); | |||
} | |||
@@ -285,7 +285,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { | |||
/** | |||
* Get the string containing all the commands written into this | |||
* Grpahics. | |||
* Graphics. | |||
* @return the string containing the PDF markup | |||
*/ | |||
public String getString() { | |||
@@ -294,7 +294,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { | |||
/** | |||
* Get the string buffer from the currentStream, containing all | |||
* the commands written into this Grpahics so far. | |||
* the commands written into this Graphics so far. | |||
* @return the StringBuffer containing the PDF markup | |||
*/ | |||
public StringBuffer getBuffer() { | |||
@@ -872,7 +872,7 @@ public class PDFGraphics2D extends AbstractGraphics2D { | |||
if (paint instanceof RadialGradientPaint) { | |||
RadialGradientPaint rgp = (RadialGradientPaint)paint; | |||
// There is essentially no way to support repeate | |||
// There is essentially no way to support repeats | |||
// in PDF for radial gradients (the one option would | |||
// be to 'grow' the outer circle until it fully covered | |||
// the bounds and then grow the stops accordingly, the |
@@ -147,7 +147,9 @@ public class PDFTextPainter extends StrokingTextPainter { | |||
textUtil.beginTextObject(); | |||
textUtil.setFonts(fonts); | |||
textUtil.setTextRenderingMode(tpi.fillPaint != null, tpi.strokePaint != null, false); | |||
boolean stroke = (tpi.strokePaint != null) | |||
&& (tpi.strokeStroke != null); | |||
textUtil.setTextRenderingMode(tpi.fillPaint != null, stroke, false); | |||
AffineTransform localTransform = new AffineTransform(); | |||
Point2D prevPos = null; |
@@ -19,60 +19,25 @@ | |||
package org.apache.fop.util; | |||
import java.io.ByteArrayInputStream; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.URIResolver; | |||
import javax.xml.transform.stream.StreamSource; | |||
// base64 support for "data" urls | |||
import org.apache.xmlgraphics.util.io.Base64DecodeStream; | |||
/** | |||
* Resolves data URLs (described in RFC 2397) returning its data as a StreamSource. | |||
* | |||
* @see javax.xml.transform.URIResolver | |||
* @see <a href="http://www.ietf.org/rfc/rfc2397">RFC 2397</a> | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.uri.DataURIResolver | |||
*/ | |||
public class DataURIResolver implements URIResolver { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
public Source resolve(String href, String base) throws TransformerException { | |||
if (href.startsWith("data:")) { | |||
return parseDataURI(href); | |||
} else { | |||
return null; | |||
} | |||
} | |||
private final URIResolver newResolver = new org.apache.xmlgraphics.util.uri.DataURIResolver(); | |||
/** | |||
* Parses inline data URIs as generated by MS Word's XML export and FO | |||
* stylesheet. | |||
* | |||
* @see <a href="http://www.ietf.org/rfc/rfc2397">RFC 2397</a> | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.uri.DataURIResolver#resolve(String, | |||
* String) | |||
*/ | |||
private Source parseDataURI(String href) { | |||
int commaPos = href.indexOf(','); | |||
// header is of the form data:[<mediatype>][;base64] | |||
String header = href.substring(0, commaPos); | |||
String data = href.substring(commaPos + 1); | |||
if (header.endsWith(";base64")) { | |||
byte[] bytes = data.getBytes(); | |||
ByteArrayInputStream encodedStream = new ByteArrayInputStream(bytes); | |||
Base64DecodeStream decodedStream = new Base64DecodeStream( | |||
encodedStream); | |||
return new StreamSource(decodedStream); | |||
} else { | |||
// Note that this is not quite the full story here. But since we are | |||
// only interested | |||
// in base64-encoded binary data, the next line will probably never | |||
// be called. | |||
//TODO Handle un-escaping of special URL chars like %20 | |||
return new StreamSource(new java.io.StringReader(data)); | |||
} | |||
public Source resolve(String href, String base) throws TransformerException { | |||
return newResolver.resolve(href, base); | |||
} | |||
} |
@@ -21,47 +21,33 @@ package org.apache.fop.util; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.StringWriter; | |||
import java.io.Writer; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.xmlgraphics.util.io.Base64EncodeStream; | |||
/** | |||
* Utility classes for generating RFC 2397 data URLs. | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.uri.DataURLUtil | |||
*/ | |||
public class DataURLUtil { | |||
/** | |||
* Creates a new data URL and returns it as a String. | |||
* @param in the InputStream to read the data from | |||
* @param mediatype the MIME type of the content, or null | |||
* @return the newly created data URL | |||
* @throws IOException if an I/O error occurs | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.uri.DataURLUtil#createDataURL(InputStream, | |||
* String) | |||
*/ | |||
public static String createDataURL(InputStream in, String mediatype) throws IOException { | |||
StringWriter writer = new StringWriter(); | |||
writeDataURL(in, mediatype, writer); | |||
return writer.toString(); | |||
public static String createDataURL(InputStream in, String mediatype) | |||
throws IOException { | |||
return org.apache.xmlgraphics.util.uri.DataURLUtil.createDataURL(in, | |||
mediatype); | |||
} | |||
/** | |||
* Generates a data URL and writes it to a Writer. | |||
* @param in the InputStream to read the data from | |||
* @param mediatype the MIME type of the content, or null | |||
* @param writer the Writer to write to | |||
* @throws IOException if an I/O error occurs | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.uri.DataURLUtil#writeDataURL(InputStream, | |||
* String, Writer) | |||
*/ | |||
public static void writeDataURL(InputStream in, String mediatype, Writer writer) | |||
throws IOException { | |||
writer.write("data:"); | |||
if (mediatype != null) { | |||
writer.write(mediatype); | |||
} | |||
writer.write(";base64,"); | |||
Base64EncodeStream out = new Base64EncodeStream( | |||
new WriterOutputStream(writer, "US-ASCII")); | |||
IOUtils.copy(in, out); | |||
out.flush(); | |||
public static void writeDataURL(InputStream in, String mediatype, | |||
Writer writer) throws IOException { | |||
org.apache.xmlgraphics.util.uri.DataURLUtil.writeDataURL(in, mediatype, | |||
writer); | |||
} | |||
} |
@@ -0,0 +1,170 @@ | |||
/* | |||
* 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.util; | |||
import java.awt.geom.AffineTransform; | |||
/** | |||
* Utility class for unit conversions. | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv instead. | |||
*/ | |||
public final class UnitConv { | |||
/** | |||
* conversion factory from millimeters to inches. | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.IN2MM instead. | |||
*/ | |||
public static final float IN2MM = org.apache.xmlgraphics.util.UnitConv.IN2MM; | |||
/** | |||
* conversion factory from centimeters to inches. | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.IN2CM instead. | |||
*/ | |||
public static final float IN2CM = org.apache.xmlgraphics.util.UnitConv.IN2CM; | |||
/** | |||
* conversion factory from inches to points. | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.IN2PT instead. | |||
*/ | |||
public static final int IN2PT = org.apache.xmlgraphics.util.UnitConv.IN2PT; | |||
/** | |||
* Converts millimeters (mm) to points (pt) | |||
* @param mm the value in mm | |||
* @return the value in pt | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.mm2pt(mm) instead. | |||
*/ | |||
public static double mm2pt(double mm) { | |||
return org.apache.xmlgraphics.util.UnitConv.mm2pt(mm); | |||
} | |||
/** | |||
* Converts millimeters (mm) to millipoints (mpt) | |||
* @param mm the value in mm | |||
* @return the value in mpt | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.mm2mpt(mm) instead. | |||
*/ | |||
public static double mm2mpt(double mm) { | |||
return org.apache.xmlgraphics.util.UnitConv.mm2mpt(mm); | |||
} | |||
/** | |||
* Converts points (pt) to millimeters (mm) | |||
* @param pt the value in pt | |||
* @return the value in mm | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.pt2mm(pt) instead. | |||
*/ | |||
public static double pt2mm(double pt) { | |||
return org.apache.xmlgraphics.util.UnitConv.pt2mm(pt); | |||
} | |||
/** | |||
* Converts millimeters (mm) to inches (in) | |||
* @param mm the value in mm | |||
* @return the value in inches | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.pt2mm(pt) instead. | |||
*/ | |||
public static double mm2in(double mm) { | |||
return org.apache.xmlgraphics.util.UnitConv.mm2in(mm); | |||
} | |||
/** | |||
* Converts inches (in) to millimeters (mm) | |||
* @param in the value in inches | |||
* @return the value in mm | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.in2mm(in) instead. | |||
*/ | |||
public static double in2mm(double in) { | |||
return org.apache.xmlgraphics.util.UnitConv.in2mm(in); | |||
} | |||
/** | |||
* Converts inches (in) to millipoints (mpt) | |||
* @param in the value in inches | |||
* @return the value in mpt | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.in2mpt(in) instead. | |||
*/ | |||
public static double in2mpt(double in) { | |||
return org.apache.xmlgraphics.util.UnitConv.in2mpt(in); | |||
} | |||
/** | |||
* Converts inches (in) to points (pt) | |||
* @param in the value in inches | |||
* @return the value in pt | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.in2pt(in) instead. | |||
*/ | |||
public static double in2pt(double in) { | |||
return org.apache.xmlgraphics.util.UnitConv.in2pt(in); | |||
} | |||
/** | |||
* Converts millipoints (mpt) to inches (in) | |||
* @param mpt the value in mpt | |||
* @return the value in inches | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.mpt2in(mpt) instead. | |||
*/ | |||
public static double mpt2in(double mpt) { | |||
return org.apache.xmlgraphics.util.UnitConv.mpt2in(mpt); | |||
} | |||
/** | |||
* Converts millimeters (mm) to pixels (px) | |||
* @param mm the value in mm | |||
* @param resolution the resolution in dpi (dots per inch) | |||
* @return the value in pixels | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.mm2px(mm, resolution) instead. | |||
*/ | |||
public static double mm2px(double mm, int resolution) { | |||
return org.apache.xmlgraphics.util.UnitConv.mm2px(mm, resolution); | |||
} | |||
/** | |||
* Converts millipoints (mpt) to pixels (px) | |||
* @param mpt the value in mpt | |||
* @param resolution the resolution in dpi (dots per inch) | |||
* @return the value in pixels | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.mpt2px(mpt, resolution) instead. | |||
*/ | |||
public static double mpt2px(double mpt, int resolution) { | |||
return org.apache.xmlgraphics.util.UnitConv.mpt2px(mpt, resolution); | |||
} | |||
/** | |||
* Converts a millipoint-based transformation matrix to points. | |||
* @param at a millipoint-based transformation matrix | |||
* @return a point-based transformation matrix | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.mptToPt(at) instead. | |||
*/ | |||
public static AffineTransform mptToPt(AffineTransform at) { | |||
return org.apache.xmlgraphics.util.UnitConv.mptToPt(at); | |||
} | |||
/** | |||
* Converts a point-based transformation matrix to millipoints. | |||
* @param at a point-based transformation matrix | |||
* @return a millipoint-based transformation matrix | |||
* @deprecated use org.apache.xmlgraphics.util.UnitConv.ptToMpt(at) instead. | |||
*/ | |||
public static AffineTransform ptToMpt(AffineTransform at) { | |||
return org.apache.xmlgraphics.util.UnitConv.ptToMpt(at); | |||
} | |||
} |
@@ -24,68 +24,72 @@ import java.io.OutputStream; | |||
import java.io.Writer; | |||
/** | |||
* An OutputStream wrapper for a Writer. | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.WriterOutputStream | |||
*/ | |||
public class WriterOutputStream extends OutputStream { | |||
private Writer writer; | |||
private String encoding; | |||
private final org.apache.xmlgraphics.util.WriterOutputStream writerOutputStream; | |||
/** | |||
* Creates a new WriterOutputStream. | |||
* @param writer the Writer to write to | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.WriterOutputStream#WriterOutputStream(Writer) | |||
* String) | |||
*/ | |||
public WriterOutputStream(Writer writer) { | |||
this(writer, null); | |||
writerOutputStream = new org.apache.xmlgraphics.util.WriterOutputStream( | |||
writer); | |||
} | |||
/** | |||
* Creates a new WriterOutputStream. | |||
* @param writer the Writer to write to | |||
* @param encoding the encoding to use, or null if the default encoding should be used | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.WriterOutputStream#WriterOutputStream(Writer, | |||
* String) String) | |||
*/ | |||
public WriterOutputStream(Writer writer, String encoding) { | |||
this.writer = writer; | |||
this.encoding = encoding; | |||
writerOutputStream = new org.apache.xmlgraphics.util.WriterOutputStream( | |||
writer, encoding); | |||
} | |||
/** | |||
* {@inheritDoc} | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.WriterOutputStream#close() | |||
*/ | |||
public void close() throws IOException { | |||
writer.close(); | |||
writerOutputStream.close(); | |||
} | |||
/** | |||
* {@inheritDoc} | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.WriterOutputStream#flush() | |||
*/ | |||
public void flush() throws IOException { | |||
writer.flush(); | |||
writerOutputStream.flush(); | |||
} | |||
/** | |||
* {@inheritDoc} | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.WriterOutputStream#write(byte[], int, | |||
* int) | |||
*/ | |||
public void write(byte[] buf, int offset, int length) throws IOException { | |||
if (encoding != null) { | |||
writer.write(new String(buf, offset, length, encoding)); | |||
} else { | |||
writer.write(new String(buf, offset, length)); | |||
} | |||
writerOutputStream.write(buf, offset, length); | |||
} | |||
/** | |||
* {@inheritDoc} | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.WriterOutputStream#write(byte[]) | |||
*/ | |||
public void write(byte[] buf) throws IOException { | |||
write(buf, 0, buf.length); | |||
writerOutputStream.write(buf); | |||
} | |||
/** | |||
* {@inheritDoc} | |||
* @deprecated | |||
* @see org.apache.xmlgraphics.util.WriterOutputStream#write(int) | |||
*/ | |||
public void write(int b) throws IOException { | |||
write(new byte[] {(byte)b}); | |||
writerOutputStream.write(b); | |||
} | |||
} |
@@ -53,6 +53,12 @@ | |||
<changes> | |||
<release version="FOP Trunk" date="TBD"> | |||
<action context="Code" dev="JM" type="fix" importance="high"> | |||
Fixed memory leak in property cache (not cleaning stale PropertyCache$CacheEntry instances). | |||
</action> | |||
<action context="Renderers" dev="JM" type="fix"> | |||
Fixed text stroking in SVG when the stroke-width is zero. | |||
</action> | |||
<action context="Layout" dev="JM" type="fix"> | |||
Fixed the source for a division by zero when the content of an fo:leader with | |||
leader-pattern="use-content" collapses to zero width during layout. | |||
@@ -135,7 +141,7 @@ | |||
Fixed a ClassCastException when using an fo:wrapper as a child | |||
of an fo:block-container. | |||
</action> | |||
<action context="Fonts" dev="AC" type="add"> | |||
<action context="Fonts" dev="AC" type="add" importance="high"> | |||
Add support for font substitution. | |||
</action> | |||
<action context="Renderers" dev="JM" type="fix" fixes-bug="43650"> | |||
@@ -158,7 +164,7 @@ | |||
Add partial support for the "show-destination" property on fo:basic-link | |||
(PDF output only; see limitations on the compliance page) | |||
</action> | |||
<action context="Layout" dev="JM" type="add"> | |||
<action context="Layout" dev="JM" type="add" importance="high"> | |||
Added minimal support for integer keep values on the various keep properties on block-level | |||
FOs. For now, all integer values are treated the same (i.e. without strength distinction). | |||
Using integers allows to avoid overflows that can happen when "always" is used extensively. | |||
@@ -186,7 +192,7 @@ | |||
When a JPEG image is embedded, an optionally embedded color profile is filtered out | |||
as it's already embedded separately in the PDF file. | |||
</action> | |||
<action context="Fonts" dev="JM" type="add"> | |||
<action context="Fonts" dev="JM" type="add" importance="high"> | |||
Added support for addressing all glyphs available in a Type 1 font, not just the ones | |||
in the font's primary encoding. | |||
</action> | |||
@@ -685,7 +691,7 @@ | |||
<action context="Code" dev="JM" type="fix"> | |||
AFP Renderer: Bugfix for 1 bit images where the width is not a multiple of 8. | |||
</action> | |||
<action context="Code" dev="MM" type="add"> | |||
<action context="Code" dev="MM" type="add" importance="high"> | |||
Support for keep-together.within-line="always". | |||
</action> | |||
<action context="Code" dev="MM" type="fix"> |
@@ -26,7 +26,6 @@ import org.apache.fop.events.BasicEventTestCase; | |||
import org.apache.fop.pdf.PDFObjectTestCase; | |||
import org.apache.fop.traits.BorderPropsTestCase; | |||
import org.apache.fop.util.ColorUtilTestCase; | |||
import org.apache.fop.util.DataURIResolverTestCase; | |||
import org.apache.fop.util.ElementListUtilsTestCase; | |||
import org.apache.fop.util.PDFNumberTestCase; | |||
import org.apache.fop.util.XMLResourceBundleTestCase; | |||
@@ -49,7 +48,6 @@ public class UtilityCodeTestSuite { | |||
suite.addTest(new TestSuite(ColorUtilTestCase.class)); | |||
suite.addTest(new TestSuite(BorderPropsTestCase.class)); | |||
suite.addTest(new TestSuite(ElementListUtilsTestCase.class)); | |||
suite.addTest(new TestSuite(DataURIResolverTestCase.class)); | |||
suite.addTest(new TestSuite(BasicEventTestCase.class)); | |||
suite.addTest(new TestSuite(XMLResourceBundleTestCase.class)); | |||
//$JUnit-END$ |
@@ -34,6 +34,7 @@ import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.sax.SAXTransformerFactory; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.io.output.NullOutputStream; | |||
import org.apache.fop.apps.FOUserAgent; | |||
@@ -51,28 +52,48 @@ public class MemoryEater { | |||
private FopFactory fopFactory = FopFactory.newInstance(); | |||
private Templates replicatorTemplates; | |||
private Stats stats; | |||
public MemoryEater() throws TransformerConfigurationException, MalformedURLException { | |||
File xsltFile = new File("test/xsl/fo-replicator.xsl"); | |||
Source xslt = new StreamSource(xsltFile); | |||
replicatorTemplates = tFactory.newTemplates(xslt); | |||
} | |||
private void eatMemory(File foFile, int replicatorRepeats) throws Exception { | |||
private void eatMemory(File foFile, int runRepeats, int replicatorRepeats) throws Exception { | |||
stats = new Stats(); | |||
for (int i = 0; i < runRepeats; i++) { | |||
eatMemory(i, foFile, replicatorRepeats); | |||
stats.progress(i, runRepeats); | |||
} | |||
stats.dumpFinalStats(); | |||
System.out.println(stats.getGoogleChartURL()); | |||
} | |||
private void eatMemory(int callIndex, File foFile, int replicatorRepeats) throws Exception { | |||
Source src = new StreamSource(foFile); | |||
Transformer transformer = replicatorTemplates.newTransformer(); | |||
transformer.setParameter("repeats", new Integer(replicatorRepeats)); | |||
OutputStream out = new NullOutputStream(); //write to /dev/nul | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
userAgent.setBaseURL(foFile.getParentFile().toURL().toExternalForm()); | |||
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out); | |||
Result res = new SAXResult(fop.getDefaultHandler()); | |||
transformer.transform(src, res); | |||
try { | |||
FOUserAgent userAgent = fopFactory.newFOUserAgent(); | |||
userAgent.setBaseURL(foFile.getParentFile().toURL().toExternalForm()); | |||
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, out); | |||
Result res = new SAXResult(fop.getDefaultHandler()); | |||
System.out.println("Generated " + fop.getResults().getPageCount() + " pages."); | |||
transformer.transform(src, res); | |||
stats.notifyPagesProduced(fop.getResults().getPageCount()); | |||
if (callIndex == 0) { | |||
System.out.println(foFile.getName() + " generates " | |||
+ fop.getResults().getPageCount() + " pages."); | |||
} | |||
stats.checkStats(); | |||
} finally { | |||
IOUtils.closeQuietly(out); | |||
} | |||
} | |||
private static void prompt() throws IOException { | |||
@@ -108,9 +129,7 @@ public class MemoryEater { | |||
long start = System.currentTimeMillis(); | |||
MemoryEater app = new MemoryEater(); | |||
for (int i = 0; i < runRepeats; i++) { | |||
app.eatMemory(testFile, replicatorRepeats); | |||
} | |||
app.eatMemory(testFile, runRepeats, replicatorRepeats); | |||
long duration = System.currentTimeMillis() - start; | |||
System.out.println("Success! Job took " + duration + " ms"); |
@@ -0,0 +1,121 @@ | |||
/* | |||
* 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.memory; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
class Stats { | |||
private static final int INTERVAL = 2000; | |||
private long startTime = System.currentTimeMillis(); | |||
private long lastProgressDump = startTime; | |||
private int pagesProduced; | |||
private int totalPagesProduced; | |||
private int step; | |||
private int stepCount; | |||
private List samples = new java.util.LinkedList(); | |||
public void checkStats() { | |||
long now = System.currentTimeMillis(); | |||
if (now > lastProgressDump + INTERVAL) { | |||
dumpStats(); | |||
reset(); | |||
} | |||
} | |||
public void notifyPagesProduced(int count) { | |||
pagesProduced += count; | |||
totalPagesProduced += count; | |||
} | |||
public void reset() { | |||
pagesProduced = 0; | |||
lastProgressDump = System.currentTimeMillis(); | |||
} | |||
public void dumpStats() { | |||
long duration = System.currentTimeMillis() - lastProgressDump; | |||
if (stepCount != 0) { | |||
int progress = 100 * step / stepCount; | |||
System.out.println("Progress: " + progress + "%, " + (stepCount - step) + " left"); | |||
} | |||
long ppm = 60000 * pagesProduced / duration; | |||
System.out.println("Speed: " + ppm + "ppm"); | |||
samples.add(new Sample((int)ppm)); | |||
} | |||
public void dumpFinalStats() { | |||
long duration = System.currentTimeMillis() - startTime; | |||
System.out.println("Final statistics"); | |||
System.out.println("Pages produced: " +totalPagesProduced); | |||
long ppm = 60000 * totalPagesProduced / duration; | |||
System.out.println("Average speed: " + ppm + "ppm"); | |||
} | |||
public String getGoogleChartURL() { | |||
StringBuffer sb = new StringBuffer("http://chart.apis.google.com/chart?"); | |||
//http://chart.apis.google.com/chart?cht=ls&chd=t:60,40&chs=250x100&chl=Hello|World | |||
sb.append("cht=ls"); | |||
sb.append("&chd=t:"); | |||
boolean first = true; | |||
int maxY = 0; | |||
Iterator iter = samples.iterator(); | |||
while (iter.hasNext()) { | |||
Sample sample = (Sample)iter.next(); | |||
if (first) { | |||
first = false; | |||
} else { | |||
sb.append(','); | |||
} | |||
sb.append(sample.ppm); | |||
maxY = Math.max(maxY, sample.ppm); | |||
} | |||
int ceilY = ((maxY / 1000) + 1) * 1000; | |||
sb.append("&chs=1000x300"); //image size | |||
sb.append("&chds=0,").append(ceilY); //data scale | |||
sb.append("&chg=0,20"); //scale steps | |||
sb.append("&chxt=y"); | |||
sb.append("&chxl=0:|0|" + ceilY); | |||
return sb.toString(); | |||
} | |||
private static class Sample { | |||
private int ppm; | |||
public Sample(int ppm) { | |||
this.ppm = ppm; | |||
} | |||
} | |||
public void progress(int step, int stepCount) { | |||
this.step = step; | |||
this.stepCount = stepCount; | |||
} | |||
} |
@@ -1,116 +0,0 @@ | |||
/* | |||
* 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.util; | |||
import java.io.ByteArrayInputStream; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.URIResolver; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.apache.commons.io.IOUtils; | |||
import junit.framework.TestCase; | |||
/** | |||
* Test case for the RFC 2397 data URL/URI resolver. | |||
*/ | |||
public class DataURIResolverTestCase extends TestCase { | |||
private static final byte[] TESTDATA = new byte[] {0, 1, 2, 3, 4, 5}; | |||
/** | |||
* Tests DataURLUtil. | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testRFC2397Generator() throws Exception { | |||
String url = DataURLUtil.createDataURL(new ByteArrayInputStream(TESTDATA), null); | |||
assertEquals("Generated data URL is wrong", "data:;base64,AAECAwQF", url); | |||
url = DataURLUtil.createDataURL(new ByteArrayInputStream(TESTDATA), "application/pdf"); | |||
assertEquals("Generated data URL is wrong", "data:application/pdf;base64,AAECAwQF", url); | |||
} | |||
/** | |||
* Test the URIResolver contract if the protocol doesn't match. Resolver must return null | |||
* in this case. | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testNonMatchingContract() throws Exception { | |||
URIResolver resolver = new DataURIResolver(); | |||
Source src; | |||
src = resolver.resolve("http://xmlgraphics.apache.org/fop/index.html", null); | |||
assertNull(src); | |||
src = resolver.resolve("index.html", "http://xmlgraphics.apache.org/fop/"); | |||
assertNull(src); | |||
} | |||
private static boolean byteCmp(byte[] src, int srcOffset, byte[] cmp) { | |||
for (int i = 0, c = cmp.length; i < c; i++) { | |||
if (src[srcOffset + i] != cmp[i]) { | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* Test the DataURIResolver with correct values. | |||
* @throws Exception if an error occurs | |||
*/ | |||
public void testDataURLHandling() throws Exception { | |||
URIResolver resolver = new DataURIResolver(); | |||
Source src; | |||
src = resolver.resolve("data:;base64,AAECAwQF", null); | |||
assertNotNull(src); | |||
StreamSource streamSource = (StreamSource)src; | |||
byte[] data = IOUtils.toByteArray(streamSource.getInputStream()); | |||
assertTrue("Decoded data doesn't match the test data", byteCmp(TESTDATA, 0, data)); | |||
src = resolver.resolve( | |||
"data:application/octet-stream;interpreter=fop;base64,AAECAwQF", null); | |||
assertNotNull(src); | |||
streamSource = (StreamSource)src; | |||
assertNotNull(streamSource.getInputStream()); | |||
assertNull(streamSource.getReader()); | |||
data = IOUtils.toByteArray(streamSource.getInputStream()); | |||
assertTrue("Decoded data doesn't match the test data", byteCmp(TESTDATA, 0, data)); | |||
src = resolver.resolve("data:,FOP", null); | |||
assertNotNull(src); | |||
streamSource = (StreamSource)src; | |||
assertNull(streamSource.getInputStream()); | |||
assertNotNull(streamSource.getReader()); | |||
String text = IOUtils.toString(streamSource.getReader()); | |||
assertEquals("FOP", text); | |||
/* TODO Un-escaping of special URL chars like %20 hasn't been implemented, yet. | |||
src = resolver.resolve("data:,A%20brief%20note", null); | |||
assertNotNull(src); | |||
streamSource = (StreamSource)src; | |||
text = IOUtils.toString(streamSource.getReader()); | |||
assertEquals("A brief note", text); | |||
*/ | |||
} | |||
} |