| 1 28 29 36 37 package net.sf.jasperreports.engine.export; 38 39 import java.awt.Color ; 40 import java.awt.Dimension ; 41 import java.awt.Rectangle ; 42 import java.awt.font.TextAttribute ; 43 import java.awt.geom.Dimension2D ; 44 import java.io.File ; 45 import java.io.FileOutputStream ; 46 import java.io.IOException ; 47 import java.io.OutputStream ; 48 import java.io.OutputStreamWriter ; 49 import java.io.StringWriter ; 50 import java.io.Writer ; 51 import java.text.AttributedCharacterIterator ; 52 import java.util.ArrayList ; 53 import java.util.HashMap ; 54 import java.util.Iterator ; 55 import java.util.LinkedList ; 56 import java.util.List ; 57 import java.util.Map ; 58 59 import net.sf.jasperreports.engine.JRAbstractExporter; 60 import net.sf.jasperreports.engine.JRAlignment; 61 import net.sf.jasperreports.engine.JRBox; 62 import net.sf.jasperreports.engine.JRElement; 63 import net.sf.jasperreports.engine.JRException; 64 import net.sf.jasperreports.engine.JRExporterParameter; 65 import net.sf.jasperreports.engine.JRGraphicElement; 66 import net.sf.jasperreports.engine.JRHyperlink; 67 import net.sf.jasperreports.engine.JRImage; 68 import net.sf.jasperreports.engine.JRImageMapRenderer; 69 import net.sf.jasperreports.engine.JRImageRenderer; 70 import net.sf.jasperreports.engine.JRPrintElement; 71 import net.sf.jasperreports.engine.JRPrintElementIndex; 72 import net.sf.jasperreports.engine.JRPrintEllipse; 73 import net.sf.jasperreports.engine.JRPrintFrame; 74 import net.sf.jasperreports.engine.JRPrintHyperlink; 75 import net.sf.jasperreports.engine.JRPrintImage; 76 import net.sf.jasperreports.engine.JRPrintImageArea; 77 import net.sf.jasperreports.engine.JRPrintImageAreaHyperlink; 78 import net.sf.jasperreports.engine.JRPrintLine; 79 import net.sf.jasperreports.engine.JRPrintPage; 80 import net.sf.jasperreports.engine.JRPrintRectangle; 81 import net.sf.jasperreports.engine.JRPrintText; 82 import net.sf.jasperreports.engine.JRRenderable; 83 import net.sf.jasperreports.engine.JRRuntimeException; 84 import net.sf.jasperreports.engine.JRTextElement; 85 import net.sf.jasperreports.engine.JRWrappingSvgRenderer; 86 import net.sf.jasperreports.engine.JasperPrint; 87 import net.sf.jasperreports.engine.util.JRStringUtil; 88 import net.sf.jasperreports.engine.util.JRStyledText; 89 import net.sf.jasperreports.engine.util.Pair; 90 91 92 102 public class JRHtmlExporter extends JRAbstractExporter 103 { 104 105 108 protected static final String JR_PAGE_ANCHOR_PREFIX = "JR_PAGE_ANCHOR_"; 109 110 113 protected static final String CSS_TEXT_ALIGN_LEFT = "left"; 114 protected static final String CSS_TEXT_ALIGN_RIGHT = "right"; 115 protected static final String CSS_TEXT_ALIGN_CENTER = "center"; 116 protected static final String CSS_TEXT_ALIGN_JUSTIFY = "justify"; 117 118 121 protected static final String HTML_VERTICAL_ALIGN_TOP = "top"; 122 protected static final String HTML_VERTICAL_ALIGN_MIDDLE = "middle"; 123 protected static final String HTML_VERTICAL_ALIGN_BOTTOM = "bottom"; 124 125 public static final String IMAGE_NAME_PREFIX = "img_"; 126 protected static final int IMAGE_NAME_PREFIX_LEGTH = IMAGE_NAME_PREFIX.length(); 127 128 131 protected Writer writer = null; 132 protected JRExportProgressMonitor progressMonitor = null; 133 protected Map rendererToImagePathMap = null; 134 protected Map imageMaps; 135 protected Map imageNameToImageDataMap = null; 136 protected List imagesToProcess = null; 137 protected boolean isPxImageLoaded = false; 138 139 protected int reportIndex = 0; 140 protected int pageIndex = 0; 141 142 145 protected File imagesDir = null; 146 protected String imagesURI = null; 147 protected boolean isOutputImagesToDir = false; 148 protected boolean isRemoveEmptySpace = false; 149 protected boolean isWhitePageBackground = true; 150 protected String encoding = null; 151 protected String sizeUnit = null; 152 153 156 protected String htmlHeader = null; 157 protected String betweenPagesHtml = null; 158 protected String htmlFooter = null; 159 160 protected StringProvider emptyCellStringProvider = null; 161 162 163 166 protected static final int colorMask = Integer.parseInt("FFFFFF", 16); 167 168 protected boolean isWrapBreakWord = false; 169 170 protected Map fontMap = null; 171 172 private LinkedList backcolorStack; 173 private Color backcolor; 174 175 protected JRHyperlinkProducerFactory hyperlinkProducerFactory; 176 177 178 public JRHtmlExporter() 179 { 180 backcolorStack = new LinkedList (); 181 backcolor = null; 182 } 183 184 185 188 public void exportReport() throws JRException 189 { 190 progressMonitor = (JRExportProgressMonitor)parameters.get(JRExporterParameter.PROGRESS_MONITOR); 191 192 193 setOffset(); 194 195 try 196 { 197 198 setExportContext(); 199 200 201 setInput(); 202 203 204 if (!isModeBatch) 205 { 206 setPageRange(); 207 } 208 209 htmlHeader = (String )parameters.get(JRHtmlExporterParameter.HTML_HEADER); 210 betweenPagesHtml = (String )parameters.get(JRHtmlExporterParameter.BETWEEN_PAGES_HTML); 211 htmlFooter = (String )parameters.get(JRHtmlExporterParameter.HTML_FOOTER); 212 213 imagesDir = (File )parameters.get(JRHtmlExporterParameter.IMAGES_DIR); 214 if (imagesDir == null) 215 { 216 String dir = (String )parameters.get(JRHtmlExporterParameter.IMAGES_DIR_NAME); 217 if (dir != null) 218 { 219 imagesDir = new File (dir); 220 } 221 } 222 223 Boolean isRemoveEmptySpaceParameter = (Boolean )parameters.get(JRHtmlExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS); 224 if (isRemoveEmptySpaceParameter != null) 225 { 226 isRemoveEmptySpace = isRemoveEmptySpaceParameter.booleanValue(); 227 } 228 229 Boolean isWhitePageBackgroundParameter = (Boolean )parameters.get(JRHtmlExporterParameter.IS_WHITE_PAGE_BACKGROUND); 230 if (isWhitePageBackgroundParameter != null) 231 { 232 isWhitePageBackground = isWhitePageBackgroundParameter.booleanValue(); 233 } 234 235 Boolean isOutputImagesToDirParameter = (Boolean )parameters.get(JRHtmlExporterParameter.IS_OUTPUT_IMAGES_TO_DIR); 236 if (isOutputImagesToDirParameter != null) 237 { 238 isOutputImagesToDir = isOutputImagesToDirParameter.booleanValue(); 239 } 240 241 String uri = (String )parameters.get(JRHtmlExporterParameter.IMAGES_URI); 242 if (uri != null) 243 { 244 imagesURI = uri; 245 } 246 247 encoding = (String )parameters.get(JRExporterParameter.CHARACTER_ENCODING); 248 if (encoding == null) 249 { 250 encoding = "UTF-8"; 251 } 252 253 rendererToImagePathMap = new HashMap (); 254 imageMaps = new HashMap (); 255 imagesToProcess = new ArrayList (); 256 isPxImageLoaded = false; 257 258 imageNameToImageDataMap = (Map )parameters.get(JRHtmlExporterParameter.IMAGES_MAP); 260 266 Boolean isWrapBreakWordParameter = (Boolean )parameters.get(JRHtmlExporterParameter.IS_WRAP_BREAK_WORD); 267 if (isWrapBreakWordParameter != null) 268 { 269 isWrapBreakWord = isWrapBreakWordParameter.booleanValue(); 270 } 271 272 sizeUnit = (String )parameters.get(JRHtmlExporterParameter.SIZE_UNIT); 273 if (sizeUnit == null) 274 { 275 sizeUnit = JRHtmlExporterParameter.SIZE_UNIT_PIXEL; 276 } 277 278 Boolean isUsingImagesToAlignParameter = (Boolean )parameters.get(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN); 279 if (isUsingImagesToAlignParameter == null) 280 { 281 isUsingImagesToAlignParameter = Boolean.TRUE; 282 } 283 284 if (isUsingImagesToAlignParameter.booleanValue()) 285 { 286 emptyCellStringProvider = 287 new StringProvider() 288 { 289 public String getStringForCollapsedTD(Object value, int width, int height, String sizeUnit) 290 { 291 return "><img alt=\"\" SRC=\"" + value + "px\" style=\"width: " + width + sizeUnit + "; height: " + height + sizeUnit + ";\"/>"; 292 } 293 public String getStringForEmptyTD(Object value) 294 { 295 return "<img alt=\"\" SRC=\"" + value + "px\" border=\"0\"/>"; 296 } 297 }; 298 299 loadPxImage(); 300 } 301 else 302 { 303 emptyCellStringProvider = 304 new StringProvider() 305 { 306 public String getStringForCollapsedTD(Object value, int width, int height, String sizeUnit) 307 { 308 return " style=\"width: " + width + sizeUnit + "; height: " + height + sizeUnit + ";\">"; 309 } 310 public String getStringForEmptyTD(Object value) 311 { 312 return ""; 313 } 314 }; 315 } 316 317 318 fontMap = (Map ) parameters.get(JRExporterParameter.FONT_MAP); 319 320 setHyperlinkProducerFactory(); 321 322 StringBuffer sb = (StringBuffer )parameters.get(JRExporterParameter.OUTPUT_STRING_BUFFER); 323 if (sb != null) 324 { 325 try 326 { 327 writer = new StringWriter (); 328 exportReportToWriter(); 329 sb.append(writer.toString()); 330 } 331 catch (IOException e) 332 { 333 throw new JRException("Error writing to StringBuffer writer : " + jasperPrint.getName(), e); 334 } 335 finally 336 { 337 if (writer != null) 338 { 339 try 340 { 341 writer.close(); 342 } 343 catch(IOException e) 344 { 345 } 346 } 347 } 348 } 349 else 350 { 351 writer = (Writer )parameters.get(JRExporterParameter.OUTPUT_WRITER); 352 if (writer != null) 353 { 354 try 355 { 356 exportReportToWriter(); 357 } 358 catch (IOException e) 359 { 360 throw new JRException("Error writing to writer : " + jasperPrint.getName(), e); 361 } 362 } 363 else 364 { 365 OutputStream os = (OutputStream )parameters.get(JRExporterParameter.OUTPUT_STREAM); 366 if (os != null) 367 { 368 try 369 { 370 writer = new OutputStreamWriter (os, encoding); 371 exportReportToWriter(); 372 } 373 catch (IOException e) 374 { 375 throw new JRException("Error writing to OutputStream writer : " + jasperPrint.getName(), e); 376 } 377 } 378 else 379 { 380 File destFile = (File )parameters.get(JRExporterParameter.OUTPUT_FILE); 381 if (destFile == null) 382 { 383 String fileName = (String )parameters.get(JRExporterParameter.OUTPUT_FILE_NAME); 384 if (fileName != null) 385 { 386 destFile = new File (fileName); 387 } 388 else 389 { 390 throw new JRException("No output specified for the exporter."); 391 } 392 } 393 394 try 395 { 396 os = new FileOutputStream (destFile); 397 writer = new OutputStreamWriter (os, encoding); 398 } 399 catch (IOException e) 400 { 401 throw new JRException("Error creating to file writer : " + jasperPrint.getName(), e); 402 } 403 404 if (imagesDir == null) 405 { 406 imagesDir = new File (destFile.getParent(), destFile.getName() + "_files"); 407 } 408 409 if (isOutputImagesToDirParameter == null) 410 { 411 isOutputImagesToDir = true; 412 } 413 414 if (imagesURI == null) 415 { 416 imagesURI = imagesDir.getName() + "/"; 417 } 418 419 try 420 { 421 exportReportToWriter(); 422 } 423 catch (IOException e) 424 { 425 throw new JRException("Error writing to file writer : " + jasperPrint.getName(), e); 426 } 427 finally 428 { 429 if (writer != null) 430 { 431 try 432 { 433 writer.close(); 434 } 435 catch(IOException e) 436 { 437 } 438 } 439 } 440 } 441 } 442 } 443 444 if (isOutputImagesToDir) 445 { 446 if (imagesDir == null) 447 { 448 throw new JRException("The images directory was not specified for the exporter."); 449 } 450 451 if (isPxImageLoaded || (imagesToProcess != null && imagesToProcess.size() > 0)) 452 { 453 if (!imagesDir.exists()) 454 { 455 imagesDir.mkdir(); 456 } 457 458 if (isPxImageLoaded) 459 { 460 JRRenderable pxRenderer = 461 JRImageRenderer.getInstance( 462 "net/sf/jasperreports/engine/images/pixel.GIF", 463 JRImage.ON_ERROR_TYPE_ERROR 464 ); 465 byte[] imageData = pxRenderer.getImageData(); 466 467 File imageFile = new File (imagesDir, "px"); 468 FileOutputStream fos = null; 469 470 try 471 { 472 fos = new FileOutputStream (imageFile); 473 fos.write(imageData, 0, imageData.length); 474 } 475 catch (IOException e) 476 { 477 throw new JRException("Error writing to image file : " + imageFile, e); 478 } 479 finally 480 { 481 if (fos != null) 482 { 483 try 484 { 485 fos.close(); 486 } 487 catch(IOException e) 488 { 489 } 490 } 491 } 492 } 493 494 for(Iterator it = imagesToProcess.iterator(); it.hasNext();) 495 { 496 JRPrintElementIndex imageIndex = (JRPrintElementIndex)it.next(); 497 498 JRPrintImage image = getImage(jasperPrintList, imageIndex); 499 JRRenderable renderer = image.getRenderer(); 500 if (renderer.getType() == JRRenderable.TYPE_SVG) 501 { 502 renderer = 503 new JRWrappingSvgRenderer( 504 renderer, 505 new Dimension (image.getWidth(), image.getHeight()), 506 JRElement.MODE_OPAQUE == image.getMode() ? image.getBackcolor() : null 507 ); 508 } 509 510 byte[] imageData = renderer.getImageData(); 511 512 File imageFile = new File (imagesDir, getImageName(imageIndex)); 513 FileOutputStream fos = null; 514 515 try 516 { 517 fos = new FileOutputStream (imageFile); 518 fos.write(imageData, 0, imageData.length); 519 } 520 catch (IOException e) 521 { 522 throw new JRException("Error writing to image file : " + imageFile, e); 523 } 524 finally 525 { 526 if (fos != null) 527 { 528 try 529 { 530 fos.close(); 531 } 532 catch(IOException e) 533 { 534 } 535 } 536 } 537 } 538 } 539 } 540 } 541 finally 542 { 543 resetExportContext(); 544 } 545 } 546 547 548 protected void setHyperlinkProducerFactory() 549 { 550 hyperlinkProducerFactory = (JRHyperlinkProducerFactory) parameters.get(JRHtmlExporterParameter.HYPERLINK_PRODUCER_FACTORY); 551 } 552 553 554 public static JRPrintImage getImage(List jasperPrintList, String imageName) 555 { 556 return getImage(jasperPrintList, getPrintElementIndex(imageName)); 557 } 558 559 560 public static JRPrintImage getImage(List jasperPrintList, JRPrintElementIndex imageIndex) 561 { 562 JasperPrint report = (JasperPrint)jasperPrintList.get(imageIndex.getReportIndex()); 563 JRPrintPage page = (JRPrintPage)report.getPages().get(imageIndex.getPageIndex()); 564 565 Integer [] elementIndexes = imageIndex.getElementIndexes(); 566 Object element = page.getElements().get(elementIndexes[0].intValue()); 567 568 for (int i = 1; i < elementIndexes.length; ++i) 569 { 570 JRPrintFrame frame = (JRPrintFrame) element; 571 element = frame.getElements().get(elementIndexes[i].intValue()); 572 } 573 574 return (JRPrintImage) element; 575 } 576 577 578 581 protected void exportReportToWriter() throws JRException, IOException  582 { 583 if (htmlHeader == null) 584 { 585 writer.write("<html>\n"); 589 writer.write("<head>\n"); 590 writer.write(" <title></title>\n"); 591 writer.write(" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=" + encoding + "\"/>\n"); 592 writer.write(" <style type=\"text/css\">\n"); 593 writer.write(" a {text-decoration: none}\n"); 594 writer.write(" </style>\n"); 595 writer.write("</head>\n"); 596 writer.write("<body text=\"#000000\" link=\"#000000\" alink=\"#000000\" vlink=\"#000000\">\n"); 597 writer.write("<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n"); 598 writer.write("<tr><td width=\"50%\"> </td><td align=\"center\">\n"); 599 writer.write("\n"); 600 } 601 else 602 { 603 writer.write(htmlHeader); 604 } 605 606 for(reportIndex = 0; reportIndex < jasperPrintList.size(); reportIndex++) 607 { 608 jasperPrint = (JasperPrint)jasperPrintList.get(reportIndex); 609 610 List pages = jasperPrint.getPages(); 611 if (pages != null && pages.size() > 0) 612 { 613 if (isModeBatch) 614 { 615 startPageIndex = 0; 616 endPageIndex = pages.size() - 1; 617 } 618 619 JRPrintPage page = null; 620 for(pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) 621 { 622 if (Thread.currentThread().isInterrupted()) 623 { 624 throw new JRException("Current thread interrupted."); 625 } 626 627 page = (JRPrintPage)pages.get(pageIndex); 628 629 writer.write("<a name=\"" + JR_PAGE_ANCHOR_PREFIX + reportIndex + "_" + (pageIndex + 1) + "\"/>\n"); 630 631 632 exportPage(page); 633
|