0001: /*
0002: * ============================================================================
0003: * GNU Lesser General Public License
0004: * ============================================================================
0005: *
0006: * JasperReports - Free Java report-generating library.
0007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
0008: *
0009: * This library is free software; you can redistribute it and/or
0010: * modify it under the terms of the GNU Lesser General Public
0011: * License as published by the Free Software Foundation; either
0012: * version 2.1 of the License, or (at your option) any later version.
0013: *
0014: * This library is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0017: * Lesser General Public License for more details.
0018: *
0019: * You should have received a copy of the GNU Lesser General Public
0020: * License along with this library; if not, write to the Free Software
0021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
0022: *
0023: * JasperSoft Corporation
0024: * 303 Second Street, Suite 450 North
0025: * San Francisco, CA 94107
0026: * http://www.jaspersoft.com
0027: */
0028:
0029: /*
0030: * Contributors:
0031: * Adrian Jackson - iapetus@users.sourceforge.net
0032: * David Taylor - exodussystems@users.sourceforge.net
0033: * Lars Kristensen - llk@users.sourceforge.net
0034: * Ling Li - lonecatz@users.sourceforge.net
0035: * Martin Clough - mtclough@users.sourceforge.net
0036: */
0037: package net.sf.jasperreports.engine.export;
0038:
0039: import java.awt.Color;
0040: import java.awt.Graphics2D;
0041: import java.awt.font.TextAttribute;
0042: import java.awt.geom.AffineTransform;
0043: import java.awt.geom.Dimension2D;
0044: import java.awt.geom.Rectangle2D;
0045: import java.awt.image.BufferedImage;
0046: import java.io.File;
0047: import java.io.FileOutputStream;
0048: import java.io.IOException;
0049: import java.io.OutputStream;
0050: import java.text.AttributedCharacterIterator;
0051: import java.util.Collection;
0052: import java.util.HashMap;
0053: import java.util.Iterator;
0054: import java.util.LinkedList;
0055: import java.util.List;
0056: import java.util.Map;
0057:
0058: import net.sf.jasperreports.engine.JRAbstractExporter;
0059: import net.sf.jasperreports.engine.JRAlignment;
0060: import net.sf.jasperreports.engine.JRAnchor;
0061: import net.sf.jasperreports.engine.JRBox;
0062: import net.sf.jasperreports.engine.JRElement;
0063: import net.sf.jasperreports.engine.JRException;
0064: import net.sf.jasperreports.engine.JRExporterParameter;
0065: import net.sf.jasperreports.engine.JRFont;
0066: import net.sf.jasperreports.engine.JRGraphicElement;
0067: import net.sf.jasperreports.engine.JRHyperlink;
0068: import net.sf.jasperreports.engine.JRImage;
0069: import net.sf.jasperreports.engine.JRImageRenderer;
0070: import net.sf.jasperreports.engine.JRLine;
0071: import net.sf.jasperreports.engine.JRPrintAnchor;
0072: import net.sf.jasperreports.engine.JRPrintElement;
0073: import net.sf.jasperreports.engine.JRPrintEllipse;
0074: import net.sf.jasperreports.engine.JRPrintFrame;
0075: import net.sf.jasperreports.engine.JRPrintGraphicElement;
0076: import net.sf.jasperreports.engine.JRPrintHyperlink;
0077: import net.sf.jasperreports.engine.JRPrintImage;
0078: import net.sf.jasperreports.engine.JRPrintLine;
0079: import net.sf.jasperreports.engine.JRPrintPage;
0080: import net.sf.jasperreports.engine.JRPrintRectangle;
0081: import net.sf.jasperreports.engine.JRPrintText;
0082: import net.sf.jasperreports.engine.JRRenderable;
0083: import net.sf.jasperreports.engine.JRRuntimeException;
0084: import net.sf.jasperreports.engine.JRTextElement;
0085: import net.sf.jasperreports.engine.JasperPrint;
0086: import net.sf.jasperreports.engine.base.JRBaseFont;
0087: import net.sf.jasperreports.engine.util.BreakIteratorSplitCharacter;
0088: import net.sf.jasperreports.engine.util.JRLoader;
0089: import net.sf.jasperreports.engine.util.JRProperties;
0090: import net.sf.jasperreports.engine.util.JRStyledText;
0091:
0092: import com.lowagie.text.Chunk;
0093: import com.lowagie.text.Document;
0094: import com.lowagie.text.DocumentException;
0095: import com.lowagie.text.Element;
0096: import com.lowagie.text.Font;
0097: import com.lowagie.text.FontFactory;
0098: import com.lowagie.text.Image;
0099: import com.lowagie.text.Phrase;
0100: import com.lowagie.text.Rectangle;
0101: import com.lowagie.text.SplitCharacter;
0102: import com.lowagie.text.pdf.BaseFont;
0103: import com.lowagie.text.pdf.ColumnText;
0104: import com.lowagie.text.pdf.FontMapper;
0105: import com.lowagie.text.pdf.PdfContentByte;
0106: import com.lowagie.text.pdf.PdfDestination;
0107: import com.lowagie.text.pdf.PdfOutline;
0108: import com.lowagie.text.pdf.PdfTemplate;
0109: import com.lowagie.text.pdf.PdfWriter;
0110:
0111: /**
0112: * Exports a JasperReports document to PDF format. It has binary output type and exports the document to
0113: * a free-form layout.
0114: * <p>
0115: * Since classic AWT fonts can be sometimes very different from PDF fonts, a font mapping feature was added.
0116: * By using the {@link JRExporterParameter#FONT_MAP} parameter, a logical font like "sansserif" can be mapped
0117: * to a system specific font, like "Helvetica-BoldOblique". PDF font mapping is a little more complicated, because
0118: * for a logical font, PDF cand provide two or more fonts, from the same family but with different styles (like
0119: * "Helvetica", "Helvetica-Bold", "Helvetica-BoldOblique"). So every key in the map is a simple bean containing
0120: * font family, bold and italic flag, and every value is another bean containing the PDF font name, encoding and
0121: * embedding flag.
0122: * @see FontKey
0123: * @see PdfFont
0124: * @author Teodor Danciu (teodord@users.sourceforge.net)
0125: * @version $Id: JRPdfExporter.java 1824 2007-08-23 14:19:12Z teodord $
0126: */
0127: public class JRPdfExporter extends JRAbstractExporter {
0128:
0129: /**
0130: * @deprecated Replaced by {@link JRPdfExporterParameter#PROPERTY_FORCE_SVG_SHAPES}.
0131: */
0132: public static final String PDF_FORCE_SVG_SHAPES = JRPdfExporterParameter.PROPERTY_FORCE_SVG_SHAPES;
0133:
0134: private static final String EMPTY_BOOKMARK_TITLE = "";
0135:
0136: /**
0137: *
0138: */
0139: protected static final String JR_PAGE_ANCHOR_PREFIX = "JR_PAGE_ANCHOR_";
0140:
0141: protected static boolean fontsRegistered = false;
0142:
0143: /**
0144: *
0145: */
0146: protected Document document = null;
0147: protected PdfContentByte pdfContentByte = null;
0148:
0149: protected Document imageTesterDocument = null;
0150: protected PdfContentByte imageTesterPdfContentByte = null;
0151:
0152: protected JRExportProgressMonitor progressMonitor = null;
0153:
0154: protected int reportIndex = 0;
0155:
0156: /**
0157: *
0158: */
0159: protected boolean forceSvgShapes;
0160: protected boolean isCreatingBatchModeBookmarks;
0161: protected boolean isCompressed;
0162: protected boolean isEncrypted;
0163: protected boolean is128BitKey;
0164: protected String userPassword;
0165: protected String ownerPassword;
0166: protected int permissions = 0;
0167: protected Character pdfVersion;
0168: protected String pdfJavaScript;
0169:
0170: /**
0171: *
0172: */
0173: protected Map loadedImagesMap = null;
0174: protected Image pxImage = null;
0175:
0176: private BookmarkStack bookmarkStack = null;
0177:
0178: private Map fontMap = null;
0179:
0180: private SplitCharacter splitCharacter;
0181: protected JRHyperlinkProducerFactory hyperlinkProducerFactory;
0182:
0183: /**
0184: *
0185: */
0186: protected Image getPxImage() {
0187: if (pxImage == null) {
0188: try {
0189: pxImage = Image
0190: .getInstance(JRLoader
0191: .loadBytesFromLocation(
0192: "net/sf/jasperreports/engine/images/pixel.GIF",
0193: null));
0194: } catch (Exception e) {
0195: throw new JRRuntimeException(e);
0196: }
0197: }
0198:
0199: return pxImage;
0200: }
0201:
0202: /**
0203: *
0204: */
0205: public void exportReport() throws JRException {
0206: registerFonts();
0207:
0208: progressMonitor = (JRExportProgressMonitor) parameters
0209: .get(JRExporterParameter.PROGRESS_MONITOR);
0210:
0211: /* */
0212: setOffset();
0213:
0214: try {
0215: /* */
0216: setExportContext();
0217:
0218: /* */
0219: setInput();
0220:
0221: /* */
0222: if (!isModeBatch) {
0223: setPageRange();
0224: }
0225:
0226: isCreatingBatchModeBookmarks = getBooleanParameter(
0227: JRPdfExporterParameter.IS_CREATING_BATCH_MODE_BOOKMARKS,
0228: JRPdfExporterParameter.PROPERTY_CREATE_BATCH_MODE_BOOKMARKS,
0229: false);
0230:
0231: forceSvgShapes = getBooleanParameter(
0232: JRPdfExporterParameter.FORCE_SVG_SHAPES,
0233: JRPdfExporterParameter.PROPERTY_FORCE_SVG_SHAPES,
0234: false);
0235:
0236: isCompressed = getBooleanParameter(
0237: JRPdfExporterParameter.IS_COMPRESSED,
0238: JRPdfExporterParameter.PROPERTY_COMPRESSED, false);
0239:
0240: isEncrypted = getBooleanParameter(
0241: JRPdfExporterParameter.IS_ENCRYPTED,
0242: JRPdfExporterParameter.PROPERTY_ENCRYPTED, false);
0243:
0244: is128BitKey = getBooleanParameter(
0245: JRPdfExporterParameter.IS_128_BIT_KEY,
0246: JRPdfExporterParameter.PROPERTY_128_BIT_KEY, false);
0247:
0248: userPassword = getStringParameter(
0249: JRPdfExporterParameter.USER_PASSWORD,
0250: JRPdfExporterParameter.PROPERTY_USER_PASSWORD);
0251:
0252: ownerPassword = getStringParameter(
0253: JRPdfExporterParameter.OWNER_PASSWORD,
0254: JRPdfExporterParameter.PROPERTY_OWNER_PASSWORD);
0255:
0256: Integer permissionsParameter = (Integer) parameters
0257: .get(JRPdfExporterParameter.PERMISSIONS);
0258: if (permissionsParameter != null) {
0259: permissions = permissionsParameter.intValue();
0260: }
0261:
0262: String strPdfVersion = getStringParameter(
0263: JRPdfExporterParameter.PDF_VERSION,
0264: JRPdfExporterParameter.PROPERTY_PDF_VERSION);
0265: pdfVersion = (strPdfVersion == null || strPdfVersion
0266: .length() == 0) ? null : new Character(
0267: strPdfVersion.charAt(0));
0268:
0269: fontMap = (Map) parameters
0270: .get(JRExporterParameter.FONT_MAP);
0271:
0272: setSplitCharacter();
0273: setHyperlinkProducerFactory();
0274:
0275: pdfJavaScript = getStringParameter(
0276: JRPdfExporterParameter.PDF_JAVASCRIPT,
0277: JRPdfExporterParameter.PROPERTY_PDF_JAVASCRIPT);
0278:
0279: OutputStream os = (OutputStream) parameters
0280: .get(JRExporterParameter.OUTPUT_STREAM);
0281: if (os != null) {
0282: exportReportToStream(os);
0283: } else {
0284: File destFile = (File) parameters
0285: .get(JRExporterParameter.OUTPUT_FILE);
0286: if (destFile == null) {
0287: String fileName = (String) parameters
0288: .get(JRExporterParameter.OUTPUT_FILE_NAME);
0289: if (fileName != null) {
0290: destFile = new File(fileName);
0291: } else {
0292: throw new JRException(
0293: "No output specified for the exporter.");
0294: }
0295: }
0296:
0297: try {
0298: os = new FileOutputStream(destFile);
0299: exportReportToStream(os);
0300: os.flush();
0301: } catch (IOException e) {
0302: throw new JRException(
0303: "Error trying to export to file : "
0304: + destFile, e);
0305: } finally {
0306: if (os != null) {
0307: try {
0308: os.close();
0309: } catch (IOException e) {
0310: }
0311: }
0312: }
0313: }
0314: } finally {
0315: resetExportContext();
0316: }
0317: }
0318:
0319: protected void setSplitCharacter() {
0320: boolean useFillSplitCharacter;
0321: Boolean useFillSplitCharacterParam = (Boolean) parameters
0322: .get(JRPdfExporterParameter.FORCE_LINEBREAK_POLICY);
0323: if (useFillSplitCharacterParam == null) {
0324: useFillSplitCharacter = JRProperties
0325: .getBooleanProperty(
0326: jasperPrint.getPropertiesMap(),
0327: JRPdfExporterParameter.PROPERTY_FORCE_LINEBREAK_POLICY,
0328: false);
0329: } else {
0330: useFillSplitCharacter = useFillSplitCharacterParam
0331: .booleanValue();
0332: }
0333:
0334: if (useFillSplitCharacter) {
0335: splitCharacter = new BreakIteratorSplitCharacter();
0336: }
0337: }
0338:
0339: protected void setHyperlinkProducerFactory() {
0340: hyperlinkProducerFactory = (JRHyperlinkProducerFactory) parameters
0341: .get(JRExporterParameter.HYPERLINK_PRODUCER_FACTORY);
0342: }
0343:
0344: /**
0345: *
0346: */
0347: protected void exportReportToStream(OutputStream os)
0348: throws JRException {
0349: //ByteArrayOutputStream baos = new ByteArrayOutputStream();
0350:
0351: document = new Document(new Rectangle(jasperPrint
0352: .getPageWidth(), jasperPrint.getPageHeight()));
0353:
0354: imageTesterDocument = new Document(new Rectangle(10, //jasperPrint.getPageWidth(),
0355: 10 //jasperPrint.getPageHeight()
0356: ));
0357:
0358: boolean closeDocuments = true;
0359: try {
0360: PdfWriter pdfWriter = PdfWriter.getInstance(document, os);
0361: pdfWriter.setCloseStream(false);
0362:
0363: if (pdfVersion != null)
0364: pdfWriter.setPdfVersion(pdfVersion.charValue());
0365:
0366: if (isCompressed)
0367: pdfWriter.setFullCompression();
0368:
0369: if (isEncrypted) {
0370: pdfWriter.setEncryption(is128BitKey, userPassword,
0371: ownerPassword, permissions);
0372: }
0373:
0374: // Add meta-data parameters to generated PDF document
0375: // mtclough@users.sourceforge.net 2005-12-05
0376: String title = (String) parameters
0377: .get(JRPdfExporterParameter.METADATA_TITLE);
0378: if (title != null)
0379: document.addTitle(title);
0380:
0381: String author = (String) parameters
0382: .get(JRPdfExporterParameter.METADATA_AUTHOR);
0383: if (author != null)
0384: document.addAuthor(author);
0385:
0386: String subject = (String) parameters
0387: .get(JRPdfExporterParameter.METADATA_SUBJECT);
0388: if (subject != null)
0389: document.addSubject(subject);
0390:
0391: String keywords = (String) parameters
0392: .get(JRPdfExporterParameter.METADATA_KEYWORDS);
0393: if (keywords != null)
0394: document.addKeywords(keywords);
0395:
0396: String creator = (String) parameters
0397: .get(JRPdfExporterParameter.METADATA_CREATOR);
0398: if (creator != null)
0399: document.addCreator(creator);
0400: else
0401: document.addCreator("JasperReports ("
0402: + jasperPrint.getName() + ")");
0403:
0404: document.open();
0405:
0406: if (pdfJavaScript != null)
0407: pdfWriter.addJavaScript(pdfJavaScript);
0408:
0409: pdfContentByte = pdfWriter.getDirectContent();
0410:
0411: initBookmarks();
0412:
0413: PdfWriter imageTesterPdfWriter = PdfWriter.getInstance(
0414: imageTesterDocument, new NullOutputStream() // discard the output
0415: );
0416: imageTesterDocument.open();
0417: imageTesterDocument.newPage();
0418: imageTesterPdfContentByte = imageTesterPdfWriter
0419: .getDirectContent();
0420: imageTesterPdfContentByte.setLiteral("\n");
0421:
0422: for (reportIndex = 0; reportIndex < jasperPrintList.size(); reportIndex++) {
0423: jasperPrint = (JasperPrint) jasperPrintList
0424: .get(reportIndex);
0425: loadedImagesMap = new HashMap();
0426: document.setPageSize(new Rectangle(jasperPrint
0427: .getPageWidth(), jasperPrint.getPageHeight()));
0428:
0429: List pages = jasperPrint.getPages();
0430: if (pages != null && pages.size() > 0) {
0431: if (isModeBatch) {
0432: document.newPage();
0433:
0434: if (isCreatingBatchModeBookmarks) {
0435: //add a new level to our outline for this report
0436: addBookmark(0, jasperPrint.getName(), 0, 0);
0437: }
0438:
0439: startPageIndex = 0;
0440: endPageIndex = pages.size() - 1;
0441: }
0442:
0443: Chunk chunk = null;
0444: ColumnText colText = null;
0445: JRPrintPage page = null;
0446: for (int pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) {
0447: if (Thread.currentThread().isInterrupted()) {
0448: throw new JRException(
0449: "Current thread interrupted.");
0450: }
0451:
0452: page = (JRPrintPage) pages.get(pageIndex);
0453:
0454: document.newPage();
0455:
0456: pdfContentByte = pdfWriter.getDirectContent();
0457:
0458: pdfContentByte.setLineCap(2);//PdfContentByte.LINE_CAP_PROJECTING_SQUARE since iText 1.02b
0459:
0460: chunk = new Chunk(" ");
0461: chunk.setLocalDestination(JR_PAGE_ANCHOR_PREFIX
0462: + reportIndex + "_" + (pageIndex + 1));
0463:
0464: colText = new ColumnText(pdfContentByte);
0465: colText.setSimpleColumn(new Phrase(chunk), 0,
0466: jasperPrint.getPageHeight(), 1, 1, 0,
0467: Element.ALIGN_LEFT);
0468:
0469: colText.go();
0470:
0471: /* */
0472: exportPage(page);
0473: }
0474: } else {
0475: document.newPage();
0476: pdfContentByte = pdfWriter.getDirectContent();
0477: pdfContentByte.setLiteral("\n");
0478: }
0479: }
0480:
0481: closeDocuments = false;
0482: document.close();
0483: imageTesterDocument.close();
0484: } catch (DocumentException e) {
0485: throw new JRException("PDF Document error : "
0486: + jasperPrint.getName(), e);
0487: } catch (IOException e) {
0488: throw new JRException("Error generating PDF report : "
0489: + jasperPrint.getName(), e);
0490: } finally {
0491: if (closeDocuments) //only on exception
0492: {
0493: try {
0494: document.close();
0495: } catch (Throwable e) {
0496: // ignore, let the original exception propagate
0497: }
0498:
0499: try {
0500: imageTesterDocument.close();
0501: } catch (Throwable e) {
0502: // ignore, let the original exception propagate
0503: }
0504: }
0505: }
0506:
0507: //return os.toByteArray();
0508: }
0509:
0510: /**
0511: *
0512: */
0513: protected void exportPage(JRPrintPage page) throws JRException,
0514: DocumentException, IOException {
0515: Collection elements = page.getElements();
0516: exportElements(elements);
0517:
0518: if (progressMonitor != null) {
0519: progressMonitor.afterPageExport();
0520: }
0521: }
0522:
0523: protected void exportElements(Collection elements)
0524: throws DocumentException, IOException, JRException {
0525: if (elements != null && elements.size() > 0) {
0526: JRPrintElement element;
0527: for (Iterator it = elements.iterator(); it.hasNext();) {
0528: element = (JRPrintElement) it.next();
0529:
0530: if (element instanceof JRPrintLine) {
0531: exportLine((JRPrintLine) element);
0532: } else if (element instanceof JRPrintRectangle) {
0533: exportRectangle((JRPrintRectangle) element);
0534: } else if (element instanceof JRPrintEllipse) {
0535: exportEllipse((JRPrintEllipse) element);
0536: } else if (element instanceof JRPrintImage) {
0537: exportImage((JRPrintImage) element);
0538: } else if (element instanceof JRPrintText) {
0539: exportText((JRPrintText) element);
0540: } else if (element instanceof JRPrintFrame) {
0541: exportFrame((JRPrintFrame) element);
0542: }
0543: }
0544: }
0545: }
0546:
0547: /**
0548: *
0549: */
0550: protected void exportLine(JRPrintLine line) {
0551: if (line.getPen() != JRGraphicElement.PEN_NONE) {
0552: pdfContentByte.setRGBColorStroke(line.getForecolor()
0553: .getRed(), line.getForecolor().getGreen(), line
0554: .getForecolor().getBlue());
0555:
0556: switch (line.getPen()) {
0557: case JRGraphicElement.PEN_DOTTED: {
0558: pdfContentByte.setLineWidth(1f);
0559: pdfContentByte.setLineDash(5f, 3f, 0f);
0560: break;
0561: }
0562: case JRGraphicElement.PEN_4_POINT: {
0563: pdfContentByte.setLineWidth(4f);
0564: pdfContentByte.setLineDash(0f);
0565: break;
0566: }
0567: case JRGraphicElement.PEN_2_POINT: {
0568: pdfContentByte.setLineWidth(2f);
0569: pdfContentByte.setLineDash(0f);
0570: break;
0571: }
0572: case JRGraphicElement.PEN_NONE: {
0573: //never reached due to the initial if statement
0574: break;
0575: }
0576: case JRGraphicElement.PEN_THIN: {
0577: pdfContentByte.setLineWidth(0.5f);
0578: pdfContentByte.setLineDash(0f);
0579: break;
0580: }
0581: case JRGraphicElement.PEN_1_POINT:
0582: default: {
0583: pdfContentByte.setLineWidth(1f);
0584: pdfContentByte.setLineDash(0f);
0585: break;
0586: }
0587: }
0588:
0589: if (line.getDirection() == JRLine.DIRECTION_TOP_DOWN) {
0590: pdfContentByte.moveTo(line.getX() + getOffsetX(),
0591: jasperPrint.getPageHeight() - line.getY()
0592: - getOffsetY());
0593: pdfContentByte.lineTo(line.getX() + getOffsetX()
0594: + line.getWidth() - 1, jasperPrint
0595: .getPageHeight()
0596: - line.getY()
0597: - getOffsetY()
0598: - line.getHeight()
0599: + 1);
0600: } else {
0601: pdfContentByte.moveTo(line.getX() + getOffsetX(),
0602: jasperPrint.getPageHeight() - line.getY()
0603: - getOffsetY() - line.getHeight() + 1);
0604: pdfContentByte.lineTo(line.getX() + getOffsetX()
0605: + line.getWidth() - 1, jasperPrint
0606: .getPageHeight()
0607: - line.getY() - getOffsetY());
0608: }
0609:
0610: pdfContentByte.stroke();
0611:
0612: pdfContentByte.setLineDash(0f);
0613: }
0614: }
0615:
0616: /**
0617: *
0618: */
0619: protected void exportRectangle(JRPrintRectangle rectangle) {
0620: pdfContentByte.setRGBColorStroke(rectangle.getForecolor()
0621: .getRed(), rectangle.getForecolor().getGreen(),
0622: rectangle.getForecolor().getBlue());
0623: pdfContentByte.setRGBColorFill(rectangle.getBackcolor()
0624: .getRed(), rectangle.getBackcolor().getGreen(),
0625: rectangle.getBackcolor().getBlue());
0626:
0627: float borderCorrection = prepareGraphicElement(rectangle);
0628:
0629: if (rectangle.getMode() == JRElement.MODE_OPAQUE) {
0630: pdfContentByte.roundRectangle(rectangle.getX()
0631: + getOffsetX() - borderCorrection, jasperPrint
0632: .getPageHeight()
0633: - rectangle.getY()
0634: - getOffsetY()
0635: - rectangle.getHeight() - borderCorrection + 1,
0636: rectangle.getWidth() + 2 * borderCorrection - 1,
0637: rectangle.getHeight() + 2 * borderCorrection - 1,
0638: rectangle.getRadius());
0639:
0640: if (rectangle.getPen() == JRGraphicElement.PEN_DOTTED) {
0641: pdfContentByte.fill();
0642:
0643: pdfContentByte.roundRectangle(rectangle.getX()
0644: + getOffsetX(), jasperPrint.getPageHeight()
0645: - rectangle.getY() - getOffsetY()
0646: - rectangle.getHeight() + 1, rectangle
0647: .getWidth() - 1, rectangle.getHeight() - 1,
0648: rectangle.getRadius());
0649: pdfContentByte.stroke();
0650: } else {
0651: pdfContentByte.fillStroke();
0652: }
0653: } else {
0654: if (rectangle.getPen() != JRGraphicElement.PEN_NONE) {
0655: pdfContentByte
0656: .roundRectangle(rectangle.getX() + getOffsetX()
0657: - borderCorrection, jasperPrint
0658: .getPageHeight()
0659: - rectangle.getY()
0660: - getOffsetY()
0661: - rectangle.getHeight()
0662: - borderCorrection + 1, rectangle
0663: .getWidth()
0664: + 2 * borderCorrection - 1, rectangle
0665: .getHeight()
0666: + 2 * borderCorrection - 1, rectangle
0667: .getRadius());
0668:
0669: pdfContentByte.stroke();
0670: }
0671: }
0672:
0673: pdfContentByte.setLineDash(0f);
0674: }
0675:
0676: protected float prepareGraphicElement(JRPrintGraphicElement element) {
0677: float borderCorrection = 0f;
0678:
0679: switch (element.getPen()) {
0680: case JRGraphicElement.PEN_DOTTED: {
0681: borderCorrection = element.getMode() == JRElement.MODE_OPAQUE ? 0.5f
0682: : 0f;
0683: pdfContentByte.setLineWidth(1f);
0684: pdfContentByte.setLineDash(5f, 3f, 0f);
0685: break;
0686: }
0687: case JRGraphicElement.PEN_4_POINT: {
0688: borderCorrection = 0.5f;
0689: pdfContentByte.setLineWidth(4f);
0690: pdfContentByte.setLineDash(0f);
0691: break;
0692: }
0693: case JRGraphicElement.PEN_2_POINT: {
0694: borderCorrection = 0.5f;
0695: pdfContentByte.setLineWidth(2f);
0696: pdfContentByte.setLineDash(0f);
0697: break;
0698: }
0699: case JRGraphicElement.PEN_THIN: {
0700: borderCorrection = 0.25f;
0701: pdfContentByte.setLineWidth(0.5f);
0702: pdfContentByte.setLineDash(0f);
0703: break;
0704: }
0705: case JRGraphicElement.PEN_NONE: {
0706: borderCorrection = 0.5f;
0707: pdfContentByte.setLineWidth(0f);
0708: pdfContentByte.setLineDash(0f);
0709:
0710: pdfContentByte.setRGBColorStroke(element.getBackcolor()
0711: .getRed(), element.getBackcolor().getGreen(),
0712: element.getBackcolor().getBlue());
0713:
0714: break;
0715: }
0716: case JRGraphicElement.PEN_1_POINT:
0717: default: {
0718: borderCorrection = 0f;
0719: pdfContentByte.setLineWidth(1f);
0720: pdfContentByte.setLineDash(0f);
0721: break;
0722: }
0723: }
0724: return borderCorrection;
0725: }
0726:
0727: /**
0728: *
0729: */
0730: protected void exportEllipse(JRPrintEllipse ellipse) {
0731: pdfContentByte.setRGBColorStroke(ellipse.getForecolor()
0732: .getRed(), ellipse.getForecolor().getGreen(), ellipse
0733: .getForecolor().getBlue());
0734: pdfContentByte.setRGBColorFill(ellipse.getBackcolor().getRed(),
0735: ellipse.getBackcolor().getGreen(), ellipse
0736: .getBackcolor().getBlue());
0737:
0738: float borderCorrection = prepareGraphicElement(ellipse);
0739:
0740: if (ellipse.getMode() == JRElement.MODE_OPAQUE) {
0741: pdfContentByte.ellipse(ellipse.getX() + getOffsetX()
0742: - borderCorrection, jasperPrint.getPageHeight()
0743: - ellipse.getY() - getOffsetY()
0744: - ellipse.getHeight() - borderCorrection + 1,
0745: ellipse.getX() + getOffsetX() + ellipse.getWidth()
0746: + borderCorrection - 1, jasperPrint
0747: .getPageHeight()
0748: - ellipse.getY()
0749: - getOffsetY()
0750: + borderCorrection);
0751:
0752: if (ellipse.getPen() == JRGraphicElement.PEN_DOTTED) {
0753: pdfContentByte.fill();
0754:
0755: pdfContentByte.ellipse(ellipse.getX() + getOffsetX(),
0756: jasperPrint.getPageHeight() - ellipse.getY()
0757: - getOffsetY() - ellipse.getHeight()
0758: + 1, ellipse.getX() + getOffsetX()
0759: + ellipse.getWidth() - 1, jasperPrint
0760: .getPageHeight()
0761: - ellipse.getY() - getOffsetY());
0762: pdfContentByte.stroke();
0763: } else {
0764: pdfContentByte.fillStroke();
0765: }
0766: } else {
0767: if (ellipse.getPen() != JRGraphicElement.PEN_NONE) {
0768: pdfContentByte.ellipse(ellipse.getX() + getOffsetX()
0769: - borderCorrection, jasperPrint.getPageHeight()
0770: - ellipse.getY() - getOffsetY()
0771: - ellipse.getHeight() - borderCorrection + 1,
0772: ellipse.getX() + getOffsetX()
0773: + ellipse.getWidth() + borderCorrection
0774: - 1, jasperPrint.getPageHeight()
0775: - ellipse.getY() - getOffsetY()
0776: + borderCorrection);
0777:
0778: pdfContentByte.stroke();
0779: }
0780: }
0781:
0782: pdfContentByte.setLineDash(0f);
0783: }
0784:
0785: /**
0786: *
0787: */
0788: protected void exportImage(JRPrintImage printImage)
0789: throws DocumentException, IOException, JRException {
0790: pdfContentByte.setRGBColorFill(printImage.getBackcolor()
0791: .getRed(), printImage.getBackcolor().getGreen(),
0792: printImage.getBackcolor().getBlue());
0793:
0794: if (printImage.getMode() == JRElement.MODE_OPAQUE) {
0795: float borderCorrection = .5f;
0796:
0797: pdfContentByte.setRGBColorStroke(printImage.getBackcolor()
0798: .getRed(), printImage.getBackcolor().getGreen(),
0799: printImage.getBackcolor().getBlue());
0800: pdfContentByte.setLineWidth(0.1f);
0801: pdfContentByte.setLineDash(0f);
0802: pdfContentByte.rectangle(printImage.getX() + getOffsetX()
0803: - borderCorrection, jasperPrint.getPageHeight()
0804: - printImage.getY() - getOffsetY()
0805: + borderCorrection, printImage.getWidth() + 2
0806: * borderCorrection - 1, -printImage.getHeight() - 2
0807: * borderCorrection + 1);
0808: pdfContentByte.fillStroke();
0809: }
0810:
0811: int topPadding = printImage.getTopPadding();
0812: int leftPadding = printImage.getLeftPadding();
0813: int bottomPadding = printImage.getBottomPadding();
0814: int rightPadding = printImage.getRightPadding();
0815:
0816: int availableImageWidth = printImage.getWidth() - leftPadding
0817: - rightPadding;
0818: availableImageWidth = (availableImageWidth < 0) ? 0
0819: : availableImageWidth;
0820:
0821: int availableImageHeight = printImage.getHeight() - topPadding
0822: - bottomPadding;
0823: availableImageHeight = (availableImageHeight < 0) ? 0
0824: : availableImageHeight;
0825:
0826: JRRenderable renderer = printImage.getRenderer();
0827:
0828: if (renderer != null && availableImageWidth > 0
0829: && availableImageHeight > 0) {
0830: if (renderer.getType() == JRRenderable.TYPE_IMAGE) {
0831: // Image renderers are all asked for their image data at some point.
0832: // Better to test and replace the renderer now, in case of lazy load error.
0833: renderer = JRImageRenderer
0834: .getOnErrorRendererForImageData(renderer,
0835: printImage.getOnErrorType());
0836: }
0837: } else {
0838: renderer = null;
0839: }
0840:
0841: if (renderer != null) {
0842: int xoffset = 0;
0843: int yoffset = 0;
0844:
0845: Chunk chunk = null;
0846:
0847: float scaledWidth = availableImageWidth;
0848: float scaledHeight = availableImageHeight;
0849:
0850: if (renderer.getType() == JRRenderable.TYPE_IMAGE) {
0851: com.lowagie.text.Image image = null;
0852:
0853: float xalignFactor = getXAlignFactor(printImage);
0854: float yalignFactor = getYAlignFactor(printImage);
0855:
0856: switch (printImage.getScaleImage()) {
0857: case JRImage.SCALE_IMAGE_CLIP: {
0858: // Image load might fail, from given image data.
0859: // Better to test and replace the renderer now, in case of lazy load error.
0860: renderer = JRImageRenderer
0861: .getOnErrorRendererForDimension(renderer,
0862: printImage.getOnErrorType());
0863: if (renderer == null) {
0864: break;
0865: }
0866:
0867: int normalWidth = availableImageWidth;
0868: int normalHeight = availableImageHeight;
0869:
0870: Dimension2D dimension = renderer.getDimension();
0871: if (dimension != null) {
0872: normalWidth = (int) dimension.getWidth();
0873: normalHeight = (int) dimension.getHeight();
0874: }
0875:
0876: xoffset = (int) (xalignFactor * (availableImageWidth - normalWidth));
0877: yoffset = (int) (yalignFactor * (availableImageHeight - normalHeight));
0878:
0879: int minWidth = Math.min(normalWidth,
0880: availableImageWidth);
0881: int minHeight = Math.min(normalHeight,
0882: availableImageHeight);
0883:
0884: BufferedImage bi = new BufferedImage(minWidth,
0885: minHeight, BufferedImage.TYPE_INT_ARGB);
0886:
0887: Graphics2D g = bi.createGraphics();
0888: if (printImage.getMode() == JRElement.MODE_OPAQUE) {
0889: g.setColor(printImage.getBackcolor());
0890: g.fillRect(0, 0, minWidth, minHeight);
0891: }
0892: renderer.render(g, new java.awt.Rectangle(
0893: (xoffset > 0 ? 0 : xoffset),
0894: (yoffset > 0 ? 0 : yoffset), normalWidth,
0895: normalHeight));
0896: g.dispose();
0897:
0898: xoffset = (xoffset < 0 ? 0 : xoffset);
0899: yoffset = (yoffset < 0 ? 0 : yoffset);
0900:
0901: //awtImage = bi.getSubimage(0, 0, minWidth, minHeight);
0902:
0903: //image = com.lowagie.text.Image.getInstance(awtImage, printImage.getBackcolor());
0904: image = com.lowagie.text.Image
0905: .getInstance(bi, null);
0906:
0907: break;
0908: }
0909: case JRImage.SCALE_IMAGE_FILL_FRAME: {
0910: if (printImage.isUsingCache()
0911: && loadedImagesMap.containsKey(renderer)) {
0912: image = (com.lowagie.text.Image) loadedImagesMap
0913: .get(renderer);
0914: } else {
0915: try {
0916: image = com.lowagie.text.Image
0917: .getInstance(renderer
0918: .getImageData());
0919: imageTesterPdfContentByte.addImage(image,
0920: 10, 0, 0, 10, 0, 0);
0921: } catch (Exception e) {
0922: JRImageRenderer tmpRenderer = JRImageRenderer
0923: .getOnErrorRendererForImage(
0924: JRImageRenderer
0925: .getInstance(renderer
0926: .getImageData()),
0927: printImage.getOnErrorType());
0928: if (tmpRenderer == null) {
0929: break;
0930: }
0931: java.awt.Image awtImage = tmpRenderer
0932: .getImage();
0933: image = com.lowagie.text.Image.getInstance(
0934: awtImage, null);
0935: }
0936:
0937: if (printImage.isUsingCache()) {
0938: loadedImagesMap.put(renderer, image);
0939: }
0940: }
0941:
0942: image.scaleAbsolute(availableImageWidth,
0943: availableImageHeight);
0944: break;
0945: }
0946: case JRImage.SCALE_IMAGE_RETAIN_SHAPE:
0947: default: {
0948: if (printImage.isUsingCache()
0949: && loadedImagesMap.containsKey(renderer)) {
0950: image = (com.lowagie.text.Image) loadedImagesMap
0951: .get(renderer);
0952: } else {
0953: try {
0954: image = com.lowagie.text.Image
0955: .getInstance(renderer
0956: .getImageData());
0957: imageTesterPdfContentByte.addImage(image,
0958: 10, 0, 0, 10, 0, 0);
0959: } catch (Exception e) {
0960: JRImageRenderer tmpRenderer = JRImageRenderer
0961: .getOnErrorRendererForImage(
0962: JRImageRenderer
0963: .getInstance(renderer
0964: .getImageData()),
0965: printImage.getOnErrorType());
0966: if (tmpRenderer == null) {
0967: break;
0968: }
0969: java.awt.Image awtImage = tmpRenderer
0970: .getImage();
0971: image = com.lowagie.text.Image.getInstance(
0972: awtImage, null);
0973: }
0974:
0975: if (printImage.isUsingCache()) {
0976: loadedImagesMap.put(renderer, image);
0977: }
0978: }
0979:
0980: image.scaleToFit(availableImageWidth,
0981: availableImageHeight);
0982:
0983: xoffset = (int) (xalignFactor * (availableImageWidth - image
0984: .plainWidth()));
0985: yoffset = (int) (yalignFactor * (availableImageHeight - image
0986: .plainHeight()));
0987:
0988: xoffset = (xoffset < 0 ? 0 : xoffset);
0989: yoffset = (yoffset < 0 ? 0 : yoffset);
0990:
0991: break;
0992: }
0993: }
0994:
0995: if (image != null) {
0996: chunk = new Chunk(image, -0.5f, 0.5f);
0997:
0998: scaledWidth = image.scaledWidth();
0999: scaledHeight = image.scaledHeight();
1000: }
1001: } else {
1002: double normalWidth = availableImageWidth;
1003: double normalHeight = availableImageHeight;
1004:
1005: Dimension2D dimension = renderer.getDimension();
1006: if (dimension != null) {
1007: float xalignFactor = getXAlignFactor(printImage);
1008: float yalignFactor = getYAlignFactor(printImage);
1009:
1010: switch (printImage.getScaleImage()) {
1011: case JRImage.SCALE_IMAGE_CLIP: {
1012: normalWidth = dimension.getWidth();
1013: normalHeight = dimension.getHeight();
1014: xoffset = (int) (xalignFactor * (availableImageWidth - normalWidth));
1015: yoffset = (int) (yalignFactor * (availableImageHeight - normalHeight));
1016: break;
1017: }
1018: case JRImage.SCALE_IMAGE_FILL_FRAME: {
1019: xoffset = 0;
1020: yoffset = 0;
1021: break;
1022: }
1023: case JRImage.SCALE_IMAGE_RETAIN_SHAPE:
1024: default: {
1025: normalWidth = dimension.getWidth();
1026: normalHeight = dimension.getHeight();
1027: double ratioX = availableImageWidth
1028: / normalWidth;
1029: double ratioY = availableImageHeight
1030: / normalHeight;
1031: double ratio = ratioX < ratioY ? ratioX
1032: : ratioY;
1033: normalWidth *= ratio;
1034: normalHeight *= ratio;
1035: xoffset = (int) (xalignFactor * (availableImageWidth - normalWidth));
1036: yoffset = (int) (yalignFactor * (availableImageHeight - normalHeight));
1037: break;
1038: }
1039: }
1040: }
1041:
1042: PdfTemplate template = pdfContentByte.createTemplate(
1043: availableImageWidth, availableImageHeight);
1044:
1045: Graphics2D g = forceSvgShapes ? template
1046: .createGraphicsShapes(availableImageWidth,
1047: availableImageHeight) : template
1048: .createGraphics(availableImageWidth,
1049: availableImageHeight,
1050: new LocalFontMapper());
1051:
1052: if (printImage.getMode() == JRElement.MODE_OPAQUE) {
1053: g.setColor(printImage.getBackcolor());
1054: g
1055: .fillRect(
1056: 0,
1057: 0,
1058: normalWidth <= availableImageWidth ? (int) normalWidth
1059: : availableImageWidth,
1060: normalHeight <= availableImageHeight ? (int) normalHeight
1061: : availableImageHeight);
1062: }
1063:
1064: Rectangle2D rectangle = new Rectangle2D.Double(
1065: (xoffset > 0 ? 0 : xoffset), (yoffset > 0 ? 0
1066: : yoffset), normalWidth, normalHeight);
1067:
1068: renderer.render(g, rectangle);
1069: g.dispose();
1070:
1071: xoffset = (xoffset < 0 ? 0 : xoffset);
1072: yoffset = (yoffset < 0 ? 0 : yoffset);
1073:
1074: pdfContentByte.saveState();
1075: pdfContentByte.addTemplate(template, printImage.getX()
1076: + getOffsetX() + xoffset, jasperPrint
1077: .getPageHeight()
1078: - printImage.getY()
1079: - getOffsetY()
1080: - availableImageHeight - yoffset);
1081: pdfContentByte.restoreState();
1082:
1083: Image image = getPxImage();
1084: image.scaleAbsolute(availableImageWidth,
1085: availableImageHeight);
1086: chunk = new Chunk(image, 0, 0);
1087: }
1088:
1089: /*
1090: image.setAbsolutePosition(
1091: printImage.getX() + offsetX + borderOffset,
1092: jasperPrint.getPageHeight() - printImage.getY() - offsetY - image.scaledHeight() - borderOffset
1093: );
1094:
1095: pdfContentByte.addImage(image);
1096: */
1097:
1098: if (chunk != null) {
1099: setAnchor(chunk, printImage, printImage);
1100: setHyperlinkInfo(chunk, printImage);
1101:
1102: ColumnText colText = new ColumnText(pdfContentByte);
1103: int upperY = jasperPrint.getPageHeight()
1104: - printImage.getY() - topPadding - getOffsetY()
1105: - yoffset;
1106: int lowerX = printImage.getX() + leftPadding
1107: + getOffsetX() + xoffset;
1108: colText.setSimpleColumn(new Phrase(chunk), lowerX,
1109: upperY - scaledHeight, lowerX + scaledWidth,
1110: upperY, scaledHeight, Element.ALIGN_LEFT);
1111:
1112: colText.go();
1113: }
1114: }
1115:
1116: if (printImage.getTopBorder() == JRGraphicElement.PEN_NONE
1117: && printImage.getLeftBorder() == JRGraphicElement.PEN_NONE
1118: && printImage.getBottomBorder() == JRGraphicElement.PEN_NONE
1119: && printImage.getRightBorder() == JRGraphicElement.PEN_NONE) {
1120: if (printImage.getPen() != JRGraphicElement.PEN_NONE) {
1121: exportBox(getBox(printImage), printImage);
1122: }
1123: } else {
1124: /* */
1125: exportBox(printImage, printImage);
1126: }
1127: }
1128:
1129: private float getXAlignFactor(JRPrintImage printImage) {
1130: float xalignFactor = 0f;
1131: switch (printImage.getHorizontalAlignment()) {
1132: case JRAlignment.HORIZONTAL_ALIGN_RIGHT: {
1133: xalignFactor = 1f;
1134: break;
1135: }
1136: case JRAlignment.HORIZONTAL_ALIGN_CENTER: {
1137: xalignFactor = 0.5f;
1138: break;
1139: }
1140: case JRAlignment.HORIZONTAL_ALIGN_LEFT:
1141: default: {
1142: xalignFactor = 0f;
1143: break;
1144: }
1145: }
1146: return xalignFactor;
1147: }
1148:
1149: private float getYAlignFactor(JRPrintImage printImage) {
1150: float yalignFactor = 0f;
1151: switch (printImage.getVerticalAlignment()) {
1152: case JRAlignment.VERTICAL_ALIGN_BOTTOM: {
1153: yalignFactor = 1f;
1154: break;
1155: }
1156: case JRAlignment.VERTICAL_ALIGN_MIDDLE: {
1157: yalignFactor = 0.5f;
1158: break;
1159: }
1160: case JRAlignment.VERTICAL_ALIGN_TOP:
1161: default: {
1162: yalignFactor = 0f;
1163: break;
1164: }
1165: }
1166: return yalignFactor;
1167: }
1168:
1169: /**
1170: *
1171: */
1172: protected void setHyperlinkInfo(Chunk chunk, JRPrintHyperlink link) {
1173: switch (link.getHyperlinkType()) {
1174: case JRHyperlink.HYPERLINK_TYPE_REFERENCE: {
1175: if (link.getHyperlinkReference() != null) {
1176: chunk.setAnchor(link.getHyperlinkReference());
1177: }
1178: break;
1179: }
1180: case JRHyperlink.HYPERLINK_TYPE_LOCAL_ANCHOR: {
1181: if (link.getHyperlinkAnchor() != null) {
1182: chunk.setLocalGoto(link.getHyperlinkAnchor());
1183: }
1184: break;
1185: }
1186: case JRHyperlink.HYPERLINK_TYPE_LOCAL_PAGE: {
1187: if (link.getHyperlinkPage() != null) {
1188: chunk.setLocalGoto(JR_PAGE_ANCHOR_PREFIX + reportIndex
1189: + "_" + link.getHyperlinkPage().toString());
1190: }
1191: break;
1192: }
1193: case JRHyperlink.HYPERLINK_TYPE_REMOTE_ANCHOR: {
1194: if (link.getHyperlinkReference() != null
1195: && link.getHyperlinkAnchor() != null) {
1196: chunk.setRemoteGoto(link.getHyperlinkReference(), link
1197: .getHyperlinkAnchor());
1198: }
1199: break;
1200: }
1201: case JRHyperlink.HYPERLINK_TYPE_REMOTE_PAGE: {
1202: if (link.getHyperlinkReference() != null
1203: && link.getHyperlinkPage() != null) {
1204: chunk.setRemoteGoto(link.getHyperlinkReference(), link
1205: .getHyperlinkPage().intValue());
1206: }
1207: break;
1208: }
1209: case JRHyperlink.HYPERLINK_TYPE_CUSTOM: {
1210: if (hyperlinkProducerFactory != null) {
1211: String hyperlink = hyperlinkProducerFactory
1212: .produceHyperlink(link);
1213: if (hyperlink != null) {
1214: chunk.setAnchor(hyperlink);
1215: }
1216: }
1217: }
1218: case JRHyperlink.HYPERLINK_TYPE_NONE:
1219: default: {
1220: break;
1221: }
1222: }
1223: }
1224:
1225: /**
1226: *
1227: */
1228: protected Phrase getPhrase(JRStyledText styledText,
1229: JRPrintText textElement) {
1230: Phrase phrase = new Phrase();
1231:
1232: String text = styledText.getText();
1233:
1234: int runLimit = 0;
1235:
1236: AttributedCharacterIterator iterator = styledText
1237: .getAttributedString().getIterator();
1238:
1239: while (runLimit < styledText.length()
1240: && (runLimit = iterator.getRunLimit()) <= styledText
1241: .length()) {
1242: Chunk chunk = getChunk(iterator.getAttributes(), text
1243: .substring(iterator.getIndex(), runLimit));
1244: setAnchor(chunk, textElement, textElement);
1245: setHyperlinkInfo(chunk, textElement);
1246: phrase.add(chunk);
1247:
1248: iterator.setIndex(runLimit);
1249: }
1250:
1251: return phrase;
1252: }
1253:
1254: /**
1255: *
1256: */
1257: protected Chunk getChunk(Map attributes, String text) {
1258: Font font = getFont(attributes);
1259:
1260: Chunk chunk = new Chunk(text, font);
1261:
1262: Color backcolor = (Color) attributes
1263: .get(TextAttribute.BACKGROUND);
1264: if (backcolor != null) {
1265: chunk.setBackground(backcolor);
1266: }
1267:
1268: Object script = attributes.get(TextAttribute.SUPERSCRIPT);
1269: if (script != null) {
1270: if (TextAttribute.SUPERSCRIPT_SUPER.equals(script)) {
1271: chunk.setTextRise(font.leading(1f) / 2);
1272: } else if (script != null
1273: && TextAttribute.SUPERSCRIPT_SUB.equals(script)) {
1274: chunk.setTextRise(-font.leading(1f) / 2);
1275: }
1276: }
1277:
1278: if (splitCharacter != null) {
1279: chunk.setSplitCharacter(splitCharacter);
1280: }
1281:
1282: return chunk;
1283: }
1284:
1285: /**
1286: *
1287: */
1288: protected Font getFont(Map attributes) {
1289: JRFont jrFont = new JRBaseFont(attributes);
1290:
1291: Exception initialException = null;
1292:
1293: Color forecolor = (Color) attributes
1294: .get(TextAttribute.FOREGROUND);
1295: /*
1296: if (forecolor == null)
1297: {
1298: forecolor = Color.black;
1299: }
1300: */
1301:
1302: Font font = null;
1303: PdfFont pdfFont = null;
1304: FontKey key = new FontKey(jrFont.getFontName(),
1305: jrFont.isBold(), jrFont.isItalic());
1306:
1307: if (fontMap != null && fontMap.containsKey(key)) {
1308: pdfFont = (PdfFont) fontMap.get(key);
1309: } else {
1310: pdfFont = new PdfFont(jrFont.getPdfFontName(), jrFont
1311: .getPdfEncoding(), jrFont.isPdfEmbedded());
1312: }
1313:
1314: try {
1315: font = FontFactory
1316: .getFont(
1317: pdfFont.getPdfFontName(),
1318: pdfFont.getPdfEncoding(),
1319: pdfFont.isPdfEmbedded(),
1320: jrFont.getFontSize(),
1321: (pdfFont.isPdfSimulatedBold() ? Font.BOLD
1322: : 0)
1323: | (pdfFont.isPdfSimulatedItalic() ? Font.ITALIC
1324: : 0)
1325: | (jrFont.isUnderline() ? Font.UNDERLINE
1326: : 0)
1327: | (jrFont.isStrikeThrough() ? Font.STRIKETHRU
1328: : 0), forecolor);
1329:
1330: // check if FontFactory didn't find the font
1331: if (font.getBaseFont() == null
1332: && font.family() == Font.UNDEFINED) {
1333: font = null;
1334: }
1335: } catch (Exception e) {
1336: initialException = e;
1337: }
1338:
1339: if (font == null) {
1340: byte[] bytes = null;
1341:
1342: try {
1343: bytes = JRLoader.loadBytesFromLocation(pdfFont
1344: .getPdfFontName(), classLoader,
1345: urlHandlerFactory);
1346: } catch (JRException e) {
1347: throw new JRRuntimeException(
1348: "Could not load the following font : "
1349: + "\npdfFontName : "
1350: + pdfFont.getPdfFontName()
1351: + "\npdfEncoding : "
1352: + pdfFont.getPdfEncoding()
1353: + "\nisPdfEmbedded : "
1354: + pdfFont.isPdfEmbedded(),
1355: initialException);
1356: }
1357:
1358: BaseFont baseFont = null;
1359:
1360: try {
1361: baseFont = BaseFont.createFont(
1362: pdfFont.getPdfFontName(), pdfFont
1363: .getPdfEncoding(), pdfFont
1364: .isPdfEmbedded(), true, bytes, null);
1365: } catch (DocumentException e) {
1366: throw new JRRuntimeException(e);
1367: } catch (IOException e) {
1368: throw new JRRuntimeException(e);
1369: }
1370:
1371: font = new Font(baseFont, jrFont.getFontSize(), ((pdfFont
1372: .isPdfSimulatedBold()) ? Font.BOLD : 0)
1373: | ((pdfFont.isPdfSimulatedItalic()) ? Font.ITALIC
1374: : 0)
1375: | (jrFont.isUnderline() ? Font.UNDERLINE : 0)
1376: | (jrFont.isStrikeThrough() ? Font.STRIKETHRU : 0),
1377: forecolor);
1378: }
1379:
1380: return font;
1381: }
1382:
1383: /**
1384: *
1385: */
1386: protected void exportText(JRPrintText text)
1387: throws DocumentException {
1388: JRStyledText styledText = getStyledText(text, false);
1389:
1390: if (styledText == null) {
1391: return;
1392: }
1393:
1394: int textLength = styledText.length();
1395:
1396: int x = text.getX() + getOffsetX();
1397: int y = text.getY() + getOffsetY();
1398: int width = text.getWidth();
1399: int height = text.getHeight();
1400: int topPadding = text.getTopPadding();
1401: int leftPadding = text.getLeftPadding();
1402: int bottomPadding = text.getBottomPadding();
1403: int rightPadding = text.getRightPadding();
1404:
1405: int xFillCorrection = 0;
1406: int yFillCorrection = 0;
1407:
1408: double angle = 0;
1409:
1410: switch (text.getRotation()) {
1411: case JRTextElement.ROTATION_LEFT: {
1412: y = text.getY() + getOffsetY() + text.getHeight();
1413: xFillCorrection = 1;
1414: width = text.getHeight();
1415: height = text.getWidth();
1416: int tmpPadding = topPadding;
1417: topPadding = leftPadding;
1418: leftPadding = bottomPadding;
1419: bottomPadding = rightPadding;
1420: rightPadding = tmpPadding;
1421: angle = Math.PI / 2;
1422: break;
1423: }
1424: case JRTextElement.ROTATION_RIGHT: {
1425: x = text.getX() + getOffsetX() + text.getWidth();
1426: yFillCorrection = -1;
1427: width = text.getHeight();
1428: height = text.getWidth();
1429: int tmpPadding = topPadding;
1430: topPadding = rightPadding;
1431: rightPadding = bottomPadding;
1432: bottomPadding = leftPadding;
1433: leftPadding = tmpPadding;
1434: angle = -Math.PI / 2;
1435: break;
1436: }
1437: case JRTextElement.ROTATION_UPSIDE_DOWN: {
1438: x = text.getX() + getOffsetX() + text.getWidth();
1439: y = text.getY() + getOffsetY() + text.getHeight();
1440: int tmpPadding = topPadding;
1441: topPadding = bottomPadding;
1442: bottomPadding = tmpPadding;
1443: tmpPadding = leftPadding;
1444: leftPadding = rightPadding;
1445: rightPadding = tmpPadding;
1446: angle = Math.PI;
1447: break;
1448: }
1449: case JRTextElement.ROTATION_NONE:
1450: default: {
1451: }
1452: }
1453:
1454: AffineTransform atrans = new AffineTransform();
1455: atrans.rotate(angle, x, jasperPrint.getPageHeight() - y);
1456: pdfContentByte.transform(atrans);
1457:
1458: if (text.getMode() == JRElement.MODE_OPAQUE) {
1459: Color backcolor = text.getBackcolor();
1460: pdfContentByte.setRGBColorStroke(backcolor.getRed(),
1461: backcolor.getGreen(), backcolor.getBlue());
1462: pdfContentByte.setRGBColorFill(backcolor.getRed(),
1463: backcolor.getGreen(), backcolor.getBlue());
1464: pdfContentByte.setLineWidth(1f);
1465: pdfContentByte.setLineDash(0f);
1466: pdfContentByte.rectangle(x + xFillCorrection, jasperPrint
1467: .getPageHeight()
1468: - y + yFillCorrection, width - 1, -height + 1);
1469: pdfContentByte.fillStroke();
1470: } else {
1471: /*
1472: pdfContentByte.setRGBColorStroke(
1473: text.getForecolor().getRed(),
1474: text.getForecolor().getGreen(),
1475: text.getForecolor().getBlue()
1476: );
1477: pdfContentByte.setLineWidth(0.1f);
1478: pdfContentByte.setLineDash(0f);
1479: pdfContentByte.rectangle(
1480: text.getX() + offsetX,
1481: jasperPrint.getPageHeight() - text.getY() - offsetY,
1482: text.getWidth(),
1483: - text.getHeight()
1484: );
1485: pdfContentByte.stroke();
1486: */
1487: }
1488:
1489: if (textLength > 0) {
1490: int horizontalAlignment = Element.ALIGN_LEFT;
1491: switch (text.getHorizontalAlignment()) {
1492: case JRAlignment.HORIZONTAL_ALIGN_LEFT: {
1493: if (text.getRunDirection() == JRPrintText.RUN_DIRECTION_LTR) {
1494: horizontalAlignment = Element.ALIGN_LEFT;
1495: } else {
1496: horizontalAlignment = Element.ALIGN_RIGHT;
1497: }
1498: break;
1499: }
1500: case JRAlignment.HORIZONTAL_ALIGN_CENTER: {
1501: horizontalAlignment = Element.ALIGN_CENTER;
1502: break;
1503: }
1504: case JRAlignment.HORIZONTAL_ALIGN_RIGHT: {
1505: if (text.getRunDirection() == JRPrintText.RUN_DIRECTION_LTR) {
1506: horizontalAlignment = Element.ALIGN_RIGHT;
1507: } else {
1508: horizontalAlignment = Element.ALIGN_LEFT;
1509: }
1510: break;
1511: }
1512: case JRAlignment.HORIZONTAL_ALIGN_JUSTIFIED: {
1513: horizontalAlignment = Element.ALIGN_JUSTIFIED;
1514: break;
1515: }
1516: default: {
1517: horizontalAlignment = Element.ALIGN_LEFT;
1518: }
1519: }
1520:
1521: float verticalOffset = 0f;
1522: switch (text.getVerticalAlignment()) {
1523: case JRAlignment.VERTICAL_ALIGN_TOP: {
1524: verticalOffset = 0f;
1525: break;
1526: }
1527: case JRAlignment.VERTICAL_ALIGN_MIDDLE: {
1528: verticalOffset = (height - topPadding - bottomPadding - text
1529: .getTextHeight()) / 2f;
1530: break;
1531: }
1532: case JRAlignment.VERTICAL_ALIGN_BOTTOM: {
1533: verticalOffset = height - topPadding - bottomPadding
1534: - text.getTextHeight();
1535: break;
1536: }
1537: default: {
1538: verticalOffset = 0f;
1539: }
1540: }
1541:
1542: ColumnText colText = new ColumnText(pdfContentByte);
1543: colText.setSimpleColumn(getPhrase(styledText, text), x
1544: + leftPadding, jasperPrint.getPageHeight() - y
1545: - topPadding - verticalOffset
1546: - text.getLeadingOffset(),
1547: //+ text.getLineSpacingFactor() * text.getFont().getSize(),
1548: x + width - rightPadding, jasperPrint
1549: .getPageHeight()
1550: - y - height + bottomPadding, 0,//text.getLineSpacingFactor(),// * text.getFont().getSize(),
1551: horizontalAlignment);
1552:
1553: colText.setLeading(0, text.getLineSpacingFactor());// * text.getFont().getSize());
1554: colText
1555: .setRunDirection(text.getRunDirection() == JRPrintText.RUN_DIRECTION_LTR ? PdfWriter.RUN_DIRECTION_LTR
1556: : PdfWriter.RUN_DIRECTION_RTL);
1557:
1558: colText.go();
1559: }
1560:
1561: atrans = new AffineTransform();
1562: atrans.rotate(-angle, x, jasperPrint.getPageHeight() - y);
1563: pdfContentByte.transform(atrans);
1564:
1565: /* */
1566: exportBox(text, text);
1567: }
1568:
1569: /**
1570: *
1571: */
1572: protected void exportBox(JRBox box, JRPrintElement element) {
1573: if (box.getTopBorder() != JRGraphicElement.PEN_NONE) {
1574: float borderCorrection = prepareBorder(pdfContentByte, box
1575: .getTopBorder());
1576: Color color = box.getTopBorderColor() == null ? element
1577: .getForecolor() : box.getTopBorderColor();
1578: pdfContentByte.setRGBColorStroke(color.getRed(), color
1579: .getGreen(), color.getBlue());
1580: pdfContentByte.moveTo(element.getX() + getOffsetX()
1581: - borderCorrection, jasperPrint.getPageHeight()
1582: - element.getY() - getOffsetY() + borderCorrection);
1583: pdfContentByte.lineTo(element.getX() + getOffsetX()
1584: + element.getWidth() - 1 + borderCorrection,
1585: jasperPrint.getPageHeight() - element.getY()
1586: - getOffsetY() + borderCorrection);
1587: pdfContentByte.stroke();
1588: }
1589:
1590: if (box.getLeftBorder() != JRGraphicElement.PEN_NONE) {
1591: float borderCorrection = prepareBorder(pdfContentByte, box
1592: .getLeftBorder());
1593: Color color = box.getLeftBorderColor() == null ? element
1594: .getForecolor() : box.getLeftBorderColor();
1595: pdfContentByte.setRGBColorStroke(color.getRed(), color
1596: .getGreen(), color.getBlue());
1597: pdfContentByte.moveTo(element.getX() + getOffsetX()
1598: - borderCorrection, jasperPrint.getPageHeight()
1599: - element.getY() - getOffsetY() + borderCorrection);
1600: pdfContentByte.lineTo(element.getX() + getOffsetX()
1601: - borderCorrection, jasperPrint.getPageHeight()
1602: - element.getY() - getOffsetY()
1603: - element.getHeight() + 1 - borderCorrection);
1604: pdfContentByte.stroke();
1605: }
1606:
1607: if (box.getBottomBorder() != JRGraphicElement.PEN_NONE) {
1608: float borderCorrection = prepareBorder(pdfContentByte, box
1609: .getBottomBorder());
1610: Color color = box.getBottomBorderColor() == null ? element
1611: .getForecolor() : box.getBottomBorderColor();
1612: pdfContentByte.setRGBColorStroke(color.getRed(), color
1613: .getGreen(), color.getBlue());
1614: pdfContentByte.moveTo(element.getX() + getOffsetX()
1615: - borderCorrection, jasperPrint.getPageHeight()
1616: - element.getY() - getOffsetY()
1617: - element.getHeight() + 1 - borderCorrection);
1618: pdfContentByte.lineTo(element.getX() + getOffsetX()
1619: + element.getWidth() - 1 + borderCorrection,
1620: jasperPrint.getPageHeight() - element.getY()
1621: - getOffsetY() - element.getHeight() + 1
1622: - borderCorrection);
1623: pdfContentByte.stroke();
1624: }
1625:
1626: if (box.getRightBorder() != JRGraphicElement.PEN_NONE) {
1627: float borderCorrection = prepareBorder(pdfContentByte, box
1628: .getRightBorder());
1629: Color color = box.getRightBorderColor() == null ? element
1630: .getForecolor() : box.getRightBorderColor();
1631: pdfContentByte.setRGBColorStroke(color.getRed(), color
1632: .getGreen(), color.getBlue());
1633: pdfContentByte.moveTo(element.getX() + getOffsetX()
1634: + element.getWidth() - 1 + borderCorrection,
1635: jasperPrint.getPageHeight() - element.getY()
1636: - getOffsetY() + borderCorrection);
1637: pdfContentByte.lineTo(element.getX() + getOffsetX()
1638: + element.getWidth() - 1 + borderCorrection,
1639: jasperPrint.getPageHeight() - element.getY()
1640: - getOffsetY() - element.getHeight() + 1
1641: - borderCorrection);
1642: pdfContentByte.stroke();
1643: }
1644:
1645: pdfContentByte.setLineDash(0f);
1646: }
1647:
1648: /**
1649: *
1650: */
1651: private static float prepareBorder(PdfContentByte pdfContentByte,
1652: byte border) {
1653: float borderCorrection = 0f;
1654:
1655: switch (border) {
1656: case JRGraphicElement.PEN_DOTTED: {
1657: borderCorrection = 0f;
1658: pdfContentByte.setLineWidth(1f);
1659: pdfContentByte.setLineDash(5f, 3f, 0f);
1660: break;
1661: }
1662: case JRGraphicElement.PEN_4_POINT: {
1663: borderCorrection = .5f;
1664: pdfContentByte.setLineWidth(4f);
1665: pdfContentByte.setLineDash(0f);
1666: break;
1667: }
1668: case JRGraphicElement.PEN_2_POINT: {
1669: borderCorrection = .5f;
1670: pdfContentByte.setLineWidth(2f);
1671: pdfContentByte.setLineDash(0f);
1672: break;
1673: }
1674: case JRGraphicElement.PEN_THIN: {
1675: borderCorrection = 0.25f;
1676: pdfContentByte.setLineWidth(0.5f);
1677: pdfContentByte.setLineDash(0f);
1678: break;
1679: }
1680: case JRGraphicElement.PEN_NONE: {
1681: borderCorrection = 0.5f;
1682: pdfContentByte.setLineWidth(1f);
1683: pdfContentByte.setLineDash(0f);
1684: break;
1685: }
1686: case JRGraphicElement.PEN_1_POINT:
1687: default: {
1688: borderCorrection = 0f;
1689: pdfContentByte.setLineWidth(1f);
1690: pdfContentByte.setLineDash(0f);
1691: break;
1692: }
1693: }
1694:
1695: return borderCorrection;
1696: }
1697:
1698: protected static synchronized void registerFonts() {
1699: if (!fontsRegistered) {
1700: List fontFiles = JRProperties
1701: .getProperties(JRProperties.PDF_FONT_FILES_PREFIX);
1702: if (!fontFiles.isEmpty()) {
1703: for (Iterator i = fontFiles.iterator(); i.hasNext();) {
1704: JRProperties.PropertySuffix font = (JRProperties.PropertySuffix) i
1705: .next();
1706: String file = font.getValue();
1707: if (file.toLowerCase().endsWith(".ttc")) {
1708: FontFactory.register(file);
1709: } else {
1710: String alias = font.getSuffix();
1711: FontFactory.register(file, alias);
1712: }
1713: }
1714: }
1715:
1716: List fontDirs = JRProperties
1717: .getProperties(JRProperties.PDF_FONT_DIRS_PREFIX);
1718: if (!fontDirs.isEmpty()) {
1719: for (Iterator i = fontDirs.iterator(); i.hasNext();) {
1720: JRProperties.PropertySuffix dir = (JRProperties.PropertySuffix) i
1721: .next();
1722: FontFactory.registerDirectory(dir.getValue());
1723: }
1724: }
1725:
1726: fontsRegistered = true;
1727: }
1728: }
1729:
1730: static protected class Bookmark {
1731: final PdfOutline pdfOutline;
1732: final int level;
1733:
1734: Bookmark(Bookmark parent, int x, int top, String title) {
1735: this (parent, new PdfDestination(PdfDestination.XYZ, x, top,
1736: 0), title);
1737: }
1738:
1739: Bookmark(Bookmark parent, PdfDestination destination,
1740: String title) {
1741: this .pdfOutline = new PdfOutline(parent.pdfOutline,
1742: destination, title, false);
1743: this .level = parent.level + 1;
1744: }
1745:
1746: Bookmark(PdfOutline pdfOutline, int level) {
1747: this .pdfOutline = pdfOutline;
1748: this .level = level;
1749: }
1750: }
1751:
1752: static protected class BookmarkStack {
1753: LinkedList stack;
1754:
1755: BookmarkStack() {
1756: stack = new LinkedList();
1757: }
1758:
1759: void push(Bookmark bookmark) {
1760: stack.add(bookmark);
1761: }
1762:
1763: Bookmark pop() {
1764: return (Bookmark) stack.removeLast();
1765: }
1766:
1767: Bookmark peek() {
1768: return (Bookmark) stack.getLast();
1769: }
1770: }
1771:
1772: protected void initBookmarks() {
1773: bookmarkStack = new BookmarkStack();
1774:
1775: int rootLevel = isModeBatch && isCreatingBatchModeBookmarks ? -1
1776: : 0;
1777: Bookmark bookmark = new Bookmark(pdfContentByte
1778: .getRootOutline(), rootLevel);
1779: bookmarkStack.push(bookmark);
1780: }
1781:
1782: protected void addBookmark(int level, String title, int x, int y) {
1783: Bookmark parent = bookmarkStack.peek();
1784: while (parent.level > level - 1) {
1785: bookmarkStack.pop();
1786: parent = bookmarkStack.peek();
1787: }
1788:
1789: for (int i = parent.level + 1; i < level; ++i) {
1790: Bookmark emptyBookmark = new Bookmark(parent,
1791: parent.pdfOutline.getPdfDestination(),
1792: EMPTY_BOOKMARK_TITLE);
1793: bookmarkStack.push(emptyBookmark);
1794: parent = emptyBookmark;
1795: }
1796:
1797: Bookmark bookmark = new Bookmark(parent, x, jasperPrint
1798: .getPageHeight()
1799: - y, title);
1800: bookmarkStack.push(bookmark);
1801: }
1802:
1803: protected void setAnchor(Chunk chunk, JRPrintAnchor anchor,
1804: JRPrintElement element) {
1805: String anchorName = anchor.getAnchorName();
1806: if (anchorName != null) {
1807: chunk.setLocalDestination(anchorName);
1808:
1809: if (anchor.getBookmarkLevel() != JRAnchor.NO_BOOKMARK) {
1810: addBookmark(anchor.getBookmarkLevel(), anchor
1811: .getAnchorName(), element.getX(), element
1812: .getY());
1813: }
1814: }
1815: }
1816:
1817: protected void exportFrame(JRPrintFrame frame)
1818: throws DocumentException, IOException, JRException {
1819: if (frame.getMode() == JRElement.MODE_OPAQUE) {
1820: int x = frame.getX() + getOffsetX();
1821: int y = frame.getY() + getOffsetY();
1822:
1823: Color backcolor = frame.getBackcolor();
1824: pdfContentByte.setRGBColorStroke(backcolor.getRed(),
1825: backcolor.getGreen(), backcolor.getBlue());
1826: pdfContentByte.setRGBColorFill(backcolor.getRed(),
1827: backcolor.getGreen(), backcolor.getBlue());
1828: pdfContentByte.setLineWidth(1f);
1829: pdfContentByte.setLineDash(0f);
1830: pdfContentByte.rectangle(x,
1831: jasperPrint.getPageHeight() - y,
1832: frame.getWidth() - 1, -frame.getHeight() + 1);
1833: pdfContentByte.fillStroke();
1834: }
1835:
1836: setFrameElementsOffset(frame, false);
1837: try {
1838: exportElements(frame.getElements());
1839: } finally {
1840: restoreElementOffsets();
1841: }
1842:
1843: exportBox(frame, frame);
1844: }
1845:
1846: /**
1847: * Output stream implementation that discards all the data.
1848: */
1849: public static class NullOutputStream extends OutputStream {
1850: public NullOutputStream() {
1851: }
1852:
1853: public void write(int b) {
1854: // discard the data
1855: }
1856:
1857: public void write(byte[] b, int off, int len) {
1858: // discard the data
1859: }
1860:
1861: public void write(byte[] b) {
1862: // discard the data
1863: }
1864: }
1865:
1866: /**
1867: *
1868: */
1869: class LocalFontMapper implements FontMapper {
1870: public LocalFontMapper() {
1871: }
1872:
1873: public BaseFont awtToPdf(java.awt.Font font) {
1874: return getFont(font.getAttributes()).getBaseFont();
1875: }
1876:
1877: public java.awt.Font pdfToAwt(BaseFont font, int size) {
1878: return null;
1879: }
1880: }
1881: }
|