How to configure fonts from Java code in Apache FOP? - java

The link says that it is not "easily" possible to configure fonts from java code. How do I achieve this?
I'm having problems rendering certain HTMLs from international languages like French and Japanese.
WARNING: Font "Symbol,normal,700" not found. Substituting with "Symbol,normal,400".
May 08, 2015 4:45:39 PM org.apache.fop.events.LoggingEventListener processEvent
WARNING: Font "ZapfDingbats,normal,700" not found. Substituting with "ZapfDingbats,normal,400".
The PDF generated is damaged as a result.
update:
My Html contains French words like "Modifié Créée le Propriétaire"
File file = new File("C:\\Users\\me\\Desktop\\Test.html");
fopFactory = FopFactory.newInstance();
foUserAgent = fopFactory.newFOUserAgent();
String fileName = file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf("\\")+1,file.getAbsolutePath().lastIndexOf("."));
String workspacePath = file.getAbsolutePath().substring(0,file.getAbsolutePath().lastIndexOf("\\"));
File xsltfile = new File("xhtml2fo.xsl");
StreamSource source = null;
source = new StreamSource(file);
StreamSource transformSource = new StreamSource(xsltfile);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Transformer xslfoTransformer = null;
TransformerFactory fac = TransformerFactory.newInstance();
xslfoTransformer = fac.newTransformer(transformSource);
xslfoTransformer.setErrorListener(this);
Fop fop;
fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, outStream);
// Resulting SAX events (the generated FO)
Result res = new SAXResult(fop.getDefaultHandler());
xslfoTransformer.transform(source, res);
output = new File(workspacePath + File.separator + fileName + ".pdf");
OutputStream out = new java.io.FileOutputStream(output);
out = new java.io.BufferedOutputStream(out);
FileOutputStream str = new FileOutputStream(output);
str.write(outStream.toByteArray());
str.close();
I'm using an XSLT provided by Antennahouse to convert HTML tags to FO tags.

sample code.
/** The Constant FOP_CONFIG. */
private static final String FOP_CONFIG = "pdf.fop.cfg.xml";
fopFactory = FopFactory.newInstance();
// for image base URL
String serverPath = request.getSession().getServletContext().getRealPath("/");
//disable strict validatetion
fopFactory.setStrictValidation(false);
fopFactory.setBaseURL(serverPath);
// for fonts base URL
fopFactory.getFontManager().setFontBaseURL(serverPath);
// read custom font setting
StreamSource configSrc = new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(PDFComponentFactory.FOP_CONFIG));
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
Configuration cfg = cfgBuilder.build(configSrc.getInputStream());
fopFactory.setUserConfig(cfg);
Hope it may help you.

Related

How to render special characters during HTML to pdf conversion using iText & XMLWorker?

