001/* 002 * Copyright (c) 2003-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2018-05-25 18:38:49 +0000 (Fri, 25 May 2018) $' 007 * '$Revision: 34695 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.reporting.rio.fop; 031 032import java.awt.Component; 033import java.awt.Dimension; 034import java.io.BufferedOutputStream; 035import java.io.File; 036import java.io.FileInputStream; 037import java.io.FileOutputStream; 038import java.io.IOException; 039import java.io.InputStream; 040import java.io.OutputStream; 041import java.util.Iterator; 042 043import javax.imageio.ImageIO; 044import javax.imageio.ImageReader; 045import javax.imageio.spi.IIORegistry; 046import javax.swing.JFrame; 047import javax.xml.transform.Result; 048import javax.xml.transform.Source; 049import javax.xml.transform.Transformer; 050import javax.xml.transform.TransformerException; 051import javax.xml.transform.TransformerFactory; 052import javax.xml.transform.dom.DOMResult; 053import javax.xml.transform.sax.SAXResult; 054import javax.xml.transform.stream.StreamResult; 055import javax.xml.transform.stream.StreamSource; 056 057import org.apache.commons.logging.Log; 058import org.apache.commons.logging.LogFactory; 059import org.apache.fop.apps.FOPException; 060import org.apache.fop.apps.FOUserAgent; 061import org.apache.fop.apps.Fop; 062import org.apache.fop.apps.FopFactory; 063import org.apache.fop.apps.MimeConstants; 064import org.apache.fop.render.awt.AWTRenderer; 065import org.apache.fop.render.awt.viewer.PreviewPanel; 066import org.kepler.reporting.rio.ReportInstance; 067import org.kepler.reporting.rio.test.ReportTest; 068import org.kepler.reporting.roml.ReportLayout; 069 070/** 071 * This class converts a report object to XML, PDF, and AWT using JAXP (XSLT) 072 * and FOP (XSL:FO). 073 */ 074public class ReportRenderer { 075 076 private static final String DEFAULT_XSLT = "/xslt/rio2fo.xsl"; 077 078 public static Log log = LogFactory.getLog(ReportRenderer.class); 079 080 // configure fopFactory as desired 081 private static FopFactory fopFactory = FopFactory.newInstance(); 082 083 static { 084 reorderPNGReaders(); 085 } 086 087 public static void reorderPNGReaders() { 088 Iterator<ImageReader> imageIter = ImageIO.getImageReadersByMIMEType("image/png"); 089 090 log.debug("--------- IMAGE READERS BEFORE ----------"); 091 while (imageIter.hasNext()) { 092 ImageReader imageReader = imageIter.next(); 093 log.debug(imageReader); 094 } 095 096 /* com.sun.imageio.plugins.png.PNGImageReaderSpi.class no longer accessible in Java 9. 097 098 099 Class category = javax.imageio.spi.ImageReaderSpi.class; 100 101 Class firstProviderClass = com.sun.imageio.plugins.png.PNGImageReaderSpi.class; 102 Object firstProvider = IIORegistry.getDefaultInstance().getServiceProviderByClass(firstProviderClass); 103 104 Class secondProviderClass = com.sun.media.imageioimpl.plugins.png.CLibPNGImageReaderSpi.class; 105 Object secondProvider = IIORegistry.getDefaultInstance().getServiceProviderByClass(secondProviderClass); 106 107 if (firstProvider !=null && secondProvider != null) { 108 IIORegistry.getDefaultInstance().setOrdering(category, firstProvider, secondProvider); 109 } 110 */ 111 112 //AFTER 113 imageIter = ImageIO.getImageReadersByMIMEType("image/png"); 114 log.debug("--------- IMAGE READERS AFTER ----------"); 115 while (imageIter.hasNext()) { 116 ImageReader imageReader = imageIter.next(); 117 log.debug(imageReader); 118 } 119 120 } 121 122 /** 123 * Converts a Report object to a PDF file. 124 * 125 * @param report 126 * the Report object 127 * @param pdf 128 * the target PDF file 129 * @param xsltStream 130 * the stylesheet input stream 131 * @throws IOException 132 * In case of an I/O problem 133 * @throws FOPException 134 * In case of a FOP problem 135 * @throws TransformerException 136 * In case of a XSL transformation problem 137 */ 138 public static void convertReport2PDF(ReportInstance report, File pdf, InputStream xsltStream) 139 throws IOException, FOPException, TransformerException { 140 141 if (xsltStream == null) { 142 // look up the stylesheet for generating the PDF 143 xsltStream = report.getClass().getResourceAsStream(DEFAULT_XSLT); 144 } 145 146 FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); 147 // configure foUserAgent as desired 148 149 // Setup output 150 OutputStream out = new java.io.FileOutputStream(pdf); 151 out = new java.io.BufferedOutputStream(out); 152 try { 153 // Construct fop with desired output format 154 Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, 155 out); 156 157 // Setup XSLT 158 TransformerFactory factory = TransformerFactory.newInstance(); 159 Transformer transformer = factory.newTransformer(new StreamSource( 160 xsltStream)); 161 162 // Set the value of a <param> in the stylesheet 163 //TODO: this will be very useful, remember it! 164 //transformer.setParameter("myParamName", "myValue"); 165 166 // Setup input for XSLT transformation 167 Source src = ReportInputSource.getSourceForReport(report); 168 169 // Resulting SAX events (the generated FO) must be piped through to 170 // FOP 171 Result res = new SAXResult(fop.getDefaultHandler()); 172 173 // Start XSLT transformation and FOP processing 174 transformer.transform(src, res); 175 176 } finally { 177 out.close(); 178 } 179 } 180 181 182 public static ReportLayout convertXML2Report(File xml) throws IOException, 183 TransformerException { 184 // Setup input 185 Source src = new StreamSource(xml); 186 return convertXML2Report(src); 187 } 188 189 public static ReportLayout convertXML2Report(InputStream xml) throws IOException, 190 TransformerException { 191 // Setup input 192 Source src = new StreamSource(xml); 193 return convertXML2Report(src); 194 } 195 196 /** 197 * Converts a Report object to XML. 198 * 199 * @param report 200 * the Report object 201 * @param xml 202 * the target XML file 203 * @throws IOException 204 * In case of an I/O problem 205 * @throws TransformerException 206 * In case of a XSL transformation problem 207 * @throws ClassNotFoundException 208 * @throws IllegalAccessException 209 * @throws InstantiationException 210 */ 211 private static ReportLayout convertXML2Report(Source src) throws IOException, 212 TransformerException { 213 214 // Setup XSLT 215 TransformerFactory factory = TransformerFactory.newInstance(); 216 Transformer transformer = factory.newTransformer(); 217 /* 218 * Note: We use the identity transformer, no XSL transformation is done. 219 * The transformer is basically just used to deserialize the XML to objects 220 */ 221 222 // Setup output 223 DOMResult res = new DOMResult(); 224 225 // Start XSLT transformation 226 transformer.transform(src, res); 227 228 ReportLayout report = null; 229 try { 230 report = ReportParser.parse(res.getNode()); 231 } catch (Exception e) { 232 // TODO Auto-generated catch block 233 e.printStackTrace(); 234 } 235 236 return report; 237 } 238 239 public static void convertReport2XML(ReportLayout report, File xml) throws IOException, 240 TransformerException { 241 convertReport2XML(report, new FileOutputStream(xml)); 242 } 243 244 /** 245 * Converts a Report object to XML. 246 * 247 * @param report 248 * the Report object 249 * @param xml 250 * the target XML file 251 * @throws IOException 252 * In case of an I/O problem 253 * @throws TransformerException 254 * In case of a XSL transformation problem 255 */ 256 public static void convertReport2XML(ReportLayout report, OutputStream xml) throws IOException, 257 TransformerException { 258 259 // Setup XSLT 260 TransformerFactory factory = TransformerFactory.newInstance(); 261 Transformer transformer = factory.newTransformer(); 262 /* 263 * Note: We use the identity transformer, no XSL transformation is done. 264 * The transformer is basically just used to serialize the generated 265 * document to XML. 266 */ 267 268 // Setup input 269 Source src = ReportInputSource.getSourceForReport(report); 270 271 // Setup output 272 // Result res = new StreamResult(xml); 273 Result res = new StreamResult(new BufferedOutputStream(xml)); 274 275 // Start XSLT transformation 276 transformer.transform(src, res); 277 } 278 279 /** 280 * Converts an XML file to an XSL-FO file using JAXP (XSLT). 281 * 282 * @param xml 283 * the XML file 284 * @param xslt 285 * the stylesheet file 286 * @param fo 287 * the target XSL-FO file 288 * @throws IOException 289 * In case of an I/O problem 290 * @throws TransformerException 291 * In case of a XSL transformation problem 292 */ 293 public static void convertXML2FO(File xml, File xslt, File fo) throws IOException, 294 TransformerException { 295 296 // Setup output 297 OutputStream out = new java.io.FileOutputStream(fo); 298 try { 299 // Setup XSLT 300 TransformerFactory factory = TransformerFactory.newInstance(); 301 Transformer transformer = factory.newTransformer(new StreamSource( 302 xslt)); 303 304 // Setup input for XSLT transformation 305 Source src = new StreamSource(xml); 306 307 // Resulting SAX events to XML 308 Result res = new StreamResult(out); 309 310 // Start XSLT transformation and FOP processing 311 transformer.transform(src, res); 312 } finally { 313 out.close(); 314 } 315 } 316 317 public static void convertReport2FO(ReportInstance report, File xslt, File fo) throws IOException, TransformerException { 318 319 // Setup output 320 OutputStream out = new java.io.FileOutputStream(fo); 321 try { 322 // Setup XSLT 323 TransformerFactory factory = TransformerFactory.newInstance(); 324 Transformer transformer = factory.newTransformer(new StreamSource(xslt)); 325 326 // Setup input for XSLT transformation 327 Source src = ReportInputSource.getSourceForReport(report); 328 329 // Resulting SAX events to FO 330 Result res = new StreamResult(out); 331 332 // Start XSLT transformation and FOP processing 333 transformer.transform(src, res); 334 } finally { 335 out.close(); 336 } 337 } 338 339 /** 340 * Renders the Report object in the default FOP viewer. Not intended to be embedded. 341 * @deprecated 342 * @see convertReport2AWT() for an embedded soltion. 343 * 344 * @param report Report to render 345 * @param xslt the transform to use for rendering the Report 346 * @throws IOException 347 * @throws FOPException 348 * @throws TransformerException 349 */ 350 public void renderReportAsAWT(ReportInstance report, File xslt) 351 throws IOException, FOPException, TransformerException { 352 353 FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); 354 // configure foUserAgent as desired 355 356 // Construct fop with desired output format 357 Fop fop = fopFactory.newFop(MimeConstants.MIME_FOP_AWT_PREVIEW, foUserAgent); 358 359 // Setup XSLT 360 TransformerFactory factory = TransformerFactory.newInstance(); 361 Transformer transformer = factory.newTransformer(new StreamSource(xslt)); 362 363 // Setup input for XSLT transformation 364 Source src = ReportInputSource.getSourceForReport(report); 365 366 // Resulting SAX events (the generated FO) must be piped through to 367 // FOP 368 Result res = new SAXResult(fop.getDefaultHandler()); 369 370 // Start XSLT transformation and FOP processing 371 transformer.transform(src, res); 372 373 } 374 375 /** 376 * Used for embedding a viewer pane in swing applications 377 * @param report Report to render 378 * @param xslt transform to use for rendering Report 379 * @return PreviewPane component that can be added to any GUI 380 * @throws IOException 381 * @throws FOPException 382 * @throws TransformerException 383 */ 384 public static Component convertReport2AWT(ReportInstance report, InputStream xslt) 385 throws IOException, FOPException, TransformerException { 386 387 FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); 388 // configure foUserAgent as desired 389 390 AWTRenderer renderer = new AWTRenderer(); 391 foUserAgent.setRendererOverride(renderer); 392 renderer.setPreviewDialogDisplayed(false); 393 renderer.setUserAgent(foUserAgent); 394 renderer.clearViewportList(); 395 396 // Construct fop with no output format since we supply the renderer 397 Fop fop = fopFactory.newFop(foUserAgent); 398 399 // Setup XSLT 400 TransformerFactory factory = TransformerFactory.newInstance(); 401 Transformer transformer = factory.newTransformer(new StreamSource(xslt)); 402 403 // Setup input for XSLT transformation 404 Source src = ReportInputSource.getSourceForReport(report); 405 406 // Resulting SAX events (the generated FO) must be piped through to FOP 407 Result res = new SAXResult(fop.getDefaultHandler()); 408 409 // Start XSLT transformation and FOP processing 410 transformer.transform(src, res); 411 412 // construct the panel to render the processed FO 413 PreviewPanel previewPanel = new PreviewPanel(foUserAgent, null, renderer); 414 //double scale = previewPanel.getScaleToFitWindow(); 415 //previewPanel.setScaleFactor(scale); 416 previewPanel.setDisplayMode(PreviewPanel.CONTINUOUS); 417 418 return previewPanel; 419 } 420 421 /** 422 * Converts a Report object to a PDF file. 423 * 424 * @param report 425 * the Report object 426 * @param xslt 427 * the stylesheet file 428 * @param html 429 * the target HTML file 430 * @throws IOException 431 * In case of an I/O problem 432 * @throws FOPException 433 * In case of a FOP problem 434 * @throws TransformerException 435 * In case of a XSL transformation problem 436 */ 437 public static void convertReport2HTML(ReportInstance report, File xslt, File html) 438 throws IOException, TransformerException { 439 440 // Setup output 441 OutputStream out = new java.io.FileOutputStream(html); 442 out = new java.io.BufferedOutputStream(out); 443 try { 444 445 // Setup XSLT 446 TransformerFactory factory = TransformerFactory.newInstance(); 447 Transformer transformer = factory.newTransformer(new StreamSource(xslt)); 448 449 // Setup input for XSLT transformation 450 Source src = ReportInputSource.getSourceForReport(report); 451 452 // Resulting SAX events sent to HTML 453 Result res = new StreamResult(out); 454 455 // Start XSLT transformation 456 transformer.transform(src, res); 457 458 } finally { 459 out.close(); 460 } 461 } 462 463 private static void showPreviewPanel(Component previewPanel) { 464 465 //show the preview panel 466 JFrame frame = new JFrame("my frame"); 467 468 Dimension dim = new Dimension(612, 792); 469 frame.setPreferredSize(dim); 470 frame.setMaximumSize(dim); 471 frame.setMinimumSize(dim); 472 frame.setSize(dim); 473 474 frame.add(previewPanel); 475 476 frame.validate(); 477 frame.setVisible(true); 478 } 479 480 /** 481 * Main method. 482 * 483 * @param args 484 * command-line arguments 485 */ 486 public static void main(String[] args) { 487 try { 488 log.debug("FOP Conversion"); 489 log.debug("Preparing..."); 490 491 // Setup directories 492 File baseDir = new File("."); 493 File outDir = new File(baseDir, "out"); 494 outDir.mkdirs(); 495 496 // Setup input and output 497 File xsltfile = new File(baseDir, "lib/xslt/rio2fo.xsl"); 498 ///File xsltHTMLfile = new File(baseDir, "lib/xslt/rio2html.xsl"); 499 ///File xmlfile = new File(outDir, "Report2XML.xml"); 500 ///File htmlfile = new File(outDir, "Report2HTML.html"); 501 ///File fofile = new File(outDir, "Report2FO.fo"); 502 File pdffile = new File(outDir, "Report2PDF.pdf"); 503 504 log.debug("Input: a Report object"); 505 log.debug("Stylesheet: " + xsltfile); 506 log.debug("Output: PDF (" + pdffile + ")"); 507 log.debug("Transforming..."); 508 509 //ReportInstance report = ReportTest.makeReport(); 510 ReportLayout reportLayout = ReportTest.makeReportLayout(); 511 ReportInstance report = new ReportInstance(reportLayout); 512 // test that the copy constructor actually works 513 reportLayout.setTitle("BLAH!"); 514 reportLayout.getSections().clear(); 515// ReportRenderer.convertReport2XML(report, xmlfile); 516// ReportRenderer.convertReport2FO(report, xsltfile, fofile); 517// ReportConverter.convertXML2FO(xmlfile, xsltfile, fofile); 518// ReportRenderer.convertReport2PDF(report, pdffile, xsltfile); 519// ReportRenderer.convertReport2HTML(report, xsltHTMLfile, htmlfile); 520// ReportRenderer.convertXML2Report(xmlfile); 521 showPreviewPanel(ReportRenderer.convertReport2AWT(report, new FileInputStream(xsltfile))); 522 523 log.debug("Success!"); 524 } catch (Exception e) { 525 e.printStackTrace(System.err); 526 System.exit(-1); 527 } 528 } 529}