使用 Apache FOP 时波兰语特殊字母不可用
Polish special letters not available while using Apache FOP
我一直在努力使用 FOP 生成带有波兰语字母的 PDF。我在这里阅读了很多关于 SO 的帖子,但到目前为止还没有成功!
这是我的模板:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:template match="root">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simpleA4" page-height="29.7cm" page-width="21cm" margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simpleA4">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="11pt" font-family='Arial'>
<xsl:value-of select="TestString"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
还有我的XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<TestString>Chcemy mieć pewność, że nasze produkty będą miały długą żywotność i stosujemy opakowania, aby uchronić je przed uszkodzeniem podczas przenoszenia i transportu.</TestString>
</root>
和我的 Java 调用它的代码:
private void PolishTest() throws IOException, FOPException, TransformerException {
// the XSL FO file
File xsltFile = new File("C:\Temp\PolishTest.xsl");
// the XML file which provides the input
StreamSource xmlSource = new StreamSource(new File("C:\Temp\PolishTest.xml"));
// create an instance of fop factory
FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
// a user agent is needed for transformation
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// Setup output
OutputStream out = new FileOutputStream("C:\Temp\PolishTest.pdf");
try {
// Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
// Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xsltFile));
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
// That's where the XML is first transformed to XSL-FO and then
// PDF is created
transformer.transform(xmlSource, res);
} finally {
out.close();
}
}
如我的模板所示,我使用 Arial 作为字体系列,如果我在 word 中键入文本,使用 Arial 效果非常好。但是当从 Java
调用它时
我收到很多警告:
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Font "Arial,normal,400" not found. Substituting with "any,normal,400".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ć" (0x107, cacute) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ś" (0x15b, sacute) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ż" (0x17c, zdot) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ę" (0x119, eogonek) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ą" (0x105, aogonek) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ł" (0x142, lslash) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
所以我的问题是(当然)我做错了什么?
为什么 FOP 选择 "Times-Roman",即使我已经指定了 Arial?更重要的是如何解决它?
** 更新 **
使用 am9417 的回答中的代码,我将 Java 代码更新为以下内容:
private static String config = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
"<fop>\n" +
" <renderers>\n" +
" <renderer mime=\"application/pdf\">\n" +
" <fonts>\n" +
" <auto-detect/>\n" +
" </fonts>\n" +
" </renderer>\n" +
" </renderers>\n" +
"</fop>";
private void PolishTest() throws IOException, SAXException, TransformerException {
// the XSL FO file
File xsltFile = new File("C:\Temp\PolishTest.xsl");
// the XML file which provides the input
StreamSource xmlSource = new StreamSource(new File("C:\Temp\PolishTest.xml"));
// create an instance of fop factory
URI uri = new File(".").toURI();
InputStream configSource = new ByteArrayInputStream(config.getBytes());
FopFactory fopFactory = FopFactory.newInstance(uri, configSource);
// a user agent is needed for transformation
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// Setup output
OutputStream out = new FileOutputStream("C:\Temp\PolishTest.pdf");
try {
// Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
// Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xsltFile));
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
// That's where the XML is first transformed to XSL-FO and then
// PDF is created
transformer.transform(xmlSource, res);
} finally {
out.close();
}
}
This answer 可能包含一些有用的信息。所有错误都是因为找不到 Arial 字体引起的,这就是为什么它切换到 Times-Roman 找不到特殊字符(由于某种原因)的原因。
因此,如该答案中所述,为 FOP 添加配置 xml,其中包含以下内容以引用您系统中的 Arial 字体:
C:\Temp\fopconf.xml
<?xml version="1.0" encoding="utf-8" ?>
<fop>
<renderers>
<renderer mime="application/pdf">
<fonts>
<font kerning="yes" embed-url="file:///C:/windows/fonts/arial.ttf">
<font-triplet name="Arial" style="normal" weight="normal"/>
</font>
</fonts>
</renderer>
</renderers>
</fop>
在具有 File
对象的 FopFactory 构造函数中添加对该配置文件的引用:
// create an instance of fop factory
FopFactory fopFactory = FopFactory.newInstance(new File("C:\Temp\fopconf.xml"));
现在文件应该呈现并且字体应该正确:
C:\Temp\PolishTest.pdf
编辑:
进一步测试后,我幸运地使用了 <auto-detect />
标签。但是,当它尝试搜索字体时,渲染会花费更多时间。如果您不知道字体文件位置,这可能会有用。您可能想尝试一下:
...
<fonts>
<auto-detect/>
</fonts>
...
我一直在努力使用 FOP 生成带有波兰语字母的 PDF。我在这里阅读了很多关于 SO 的帖子,但到目前为止还没有成功!
这是我的模板:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:template match="root">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simpleA4" page-height="29.7cm" page-width="21cm" margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simpleA4">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="11pt" font-family='Arial'>
<xsl:value-of select="TestString"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
还有我的XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<TestString>Chcemy mieć pewność, że nasze produkty będą miały długą żywotność i stosujemy opakowania, aby uchronić je przed uszkodzeniem podczas przenoszenia i transportu.</TestString>
</root>
和我的 Java 调用它的代码:
private void PolishTest() throws IOException, FOPException, TransformerException {
// the XSL FO file
File xsltFile = new File("C:\Temp\PolishTest.xsl");
// the XML file which provides the input
StreamSource xmlSource = new StreamSource(new File("C:\Temp\PolishTest.xml"));
// create an instance of fop factory
FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
// a user agent is needed for transformation
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// Setup output
OutputStream out = new FileOutputStream("C:\Temp\PolishTest.pdf");
try {
// Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
// Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xsltFile));
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
// That's where the XML is first transformed to XSL-FO and then
// PDF is created
transformer.transform(xmlSource, res);
} finally {
out.close();
}
}
如我的模板所示,我使用 Arial 作为字体系列,如果我在 word 中键入文本,使用 Arial 效果非常好。但是当从 Java
调用它时我收到很多警告:
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Font "Arial,normal,400" not found. Substituting with "any,normal,400".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ć" (0x107, cacute) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ś" (0x15b, sacute) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ż" (0x17c, zdot) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ę" (0x119, eogonek) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ą" (0x105, aogonek) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Glyph "ł" (0x142, lslash) not available in font "Times-Roman".
jul. 10, 2018 8:16:57 AM org.apache.fop.events.LoggingEventListener processEvent
所以我的问题是(当然)我做错了什么?
为什么 FOP 选择 "Times-Roman",即使我已经指定了 Arial?更重要的是如何解决它?
** 更新 **
使用 am9417 的回答中的代码,我将 Java 代码更新为以下内容:
private static String config = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
"<fop>\n" +
" <renderers>\n" +
" <renderer mime=\"application/pdf\">\n" +
" <fonts>\n" +
" <auto-detect/>\n" +
" </fonts>\n" +
" </renderer>\n" +
" </renderers>\n" +
"</fop>";
private void PolishTest() throws IOException, SAXException, TransformerException {
// the XSL FO file
File xsltFile = new File("C:\Temp\PolishTest.xsl");
// the XML file which provides the input
StreamSource xmlSource = new StreamSource(new File("C:\Temp\PolishTest.xml"));
// create an instance of fop factory
URI uri = new File(".").toURI();
InputStream configSource = new ByteArrayInputStream(config.getBytes());
FopFactory fopFactory = FopFactory.newInstance(uri, configSource);
// a user agent is needed for transformation
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// Setup output
OutputStream out = new FileOutputStream("C:\Temp\PolishTest.pdf");
try {
// Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
// Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xsltFile));
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
// That's where the XML is first transformed to XSL-FO and then
// PDF is created
transformer.transform(xmlSource, res);
} finally {
out.close();
}
}
This answer 可能包含一些有用的信息。所有错误都是因为找不到 Arial 字体引起的,这就是为什么它切换到 Times-Roman 找不到特殊字符(由于某种原因)的原因。
因此,如该答案中所述,为 FOP 添加配置 xml,其中包含以下内容以引用您系统中的 Arial 字体:
C:\Temp\fopconf.xml
<?xml version="1.0" encoding="utf-8" ?>
<fop>
<renderers>
<renderer mime="application/pdf">
<fonts>
<font kerning="yes" embed-url="file:///C:/windows/fonts/arial.ttf">
<font-triplet name="Arial" style="normal" weight="normal"/>
</font>
</fonts>
</renderer>
</renderers>
</fop>
在具有 File
对象的 FopFactory 构造函数中添加对该配置文件的引用:
// create an instance of fop factory
FopFactory fopFactory = FopFactory.newInstance(new File("C:\Temp\fopconf.xml"));
现在文件应该呈现并且字体应该正确:
C:\Temp\PolishTest.pdf
编辑:
进一步测试后,我幸运地使用了 <auto-detect />
标签。但是,当它尝试搜索字体时,渲染会花费更多时间。如果您不知道字体文件位置,这可能会有用。您可能想尝试一下:
...
<fonts>
<auto-detect/>
</fonts>
...