Hi i am using iText & XMLWorker for HTML to pdf Conversion (Java) as below
public void convertHtmlToPdf(StringBuilder content, String path) throws Exception {
String methodName = "convertHtmlToPdf";
try {
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontProvider.register("C:/Users/Aaryan/Downloads/arial.ttf");
final OutputStream file = new FileOutputStream(new File(path));
final Document document = new Document();
final PdfWriter writer = PdfWriter.getInstance(document, file);
document.open();
final TagProcessorFactory tagProcessorFactory = Tags.getHtmlTagProcessorFactory();
tagProcessorFactory.removeProcessor(HTML.Tag.IMG);
tagProcessorFactory.addProcessor(new ImageTagProcessor(), HTML.Tag.IMG);
final CssFilesImpl cssFiles = new CssFilesImpl();
cssFiles.add(XMLWorkerHelper.getInstance().getDefaultCSS());
final StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
final HtmlPipelineContext hpc = new HtmlPipelineContext(new CssAppliersImpl(fontProvider));
hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(tagProcessorFactory);
final HtmlPipeline htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(document, writer));
final Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
final XMLWorker worker = new XMLWorker(pipeline, true);
final Charset charset = Charset.forName("UTF-8");
final XMLParser xmlParser = new XMLParser(true, worker, charset);
InputStream is2 = new ByteArrayInputStream(content.toString().getBytes());
xmlParser.parse(is2, charset);
is2.close();
document.close();
file.close();
} catch (Exception ex) {
System.out.println("Exception in Class::" + className + "::Method::" + methodName + "::" + ex.getMessage());
ex.printStackTrace();
throw new Exception(ex);
}
}
PDFGeneration works Fine. The HTML content parsed for pdfConversion has special characters as appropiate entities as below
StringBuilder content = new StringBuilder();
content.append("<html><body style=\"font-size:12.0pt; font-family:Arial\">
<p>Testes → → Vasa efferentia → Kidney → Seminal Vescile</p></body></html>");
The Generated pdf displays '?' instead appropiate special characters (arrow symbols) . "Testes ?? Vasa efferentia ? Kidney ? Seminal Vescile ". Where am i going wrong. Please guide me on this.
The solution has almost nothing to do with the code/classes/objects...
You need to set the CSS "font-family" with something matching your requested output char-set
for example, if you have your special characters inside the 'p' html tag, then you can set the below style with desired font-family:
<HEAD>
<style>
p {
font-family: -good-font-family-
}
</style>
</HEAD>
This site might help you w3schools, but try to replace → with →

Generating PDF using fop and XSL when having URLS in XSLT

Generating PDF using fop and XSL when having URLS in XSLT
I am generating PDF using FOP 2.0 and XSLT. Here i am getting XSL from web url. my one XSL URL is including and importing other urls of XSLs. If its a single XSL I could able to generate PDF. If i have multiple URLS in one XSLT on Web . The FOP is not able to Connect automatically to other URLS[ Example of using XSLTS]
xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" \
xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
<xsl:include href="abc.xsl"/>
<xsl:include href="xyz.xsl"/>
<xsl:include href="wgh.xsl"/>
This is the way Its including XSLs in one XSLs. In this Case my FOP is not redirecting to those xsls and couldn't able to generate PDF
ERROR:
SystemId Unknown; Line #3; Column #34; Had IO Exception with stylesheet file: header.xsl
SystemId Unknown; Line #4; Column #34; Had IO Exception with stylesheet file: footer.xsl
SystemId Unknown; Line #5; Column #36; Had IO Exception with stylesheet file: mainbody.xsl
SystemId Unknown; Line #6; Column #41; Had IO Exception with stylesheet file: secondarybody.xsl
SystemId Unknown; Line #10; Column #38; org.xml.sax.SAXException: ElemTemplateElement error: layout
javax.xml.transform.TransformerException: ElemTemplateElement error: layout
13:58:27.326 [http-nio-auto-1-exec-2] DEBUG org.apache.fop.fo.FOTreeBuilder - Building formatting object tree
SystemId Unknown; Line #10; Column #38; Could not find template named: layout
Code for PDF Generator:
public class PdfGenerator {
private static final Logger LOG=LoggerFactory.getLogger(PdfGenerator.class);
public List<OutputStream> generatePdfs(List<Content> xmlList, int reqestListSize,String xslPath)
{
try {
List<OutputStream> pdfOutputStreams= new ArrayList();
for(int p = 0; p <reqestListSize; p++) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
String jaxbType = "com.abc.model"; // model package
JAXBContext context = JAXBContext.newInstance(jaxbType);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output",Boolean.TRUE);
marshaller.marshal(xmlList.get(p),bos);
ByteArrayInputStream inStream = new ByteArrayInputStream(bos.toByteArray());
StreamSource xmlSource = new StreamSource(inStream);
// create an instance of fop factory
FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
// a user agent is needed for transformation
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
ByteArrayOutputStream tempOutputStream = new ByteArrayOutputStream();
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, tempOutputStream);
pdfOutputStreams.add(p, tempOutputStream);
// Setup XSLT
TransformerFactory transformerFactory = TransformerFactory.newInstance();
URL url = new URL(xslPath);
InputStream xslFile = url.openStream(); ( **http://home.www.test.com/abc_web/xsl/test.xsl** ( Using an url to get XSLT. faild loading due to XSL :include) )
StreamSource xsltStreamSource = new StreamSource(xslFile);
Transformer transformer = transformerFactory.newTransformer(xsltStreamSource);
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);
}
return pdfOutputStreams;
}catch(Exception ex) {
LOG.error("Error", ex);
return new ArrayList();
}
Simply replace
URL url = new URL(xslPath);
InputStream xslFile = url.openStream();
StreamSource xsltStreamSource = new StreamSource(xslFile);
with
StreamSource xsltStreamSource = new StreamSource(xslPath);
and the XSLT processor should be able to resolve any relative imports or includes.
Or you would need to explicitly set the SystemId on your xsltStreamSource. But the single line I have suggested should do the job just fine.

Apache FOP Xml to PDF

I'm trying to transform XML financial data to PDF in Java using xslt and Apache FOP. But I'm getting following exception while transforming XML to PDF with created xsl-fo.
Caused by: org.xml.sax.SAXParseExceptionpublicId: -//W3C//DTD HTML 4.01 Transitional//EN; systemId: http://www.w3.org/TR/html4/loose.dtd; lineNumber: 31; columnNumber: 3; The declaration for the entity "HTML.Version" must end with '>'.
http://www.w3.org/TR/html4/loose.dtd is included in my xslt file. It has really that line without closing tag. I read on https://sourceforge.net/p/saxon/mailman/message/23058335/ that its SGML DTD. I can't transform this xslt to xsl-fo using Apache FOP, because underlying saxon can't parse sgml dtd?
Code for transform xslt to xsl-fo and then xsl-fo to PDF look like following. Could someone tell me, what I'm doing wrong? And how can I transform XML to PDF? Thanks in Advance.
private byte[] generateFOFromXML(Source xslt, Source invoice) throws TransformerException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
//Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(xslt);
//Setup input for XSLT transformation
//Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new StreamResult(out);
//Start XSLT transformation and FOP processing
transformer.transform(invoice, res);
return out.toByteArray();
} finally {
// try {
// out.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}
byte[] xslFO = generaterFOFromXML(xsltSource, invoiceSource);
FopFactoryBuilder builder = new FopFactoryBuilder(new File(".").toURI());
builder.setStrictFOValidation(false);
FopFactory fopFactory= builder.build();
// FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
ByteArrayOutputStream tempBAO = new ByteArrayOutputStream();
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, tempBAO);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setParameter("versionParam", "2.0");
Result result = new SAXResult(fop.getDefaultHandler());
Source foSource = new StreamSource(new ByteArrayInputStream(xslFO));
transformer.transform(foSource, result);

One FOP XSLT transformation but different files rendered

Is there any way to make only one xslt transformation and render the output to pdf, png, svg files?
StreamSource contentSource = new StreamSource(xmlContentStream);
StreamSource transformSource = new StreamSource(xslFoMarkupStream);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Transformer xslfoTransformer = getTransformer(transformSource);
Fop fop = fopFactory.newFop("application/pdf", foUserAgent, outStream);
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
xslfoTransformer.transform(contentSource, res);
xmlContentStream.close();
xslMarkupStream.close();
return outStream;
In the case above to generate PDF and then PNG I will have to create a new Fop instance with different mime type and then again call xslfoTransformer.transform().
That means that I will have the transformation twice, but I wonder if there is a way to run the transformation once and then render the output to different formats? (Custom Renderer?)
Or maybe there are any suggestions to speed up the rendering as I still need to do it several times - once for PDF, PNG, SVG.
I also tried to generate PDF via FOP and then convert it to image via Apache PdfBox. That works slightly faster, but looks silly.
Thank_you.
You can save one step. Your code does 2 steps above: take some arbitrary XML, transform that into XSL:FO using XSLT and then render the output into whatever format you want. You could do the transformation XML to XSL:FO (probably the slower part) once and use that result as input to 2 FO instances. Something like this:
public void fopReport(OutputStream pdfOut, OutputStream jpgOut, Source xmlSource, Source xsltSource) throws Exception {
// Create the FO content
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(xsltSource);
ByteArrayOutputStream foBytesStream = new ByteArrayOutputStream();
StreamResult foByteStreamResult = new StreamResult(foBytesStream);
transformer.transform(xmlSource, foByteStreamResult);
byte[] foBytes = foBytesStream.toByteArray();
// Render twice
FopFactory fopFactory = FopFactory.newInstance();
FOUserAgent uaPDF = fopFactory.newFOUserAgent();
FOUserAgent uaJpg = fopFactory.newFOUserAgent();
Fop fopPDF = fopFactory.newFop(MimeConstants.MIME_PDF, uaPDF, pdfOut);
Fop fopJpg = fopFactory.newFop(MimeConstants.MIME_JPEG, uaJpg, jpgOut);
//PDF
Source src = new StreamSource(new ByteArrayInputStream(foBytes));
Transformer resultTransformer = factory.newTransformer();
resultTransformer.transform(src, new SAXResult(fopPDF.getDefaultHandler()));
//JPF
src = new StreamSource(new ByteArrayInputStream(foBytes));
resultTransformer = factory.newTransformer();
resultTransformer.transform(src, new SAXResult(fopJpg.getDefaultHandler()));
}
Hope that helps

Saxon XSLT Transform to String Instead of File

In the Java code below, I am creating a *.html report by transforming generated xml data that is stored in a string,
combinedDDIString
... against an XSLT file,
reportXSLT
... and writing the result to a physical file,
tmpReportHTML.
The code then reads the file back into a string to use in other methods. I would like to avoid having to write the results to a file, just transform the results directly into a string.
Is there any way I can write the transform results to a string directly, and avoid writing the results out to a physical file?
String reportString = null;
FileInputStream stream = null;
ByteArrayOutputStream reportBAOS = new ByteArrayOutputStream();
try {
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
transformerFactory = TransformerFactory.newInstance();
transformer = transformerFactory.newTransformer(new StreamSource(reportXSLT));
transformer.setOutputProperty(OutputKeys.ENCODING, "US-ASCII");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
/*
* Create a new report file time-stamped for uniqueness, to avoid concurrency issues
*/
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
Date date = new Date();
File tmpReportHTML = new File(reportHTML + dateFormat.format(date) + ".html");
/*
* Perform the transform to get the report
*/
FileOutputStream reportFOS = new FileOutputStream(tmpReportHTML);
OutputStreamWriter osw = new OutputStreamWriter(reportFOS, "US-ASCII");//(reportBAOS), "US-ASCII");
transformer.transform(new StreamSource(new StringReader(combinedDDIString)), new StreamResult(osw));
osw.close();
/*
* Get the report as a string from the temp report file
*/
//FileInputStream stream = new FileInputStream(new File(REPORT_OUTPUT));
stream = new FileInputStream(tmpReportHTML); //(new File(reportXML));
FileChannel fc = stream.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
reportString = Charset.defaultCharset().decode(bb).toString();
/*
* Delete the temp report file
*/
tmpReportHTML.delete();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
finally {
stream.close();
Thanks in advance for the help.
Try using a StringWriter to create the StreamResult. (You should be able to obtain a String from the StringWriter simply using the toString method.)

Categories

Resources