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: * Matt Thompson - mthomp1234@users.sourceforge.net
0032: */
0033: package net.sf.jasperreports.engine.export;
0034:
0035: import java.awt.Color;
0036: import java.awt.Dimension;
0037: import java.awt.font.TextAttribute;
0038: import java.awt.geom.Dimension2D;
0039: import java.io.BufferedWriter;
0040: import java.io.ByteArrayInputStream;
0041: import java.io.File;
0042: import java.io.FileOutputStream;
0043: import java.io.IOException;
0044: import java.io.OutputStream;
0045: import java.io.OutputStreamWriter;
0046: import java.io.StringWriter;
0047: import java.io.Writer;
0048: import java.text.AttributedCharacterIterator;
0049: import java.util.ArrayList;
0050: import java.util.Collection;
0051: import java.util.Iterator;
0052: import java.util.List;
0053: import java.util.Map;
0054:
0055: import net.sf.jasperreports.engine.JRAbstractExporter;
0056: import net.sf.jasperreports.engine.JRAlignment;
0057: import net.sf.jasperreports.engine.JRBox;
0058: import net.sf.jasperreports.engine.JRElement;
0059: import net.sf.jasperreports.engine.JRException;
0060: import net.sf.jasperreports.engine.JRExporterParameter;
0061: import net.sf.jasperreports.engine.JRFont;
0062: import net.sf.jasperreports.engine.JRGraphicElement;
0063: import net.sf.jasperreports.engine.JRHyperlink;
0064: import net.sf.jasperreports.engine.JRImage;
0065: import net.sf.jasperreports.engine.JRImageRenderer;
0066: import net.sf.jasperreports.engine.JRLine;
0067: import net.sf.jasperreports.engine.JRPrintElement;
0068: import net.sf.jasperreports.engine.JRPrintEllipse;
0069: import net.sf.jasperreports.engine.JRPrintFrame;
0070: import net.sf.jasperreports.engine.JRPrintGraphicElement;
0071: import net.sf.jasperreports.engine.JRPrintHyperlink;
0072: import net.sf.jasperreports.engine.JRPrintImage;
0073: import net.sf.jasperreports.engine.JRPrintLine;
0074: import net.sf.jasperreports.engine.JRPrintPage;
0075: import net.sf.jasperreports.engine.JRPrintRectangle;
0076: import net.sf.jasperreports.engine.JRPrintText;
0077: import net.sf.jasperreports.engine.JRRenderable;
0078: import net.sf.jasperreports.engine.JRReport;
0079: import net.sf.jasperreports.engine.JRWrappingSvgRenderer;
0080: import net.sf.jasperreports.engine.JasperPrint;
0081: import net.sf.jasperreports.engine.base.JRBaseFont;
0082: import net.sf.jasperreports.engine.base.JRBasePrintText;
0083: import net.sf.jasperreports.engine.util.JRStyledText;
0084:
0085: /**
0086: * Exports a JasperReports document to RTF format. It has binary output type and exports the document to
0087: * a free-form layout. It uses the RTF Specification 1.6 (compatible with MS Word 6.0, 2003 and XP).
0088: * <p>
0089: * Since classic AWT fonts can be sometimes very different from system fonts (which are used by RTF viewers),
0090: * a font mapping feature was added. By using the {@link JRExporterParameter#FONT_MAP} parameter, a logical
0091: * font like "sansserif" can be mapped to a system specific font, like "Comic Sans MS". Both map keys and values are strings.
0092: * @author Flavius Sana (flavius_sana@users.sourceforge.net)
0093: * @version $Id: JRRtfExporter.java 1824 2007-08-23 14:19:12Z teodord $
0094: */
0095: public class JRRtfExporter extends JRAbstractExporter {
0096: /**
0097: *
0098: */
0099: protected static final String JR_PAGE_ANCHOR_PREFIX = "JR_PAGE_ANCHOR_";
0100: protected JRExportProgressMonitor progressMonitor = null;
0101:
0102: protected Writer writer = null;
0103: protected File destFile = null;
0104:
0105: protected int reportIndex = 0;
0106:
0107: // temporary list of fonts and colors to be
0108: // added to the header or the document
0109: private StringBuffer colorBuffer = null;
0110: private StringBuffer fontBuffer = null;
0111: protected List colors = null;
0112: protected List fonts = null;
0113:
0114: // z order of the graphical objects in .rtf file
0115: private int zorder = 1;
0116:
0117: // indicate that report containts Unicode characters with code > 127
0118: private boolean isUnicode = false;
0119:
0120: private Map fontMap = null;
0121: protected JRHyperlinkProducerFactory hyperlinkProducerFactory;
0122:
0123: /**
0124: * Export report in .rtf format
0125: */
0126: public void exportReport() throws JRException {
0127: progressMonitor = (JRExportProgressMonitor) parameters
0128: .get(JRExporterParameter.PROGRESS_MONITOR);
0129:
0130: /* */
0131: setOffset();
0132:
0133: try {
0134: /* */
0135: setExportContext();
0136:
0137: /* */
0138: setInput();
0139:
0140: if (!isModeBatch) {
0141: setPageRange();
0142: }
0143:
0144: fonts = new ArrayList();
0145: fontBuffer = new StringBuffer();
0146: colors = new ArrayList();
0147: colors.add(null);
0148: colorBuffer = new StringBuffer(";");
0149:
0150: fontMap = (Map) parameters
0151: .get(JRExporterParameter.FONT_MAP);
0152: setHyperlinkProducerFactory();
0153: StringBuffer sb = (StringBuffer) parameters
0154: .get(JRExporterParameter.OUTPUT_STRING_BUFFER);
0155: if (sb != null) {
0156: StringBuffer buffer = exportReportToBuffer();
0157: sb.append(buffer.toString());
0158: } else {
0159: Writer outWriter = (Writer) parameters
0160: .get(JRExporterParameter.OUTPUT_WRITER);
0161: if (outWriter != null) {
0162: try {
0163: writer = outWriter;
0164:
0165: // export report
0166: exportReportToStream();
0167: } catch (IOException ex) {
0168: throw new JRException(
0169: "Error writing to writer : "
0170: + jasperPrint.getName(), ex);
0171: }
0172: } else {
0173: OutputStream os = (OutputStream) parameters
0174: .get(JRExporterParameter.OUTPUT_STREAM);
0175: if (os != null) {
0176: try {
0177: writer = new OutputStreamWriter(os);
0178:
0179: // export report
0180: exportReportToStream();
0181: } catch (Exception ex) {
0182: throw new JRException(
0183: "Error writing to output stream : "
0184: + jasperPrint.getName(), ex);
0185: }
0186: } else {
0187: destFile = (File) parameters
0188: .get(JRExporterParameter.OUTPUT_FILE);
0189: if (destFile == null) {
0190: String fileName = (String) parameters
0191: .get(JRExporterParameter.OUTPUT_FILE_NAME);
0192: if (fileName != null) {
0193: destFile = new File(fileName);
0194: } else {
0195: throw new JRException(
0196: "No output specified for the exporter");
0197: }
0198: }
0199:
0200: // export report
0201: exportReportToFile();
0202: }
0203: }
0204: }
0205: } finally {
0206: resetExportContext();
0207: }
0208: }
0209:
0210: protected void setHyperlinkProducerFactory() {
0211: hyperlinkProducerFactory = (JRHyperlinkProducerFactory) parameters
0212: .get(JRExporterParameter.HYPERLINK_PRODUCER_FACTORY);
0213: }
0214:
0215: /**
0216: * Export report in .rtf format
0217: * @return report in .rtf format in a StringBuffer object
0218: */
0219: protected StringBuffer exportReportToBuffer() throws JRException {
0220: StringWriter buffer = new StringWriter();
0221: writer = buffer;
0222: try {
0223: exportReportToStream();
0224: } catch (IOException ex) {
0225: throw new JRException(
0226: "Error while exporting report to the buffer");
0227: }
0228:
0229: return buffer.getBuffer();
0230: }
0231:
0232: /**
0233: * Export report in .rtf format to a stream
0234: * @throws JRException
0235: * @throws IOException
0236: */
0237: protected void exportReportToStream() throws JRException,
0238: IOException {
0239:
0240: // create the header of the rtf file
0241: writer.write("{\\rtf1\\ansi\\deff0\n");
0242: // create font and color tables
0243: createColorAndFontEntries();
0244: writer.write("{\\fonttbl ");
0245: writer.write(fontBuffer.toString());
0246: writer.write("}\n");
0247:
0248: writer.write("{\\colortbl ");
0249: writer.write(colorBuffer.toString());
0250: writer.write("}\n");
0251:
0252: for (reportIndex = 0; reportIndex < jasperPrintList.size(); reportIndex++) {
0253: jasperPrint = (JasperPrint) jasperPrintList
0254: .get(reportIndex);
0255:
0256: List pages = jasperPrint.getPages();
0257: if (pages != null && pages.size() > 0) {
0258: if (isModeBatch) {
0259: startPageIndex = 0;
0260: endPageIndex = pages.size() - 1;
0261: }
0262: JRPrintPage page = null;
0263:
0264: writer.write("{\\info{\\nofpages");
0265: writer.write(String.valueOf(pages.size()));
0266: writer.write("}}\n");
0267:
0268: writer.write("\\viewkind1\\paperw");
0269: writer.write(String.valueOf(twip(jasperPrint
0270: .getPageWidth())));
0271: writer.write("\\paperh");
0272: writer.write(String.valueOf(twip(jasperPrint
0273: .getPageHeight())));
0274:
0275: writer
0276: .write("\\marglsxn0\\margrsxn0\\margtsxn0\\margbsxn0");
0277:
0278: if (jasperPrint.getOrientation() == JRReport.ORIENTATION_LANDSCAPE) {
0279: writer.write("\\lndscpsxn");
0280: }
0281:
0282: for (int pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) {
0283: writer.write("\n");
0284: if (Thread.currentThread().isInterrupted()) {
0285: throw new JRException(
0286: "Current thread intrerrupted");
0287: }
0288:
0289: page = (JRPrintPage) pages.get(pageIndex);
0290: writeAnchor(JR_PAGE_ANCHOR_PREFIX + reportIndex
0291: + "_" + (pageIndex + 1));
0292:
0293: boolean lastPageFlag = false;
0294: if (pageIndex == endPageIndex
0295: && reportIndex == (jasperPrintList.size() - 1)) {
0296: lastPageFlag = true;
0297: }
0298: exportPage(page, lastPageFlag);
0299: }
0300: }
0301: }
0302: writer.write("}\n");
0303: writer.flush();
0304: }
0305:
0306: /**
0307: * Export report to a file in the .rtf format
0308: */
0309: protected void exportReportToFile() throws JRException {
0310: try {
0311: OutputStream fileOutputStream = new FileOutputStream(
0312: destFile);
0313: writer = new BufferedWriter(new OutputStreamWriter(
0314: fileOutputStream));
0315: exportReportToStream();
0316: } catch (IOException ex) {
0317: throw new JRException("Error writing to the file : "
0318: + destFile, ex);
0319: } finally {
0320: if (writer != null) {
0321: try {
0322: writer.close();
0323: } catch (IOException ex) {
0324:
0325: }
0326: }
0327: }
0328: }
0329:
0330: /**
0331: * Create color and font entries for the header of .rtf file.
0332: * Each color is represented by values of the red,
0333: * green and blue components.
0334: * @throws JRException
0335: */
0336: protected void createColorAndFontEntries() throws JRException {
0337: for (reportIndex = 0; reportIndex < jasperPrintList.size(); reportIndex++) {
0338: jasperPrint = (JasperPrint) jasperPrintList
0339: .get(reportIndex);
0340:
0341: getFontIndex(new JRBasePrintText(jasperPrint
0342: .getDefaultStyleProvider()));
0343:
0344: List pages = jasperPrint.getPages();
0345: if (pages != null && pages.size() > 0) {
0346: if (isModeBatch) {
0347: startPageIndex = 0;
0348: endPageIndex = pages.size() - 1;
0349: }
0350:
0351: for (int pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) {
0352: if (Thread.currentThread().isInterrupted()) {
0353: throw new JRException(
0354: "Current thread interrupted");
0355: }
0356: JRPrintPage page = (JRPrintPage) pages
0357: .get(pageIndex);
0358: JRPrintElement element = null;
0359: Collection elements = page.getElements();
0360: if (elements != null && elements.size() > 0) {
0361: for (Iterator it = elements.iterator(); it
0362: .hasNext();) {
0363: element = (JRPrintElement) it.next();
0364: getColorIndex(element.getForecolor());
0365: getColorIndex(element.getBackcolor());
0366:
0367: if (element instanceof JRPrintText) {
0368: JRPrintText text = (JRPrintText) element;
0369:
0370: // create color indices for box border color
0371: getColorIndex(text.getBorderColor());
0372: getColorIndex(text.getTopBorderColor());
0373: getColorIndex(text
0374: .getBottomBorderColor());
0375: getColorIndex(text.getLeftBorderColor());
0376: getColorIndex(text
0377: .getRightBorderColor());
0378:
0379: for (int i = 0; i < text.getText()
0380: .length(); i++) {
0381: if ((text.getText().charAt(i)) > 127) {
0382: isUnicode = true;
0383: break;
0384: }
0385: }
0386:
0387: int runLimit = 0;
0388: JRStyledText styledText = getStyledText((JRPrintText) element);
0389: AttributedCharacterIterator iterator = styledText
0390: .getAttributedString()
0391: .getIterator();
0392: while (runLimit < styledText.length()
0393: && (runLimit = iterator
0394: .getRunLimit()) <= styledText
0395: .length()) {
0396: Map styledTextAttributes = iterator
0397: .getAttributes();
0398:
0399: getFontIndex(new JRBaseFont(
0400: styledTextAttributes));
0401:
0402: getColorIndex((Color) styledTextAttributes
0403: .get(TextAttribute.FOREGROUND));
0404: getColorIndex((Color) styledTextAttributes
0405: .get(TextAttribute.BACKGROUND));
0406:
0407: iterator.setIndex(runLimit);
0408: }
0409:
0410: getFontIndex((JRPrintText) element);
0411: }
0412: }
0413: }
0414: }
0415: }
0416: }
0417: }
0418:
0419: /**
0420: * Return color index from header of the .rtf file. If a color is not
0421: * found is automatically added to the header of the rtf file. The
0422: * method is called first when the header of the .rtf file is constructed
0423: * and when a componenent needs a color for foreground or background
0424: * @param color Color for which the index is required.
0425: * @return index of the color from .rtf file header
0426: */
0427: private int getColorIndex(Color color) {
0428: int colorNdx = colors.indexOf(color);
0429: if (colorNdx < 0) {
0430: colorNdx = colors.size();
0431: colors.add(color);
0432: colorBuffer.append("\\red").append(color.getRed()).append(
0433: "\\green").append(color.getGreen())
0434: .append("\\blue").append(color.getBlue()).append(
0435: ";");
0436: }
0437: return colorNdx;
0438: }
0439:
0440: /**
0441: * Return font index from the header of the .rtf file. The method is
0442: * called first when the header of the .rtf document is constructed and when a
0443: * text component needs font informations.
0444: * @param font the font for which the index is required
0445: * @return index of the font from .rtf file header
0446: */
0447: private int getFontIndex(JRFont font) {
0448: String fontName = font.getFontName();
0449: if (fontMap != null && fontMap.containsKey(fontName)) {
0450: fontName = (String) fontMap.get(fontName);
0451: }
0452:
0453: int fontIndex = fonts.indexOf(fontName);
0454:
0455: if (fontIndex < 0) {
0456: fontIndex = fonts.size();
0457: fonts.add(fontName);
0458: fontBuffer.append("{\\f").append(fontIndex).append(
0459: "\\fnil ").append(fontName).append(";}");
0460: }
0461:
0462: return fontIndex;
0463: }
0464:
0465: /**
0466: * Convert a int value from points to twips (multiply with 20)
0467: * @param points value that needs to be converted
0468: * @return converted value in twips
0469: */
0470: private int twip(int points) {
0471: return points * 20;
0472: }
0473:
0474: /**
0475: * Convert a float value to twips (multiply with 20)
0476: * @param points value that need to be converted
0477: * @return converted value in twips
0478: */
0479: private int twip(float points) {
0480: return (int) (points * 20);
0481: }
0482:
0483: /**
0484: * Exports a report page
0485: * @param page Page that will be exported
0486: * @throws JRException
0487: */
0488: protected void exportPage(JRPrintPage page, boolean lastPage)
0489: throws JRException, IOException {
0490: exportElements(page.getElements());
0491:
0492: if (!lastPage) {
0493: if (isUnicode) {
0494: writer.write("{\\pard\\pagebb\\par}\n");
0495: } else {
0496: writer.write("\\page\n");
0497: }
0498:
0499: }
0500: }
0501:
0502: /**
0503: * Add a graphic element to the .rtf document
0504: * @param type Type of the graphic element
0505: * @param x x axis position of the graphic element
0506: * @param y y axis position of the graphic
0507: * @param w width of the graphic element
0508: * @param h height of the graphic element
0509: * @throws IOException
0510: */
0511: private void startGraphic(String type, int x, int y, int w, int h)
0512: throws IOException {
0513: writer.write("{\\*\\do\\dobxpage\\dobypage\\dodhgt");
0514: writer.write(String.valueOf(zorder++));
0515:
0516: writer.write("\\");
0517: writer.write(type);
0518:
0519: writer.write("\\dpx");
0520: writer.write(String.valueOf(x));
0521: writer.write("\\dpy");
0522: writer.write(String.valueOf(y));
0523:
0524: writer.write("\\dpxsize");
0525: writer.write(String.valueOf(w));
0526: writer.write("\\dpysize");
0527: writer.write(String.valueOf(h));
0528: }
0529:
0530: /**
0531: * Add document control words that marks the end of a graphic element
0532: * @param element Graphic element
0533: * @throws IOException
0534: */
0535: private void finishGraphic(JRPrintGraphicElement element)
0536: throws IOException {
0537: int mode = 0;
0538: if (element.getMode() == JRElement.MODE_OPAQUE) {
0539: mode = 1;
0540: }
0541:
0542: finishGraphic(element.getPen(), element.getForecolor(), element
0543: .getBackcolor(), mode);
0544: }
0545:
0546: /**
0547: * Add document control words that marks the end of a graphic element
0548: * @param pen pen dimension
0549: * @param fg foreground color
0550: * @param bg background color
0551: * @param fillPattern fill pattern
0552: * @throws IOException
0553: */
0554: private void finishGraphic(byte pen, Color fg, Color bg,
0555: int fillPattern) throws IOException {
0556: switch (pen) {
0557: case JRGraphicElement.PEN_THIN:
0558: writer.write("\\dplinew10");
0559: break;
0560: case JRGraphicElement.PEN_1_POINT:
0561: writer.write("\\dplinew20");
0562: break;
0563: case JRGraphicElement.PEN_2_POINT:
0564: writer.write("\\dplinew40");
0565: break;
0566: case JRGraphicElement.PEN_4_POINT:
0567: writer.write("\\dplinew80");
0568: break;
0569: case JRGraphicElement.PEN_DOTTED:
0570: writer.write("\\dplinedash");
0571: break;
0572: case JRGraphicElement.PEN_NONE:
0573: writer.write("\\dplinehollow");
0574: break;
0575: default:
0576: writer.write("\\dplinew20");
0577: break;
0578: }
0579:
0580: writer.write("\\dplinecor");
0581: writer.write(String.valueOf(fg.getRed()));
0582: writer.write("\\dplinecob");
0583: writer.write(String.valueOf(fg.getBlue()));
0584: writer.write("\\dplinecog");
0585: writer.write(String.valueOf(fg.getGreen()));
0586:
0587: writer.write("\\dpfillfgcr");
0588: writer.write(String.valueOf(fg.getRed()));
0589: writer.write("\\dplinefgcb");
0590: writer.write(String.valueOf(fg.getBlue()));
0591: writer.write("\\dpfillfgcg");
0592: writer.write(String.valueOf(fg.getGreen()));
0593:
0594: writer.write("\\dpfillbgcr");
0595: writer.write(String.valueOf(bg.getRed()));
0596: writer.write("\\dpfillbgcg");
0597: writer.write(String.valueOf(bg.getGreen()));
0598: writer.write("\\dpfillbgcb");
0599: writer.write(String.valueOf(bg.getBlue()));
0600:
0601: writer.write("\\dpfillpat");
0602: writer.write(String.valueOf(fillPattern));
0603: writer.write("}\n");
0604: }
0605:
0606: /**
0607: * Get border adjustment for graphic elements depending on pen width used
0608: * @param pen
0609: */
0610: protected int getAdjustment(byte pen) {
0611: switch (pen) {
0612: case JRGraphicElement.PEN_THIN:
0613: return 0;
0614: case JRGraphicElement.PEN_1_POINT:
0615: return 10;
0616: case JRGraphicElement.PEN_2_POINT:
0617: return 20;
0618: case JRGraphicElement.PEN_4_POINT:
0619: return 40;
0620: case JRGraphicElement.PEN_DOTTED:
0621: return 0;
0622: case JRGraphicElement.PEN_NONE:
0623: return 0;
0624: default:
0625: return 0;
0626: }
0627: }
0628:
0629: /**
0630: * Draw a line object
0631: * @param line JasperReports line object - JRPrintLine
0632: * @throws IOException
0633: */
0634: protected void exportLine(JRPrintLine line) throws IOException {
0635: int x = twip(line.getX() + getOffsetX());
0636: int y = twip(line.getY() + getOffsetY());
0637: int h = twip(line.getHeight());
0638: int w = twip(line.getWidth());
0639:
0640: if (w <= 20 || h <= 20) {
0641: if (w > 20) {
0642: h = 0;
0643: } else {
0644: w = 0;
0645: }
0646: }
0647:
0648: startGraphic("dpline", x, y, w, h);
0649:
0650: if (line.getDirection() == JRLine.DIRECTION_TOP_DOWN) {
0651: writer.write("\\dpptx");
0652: writer.write(String.valueOf(x));
0653: writer.write("\\dppty");
0654: writer.write(String.valueOf(y));
0655: writer.write("\\dpptx");
0656: writer.write(String.valueOf(x + w));
0657: writer.write("\\dppty");
0658: writer.write(String.valueOf(y + h));
0659: } else {
0660: writer.write("\\dpptx");
0661: writer.write(String.valueOf(x));
0662: writer.write("\\dppty");
0663: writer.write(String.valueOf(y + h));
0664: writer.write("\\dpptx");
0665: writer.write(String.valueOf(x + w));
0666: writer.write("\\dppty");
0667: writer.write(String.valueOf(y));
0668: }
0669:
0670: finishGraphic(line);
0671: }
0672:
0673: /**
0674: * Draw a rectangle
0675: * @param rect JasperReports rectangle object (JRPrintRectangle)
0676: */
0677: protected void exportRectangle(JRPrintRectangle rect)
0678: throws IOException {
0679: startGraphic("dprect"
0680: + (rect.getRadius() > 0 ? "\\dproundr" : ""), twip(rect
0681: .getX()
0682: + getOffsetX()), twip(rect.getY() + getOffsetY()),
0683: twip(rect.getWidth()), twip(rect.getHeight()));
0684: finishGraphic(rect);
0685: }
0686:
0687: /**
0688: * Draw a ellipse object
0689: * @param ellipse JasperReports ellipse object (JRPrintElipse)
0690: */
0691: protected void exportEllipse(JRPrintEllipse ellipse)
0692: throws IOException {
0693: startGraphic("dpellipse", twip(ellipse.getX() + getOffsetX()),
0694: twip(ellipse.getY() + getOffsetY()), twip(ellipse
0695: .getWidth()), twip(ellipse.getHeight()));
0696: finishGraphic(ellipse);
0697: }
0698:
0699: /**
0700: * Draw a text box
0701: * @param text JasperReports text object (JRPrintText)
0702: * @throws JRException
0703: */
0704: protected void exportText(JRPrintText text) throws IOException,
0705: JRException {
0706:
0707: // use styled text
0708: JRStyledText styledText = getStyledText(text);
0709: if (styledText == null) {
0710: return;
0711: }
0712:
0713: int x = twip(text.getX() + getOffsetX());
0714: int y = twip(text.getY() + getOffsetY());
0715:
0716: int width = twip(text.getWidth());
0717: int height = twip(text.getHeight());
0718:
0719: int textBoxAdjustment = 20;
0720:
0721: int textHeight = twip(text.getTextHeight());
0722:
0723: if (textHeight <= 0) {
0724: if (height <= 0) {
0725: throw new JRException("Invalid text height");
0726: }
0727: textHeight = height;
0728: }
0729:
0730: // padding for the text
0731: int topPadding = twip(text.getTopPadding());
0732: int leftPadding = twip(text.getLeftPadding());
0733: int bottomPadding = twip(text.getBottomPadding());
0734: int rightPadding = twip(text.getRightPadding());
0735:
0736: Color bgcolor = text.getBackcolor();
0737:
0738: if (text.getMode() == JRElement.MODE_OPAQUE) {
0739: startGraphic("dprect", x, y, width, height);
0740: finishGraphic(JRGraphicElement.PEN_NONE, text
0741: .getForecolor(), bgcolor, 1);
0742: }
0743:
0744: int verticalAdjustment = topPadding;
0745: switch (text.getVerticalAlignment()) {
0746: case JRAlignment.VERTICAL_ALIGN_TOP:
0747: verticalAdjustment = 0;
0748: break;
0749: case JRAlignment.VERTICAL_ALIGN_MIDDLE:
0750: verticalAdjustment = (height - topPadding - bottomPadding - twip(text
0751: .getTextHeight())) / 2;
0752: break;
0753: case JRAlignment.VERTICAL_ALIGN_BOTTOM:
0754: verticalAdjustment = (height - topPadding - bottomPadding - twip(text
0755: .getTextHeight()));
0756: break;
0757: }
0758:
0759: /*
0760: rtf text box does not allow unicode characters
0761: representation so if the report contains
0762: unicode characters above 127 the text box
0763: is replaced by paragraphs
0764: */
0765: if (isUnicode) {
0766: writer.write("{\\pard\\absw");
0767: writer.write(String.valueOf(width));
0768: writer.write("\\absh");
0769: writer.write(String.valueOf(textHeight));
0770: writer.write("\\phpg\\posx");
0771: writer.write(String.valueOf(x));
0772: writer.write("\\pvpg\\posy");
0773: writer.write(String.valueOf(y + verticalAdjustment
0774: + topPadding));
0775: } else {
0776: writer.write("{\\*\\do\\dobxpage\\dobypage\\dodhgt");
0777: writer.write(String.valueOf(zorder++));
0778: writer.write("\\dptxbx\\dpx");
0779: writer.write(String.valueOf(x + textBoxAdjustment));
0780: writer.write("\\dpxsize");
0781: writer.write(String.valueOf(width - textBoxAdjustment));
0782: writer.write("\\dpy");
0783: writer.write(String.valueOf(y + verticalAdjustment
0784: + topPadding + textBoxAdjustment));
0785: writer.write("\\dpysize");
0786: writer.write(String.valueOf(textHeight + bottomPadding
0787: - textBoxAdjustment));
0788: writer
0789: .write("\\dpfillpat0\\dplinehollow{\\dptxbxtext {\\pard");
0790: }
0791:
0792: JRFont font = text;
0793: writer.write("\\f");
0794: writer.write(String.valueOf(getFontIndex(font)));
0795: writer.write("\\cf");
0796: writer
0797: .write(String
0798: .valueOf(getColorIndex(text.getForecolor())));
0799: writer.write("\\cb");
0800: writer.write(String.valueOf(getColorIndex(bgcolor)));
0801: writer.write(" ");
0802:
0803: if (leftPadding > 0) {
0804: writer.write("\\li");
0805: writer.write(String.valueOf(leftPadding));
0806: }
0807:
0808: if (rightPadding > 0) {
0809: writer.write("\\ri");
0810: writer.write(String.valueOf(rightPadding));
0811: }
0812:
0813: if (font.isBold())
0814: writer.write("\\b");
0815: if (font.isItalic())
0816: writer.write("\\i");
0817: if (font.isStrikeThrough())
0818: writer.write("\\strike");
0819: if (font.isUnderline())
0820: writer.write("\\ul");
0821: writer.write("\\fs");
0822: writer.write(String.valueOf(font.getFontSize() * 2));
0823:
0824: switch (text.getHorizontalAlignment()) {
0825: case JRAlignment.HORIZONTAL_ALIGN_LEFT:
0826: writer.write("\\ql");
0827: break;
0828: case JRAlignment.HORIZONTAL_ALIGN_CENTER:
0829: writer.write("\\qc");
0830: break;
0831: case JRAlignment.HORIZONTAL_ALIGN_RIGHT:
0832: writer.write("\\qr");
0833: break;
0834: case JRAlignment.HORIZONTAL_ALIGN_JUSTIFIED:
0835: writer.write("\\qj");
0836: break;
0837: default:
0838: writer.write("\\ql");
0839: break;
0840: }
0841:
0842: writer.write("\\sl");
0843: writer.write(String.valueOf(twip(text.getLineSpacingFactor()
0844: * font.getFontSize())));
0845: writer.write(" ");
0846:
0847: if (text.getAnchorName() != null) {
0848: writeAnchor(text.getAnchorName());
0849: }
0850:
0851: boolean startedHyperlink = startHyperlink(text);
0852:
0853: // add parameters in case of styled text element
0854: String plainText = styledText.getText();
0855: int runLimit = 0;
0856:
0857: AttributedCharacterIterator iterator = styledText
0858: .getAttributedString().getIterator();
0859: while (runLimit < styledText.length()
0860: && (runLimit = iterator.getRunLimit()) <= styledText
0861: .length()) {
0862:
0863: Map styledTextAttributes = iterator.getAttributes();
0864: JRFont styleFont = new JRBaseFont(styledTextAttributes);
0865: Color styleForeground = (Color) styledTextAttributes
0866: .get(TextAttribute.FOREGROUND);
0867: Color styleBackground = (Color) styledTextAttributes
0868: .get(TextAttribute.BACKGROUND);
0869:
0870: writer.write("\\f");
0871: writer.write(String.valueOf(getFontIndex(styleFont)));
0872: writer.write("\\fs");
0873: writer.write(String.valueOf(2 * styleFont.getFontSize()));
0874:
0875: if (styleFont.isBold()) {
0876: writer.write("\\b");
0877: }
0878: if (styleFont.isItalic()) {
0879: writer.write("\\i");
0880: }
0881: if (styleFont.isUnderline()) {
0882: writer.write("\\ul");
0883: }
0884: if (styleFont.isStrikeThrough()) {
0885: writer.write("\\strike");
0886: }
0887:
0888: if (TextAttribute.SUPERSCRIPT_SUPER
0889: .equals(styledTextAttributes
0890: .get(TextAttribute.SUPERSCRIPT))) {
0891: writer.write("\\super");
0892: } else if (TextAttribute.SUPERSCRIPT_SUB
0893: .equals(styledTextAttributes
0894: .get(TextAttribute.SUPERSCRIPT))) {
0895: writer.write("\\sub");
0896: }
0897:
0898: if (!(null == styleBackground || styleBackground
0899: .equals(bgcolor))) {
0900: writer.write("\\highlight");
0901: writer.write(String
0902: .valueOf(getColorIndex(styleBackground)));
0903: }
0904: writer.write("\\cf");
0905: writer
0906: .write(String
0907: .valueOf(getColorIndex(styleForeground)));
0908: writer.write(" ");
0909:
0910: String str = plainText.substring(iterator.getIndex(),
0911: runLimit);
0912:
0913: StringBuffer result = new StringBuffer(str);
0914: writer
0915: .write(handleUnicodeText(
0916: result,
0917: text.getRunDirection() == JRPrintText.RUN_DIRECTION_RTL));
0918:
0919: // reset all styles in the paragraph
0920: writer.write("\\plain");
0921:
0922: iterator.setIndex(runLimit);
0923: }
0924: if (startedHyperlink) {
0925: endHyperlink();
0926: }
0927:
0928: if (isUnicode) {
0929: writer.write("\\par}\n");
0930: } else {
0931: writer.write("\\par}}}\n");
0932: }
0933:
0934: exportBox(text, x, y, width, height, text.getForecolor(),
0935: bgcolor);
0936: }
0937:
0938: /**
0939: * Replace Unicode characters with RTF Unicode control words
0940: * @param source source text
0941: * @return text with Unicode characters replaced
0942: */
0943: private String handleUnicodeText(StringBuffer source,
0944: boolean isRightToLeft) {
0945: StringBuffer resultBuffer = new StringBuffer();
0946: StringBuffer leftToRightBuffer = new StringBuffer();
0947:
0948: for (int i = 0; i < source.length(); i++) {
0949: long ch = source.charAt(i);
0950: if (ch > 127) {
0951: if (isRightToLeft) {
0952: resultBuffer
0953: .insert(0, leftToRightBuffer.toString());
0954: leftToRightBuffer = new StringBuffer();
0955:
0956: resultBuffer.insert(0, "\\u" + ch + '?');
0957: } else {
0958: leftToRightBuffer.append("\\u" + ch + '?');
0959: }
0960: } else {
0961: if (ch == '\n') {
0962: leftToRightBuffer.append("\\line ");
0963: } else if (ch == '\\' || ch == '{' || ch == '}') {
0964: leftToRightBuffer.append('\\').append((char) ch);
0965: } else {
0966: leftToRightBuffer.append((char) ch);
0967: }
0968: }
0969: }
0970:
0971: if (leftToRightBuffer != null && leftToRightBuffer.length() > 0) {
0972: if (isRightToLeft) {
0973: resultBuffer.insert(0, leftToRightBuffer.toString());
0974: } else {
0975: resultBuffer.append(leftToRightBuffer.toString());
0976: }
0977: }
0978:
0979: return resultBuffer.toString();
0980: }
0981:
0982: /**
0983: * Export a image object
0984: * @param printImage JasperReports image object (JRPrintImage)
0985: * @throws JRException
0986: * @throws IOException
0987: */
0988: protected void exportImage(JRPrintImage printImage)
0989: throws JRException, IOException {
0990: int x = twip(printImage.getX() + globalOffsetX);
0991: int y = twip(printImage.getY() + globalOffsetY);
0992: int width = twip(printImage.getWidth());
0993: int height = twip(printImage.getHeight());
0994:
0995: if (printImage.getMode() == JRElement.MODE_OPAQUE) {
0996: startGraphic("dprect", x, y, width, height);
0997: finishGraphic(JRGraphicElement.PEN_NONE, printImage
0998: .getForecolor(), printImage.getBackcolor(), 1);
0999: }
1000:
1001: int leftPadding = printImage.getLeftPadding();
1002: int topPadding = printImage.getTopPadding();
1003: int rightPadding = printImage.getRightPadding();
1004: int bottomPadding = printImage.getBottomPadding();
1005:
1006: int availableImageWidth = printImage.getWidth() - leftPadding
1007: - rightPadding;
1008: availableImageWidth = availableImageWidth < 0 ? 0
1009: : availableImageWidth;
1010:
1011: int availableImageHeight = printImage.getHeight() - topPadding
1012: - bottomPadding;
1013: availableImageHeight = availableImageHeight < 0 ? 0
1014: : availableImageHeight;
1015:
1016: JRRenderable renderer = printImage.getRenderer();
1017:
1018: if (renderer != null && availableImageWidth > 0
1019: && availableImageHeight > 0) {
1020: if (renderer.getType() == JRRenderable.TYPE_IMAGE) {
1021: // Image renderers are all asked for their image data at some point.
1022: // Better to test and replace the renderer now, in case of lazy load error.
1023: renderer = JRImageRenderer
1024: .getOnErrorRendererForImageData(renderer,
1025: printImage.getOnErrorType());
1026: }
1027: } else {
1028: renderer = null;
1029: }
1030:
1031: if (renderer != null) {
1032: if (renderer.getType() == JRRenderable.TYPE_SVG) {
1033: renderer = new JRWrappingSvgRenderer(
1034: renderer,
1035: new Dimension(printImage.getWidth(), printImage
1036: .getHeight()),
1037: JRElement.MODE_OPAQUE == printImage.getMode() ? printImage
1038: .getBackcolor()
1039: : null);
1040: }
1041:
1042: int normalWidth = availableImageWidth;
1043: int normalHeight = availableImageHeight;
1044:
1045: // Image load might fail.
1046: JRRenderable tmpRenderer = JRImageRenderer
1047: .getOnErrorRendererForDimension(renderer,
1048: printImage.getOnErrorType());
1049: Dimension2D dimension = tmpRenderer == null ? null
1050: : tmpRenderer.getDimension();
1051: // If renderer was replaced, ignore image dimension.
1052: if (tmpRenderer == renderer && dimension != null) {
1053: normalWidth = (int) dimension.getWidth();
1054: normalHeight = (int) dimension.getHeight();
1055: }
1056:
1057: float xalignFactor = getXAlignFactor(printImage);
1058: float yalignFactor = getYAlignFactor(printImage);
1059:
1060: int imageWidth = 0;
1061: int imageHeight = 0;
1062: int xoffset = 0;
1063: int yoffset = 0;
1064: int cropt = 0;
1065: int cropl = 0;
1066:
1067: switch (printImage.getScaleImage()) {
1068: case JRImage.SCALE_IMAGE_CLIP: {
1069: cropl = -(int) (xalignFactor * (availableImageWidth - normalWidth));
1070: cropt = -(int) (yalignFactor * (availableImageHeight - normalHeight));
1071: imageWidth = availableImageWidth;
1072: imageHeight = availableImageHeight;
1073: break;
1074: }
1075: case JRImage.SCALE_IMAGE_FILL_FRAME: {
1076: normalWidth = availableImageWidth;
1077: normalHeight = availableImageHeight;
1078: imageWidth = availableImageWidth;
1079: imageHeight = availableImageHeight;
1080: break;
1081: }
1082: case JRImage.SCALE_IMAGE_RETAIN_SHAPE:
1083: default: {
1084: if (printImage.getHeight() > 0) {
1085: double ratio = (double) normalWidth
1086: / (double) normalHeight;
1087:
1088: if (ratio > (double) availableImageWidth
1089: / (double) availableImageHeight) {
1090: normalWidth = availableImageWidth;
1091: normalHeight = (int) (availableImageWidth / ratio);
1092: } else {
1093: normalWidth = (int) (availableImageHeight * ratio);
1094: normalHeight = availableImageHeight;
1095: }
1096:
1097: xoffset = (int) (xalignFactor * (availableImageWidth - normalWidth));
1098: yoffset = (int) (yalignFactor * (availableImageHeight - normalHeight));
1099: imageWidth = normalWidth;
1100: imageHeight = normalHeight;
1101: }
1102:
1103: break;
1104: }
1105: }
1106:
1107: writer.write("{\\*\\do\\dobxpage\\dobypage\\dodhgt");
1108: writer.write(String.valueOf(zorder++));
1109: writer.write("\\dptxbx\\dpx");
1110: writer.write(String.valueOf(twip(printImage.getX()
1111: + leftPadding + xoffset + getOffsetX())));
1112: writer.write("\\dpxsize");
1113: writer.write(String.valueOf(twip(imageWidth)));
1114: writer.write("\\dpy");
1115: writer.write(String.valueOf(twip(printImage.getY()
1116: + topPadding + yoffset + getOffsetY())));
1117: writer.write("\\dpysize");
1118: writer.write(String.valueOf(twip(imageHeight)));
1119: writer.write("\\dpfillpat0\\dplinehollow{\\dptxbxtext ");
1120: if (printImage.getAnchorName() != null) {
1121: writeAnchor(printImage.getAnchorName());
1122: }
1123: boolean startedHyperlink = startHyperlink(printImage);
1124:
1125: writer.write("{\\pict\\jpegblip");
1126: writer.write("\\picwgoal");
1127: writer.write(String.valueOf(twip(normalWidth)));
1128: writer.write("\\pichgoal");
1129: writer.write(String.valueOf(twip(normalHeight)));
1130: writer.write("\\piccropt");
1131: writer.write(String.valueOf(twip(cropt)));
1132: writer.write("\\piccropl");
1133: writer.write(String.valueOf(twip(cropl)));
1134: writer.write("\n");
1135:
1136: ByteArrayInputStream bais = new ByteArrayInputStream(
1137: renderer.getImageData());
1138:
1139: int count = 0;
1140: int current = 0;
1141: while ((current = bais.read()) != -1) {
1142: String helperStr = Integer.toHexString(current);
1143: if (helperStr.length() < 2) {
1144: helperStr = "0" + helperStr;
1145: }
1146: writer.write(helperStr);
1147: count++;
1148: if (count == 64) {
1149: writer.write("\n");
1150: count = 0;
1151: }
1152: }
1153:
1154: writer.write("\n}");
1155: if (startedHyperlink)
1156: endHyperlink();
1157: writer.write("}}\n");
1158: }
1159:
1160: if (printImage.getTopBorder() == JRGraphicElement.PEN_NONE
1161: && printImage.getLeftBorder() == JRGraphicElement.PEN_NONE
1162: && printImage.getBottomBorder() == JRGraphicElement.PEN_NONE
1163: && printImage.getRightBorder() == JRGraphicElement.PEN_NONE) {
1164: if (printImage.getPen() != JRGraphicElement.PEN_NONE) {
1165: startGraphic("dprect", x, y, width, height);
1166: finishGraphic(printImage);
1167: }
1168: } else {
1169: exportBox(printImage, x, y, width, height, printImage
1170: .getForecolor(), printImage.getBackcolor());
1171: }
1172: }
1173:
1174: /**
1175: *
1176: * @param frame
1177: * @throws JRException
1178: */
1179: protected void exportFrame(JRPrintFrame frame) throws JRException,
1180: IOException {
1181: int x = twip(frame.getX() + getOffsetX());
1182: int y = twip(frame.getY() + getOffsetY());
1183: int width = twip(frame.getWidth());
1184: int height = twip(frame.getHeight());
1185:
1186: if (frame.getMode() == JRElement.MODE_OPAQUE) {
1187: startGraphic("dprect", x, y, width, height);
1188: finishGraphic(JRGraphicElement.PEN_NONE, frame
1189: .getForecolor(), frame.getBackcolor(), 1);
1190: }
1191:
1192: setFrameElementsOffset(frame, false);
1193: exportElements(frame.getElements());
1194: restoreElementOffsets();
1195:
1196: exportBox(frame, x, y, width, height, frame.getForecolor(),
1197: frame.getBackcolor());
1198: }
1199:
1200: protected void exportElements(Collection elements)
1201: throws JRException, IOException {
1202: if (elements != null && elements.size() > 0) {
1203: for (Iterator it = elements.iterator(); it.hasNext();) {
1204: JRPrintElement element = (JRPrintElement) it.next();
1205: if (element instanceof JRPrintLine) {
1206: exportLine((JRPrintLine) element);
1207: } else if (element instanceof JRPrintRectangle) {
1208: exportRectangle((JRPrintRectangle) element);
1209: } else if (element instanceof JRPrintEllipse) {
1210: exportEllipse((JRPrintEllipse) element);
1211: } else if (element instanceof JRPrintImage) {
1212: exportImage((JRPrintImage) element);
1213: } else if (element instanceof JRPrintText) {
1214: exportText((JRPrintText) element);
1215: } else if (element instanceof JRPrintFrame) {
1216: exportFrame((JRPrintFrame) element);
1217: }
1218: }
1219: }
1220: }
1221:
1222: /**
1223: * Exports a JRBox that represents the border of a JasperReports object
1224: * @param box
1225: * @param x
1226: * @param y
1227: * @param width
1228: * @param height
1229: * @param fg
1230: * @param bg
1231: * @throws IOException
1232: */
1233: private void exportBox(JRBox box, int x, int y, int width,
1234: int height, Color fg, Color bg) throws IOException {
1235:
1236: if (box.getTopBorder() != JRGraphicElement.PEN_NONE) {
1237: Color bc = box.getTopBorderColor();
1238: byte pen = box.getTopBorder();
1239:
1240: int a = getAdjustment(box.getTopBorder());
1241: if (bc == null) {
1242: bc = fg;
1243: }
1244: startGraphic("dpline", x, y + a, width, 0);
1245: finishGraphic(pen, bc, bg, 1);
1246:
1247: }
1248: if (box.getLeftBorder() != JRGraphicElement.PEN_NONE) {
1249: Color bc = box.getLeftBorderColor();
1250: byte pen = box.getLeftBorder();
1251: int a = getAdjustment(pen);
1252: if (bc == null)
1253: bc = fg;
1254: startGraphic("dpline", x + a, y, 0, height);
1255: finishGraphic(pen, bc, bg, 1);
1256:
1257: }
1258:
1259: if (box.getBottomBorder() != JRGraphicElement.PEN_NONE) {
1260: Color bc = box.getBottomBorderColor();
1261: byte pen = box.getBottomBorder();
1262: int a = getAdjustment(pen);
1263: if (bc == null)
1264: bc = fg;
1265: startGraphic("dpline", x, y + height - a, width, 0);
1266: finishGraphic(pen, bc, bg, 1);
1267: }
1268:
1269: if (box.getRightBorder() != JRGraphicElement.PEN_NONE) {
1270: Color bc = box.getRightBorderColor();
1271: byte pen = box.getRightBorder();
1272: int a = getAdjustment(pen);
1273: if (bc == null)
1274: bc = fg;
1275: startGraphic("dpline", x + width - a, y, 0, height);
1276: finishGraphic(pen, bc, bg, 1);
1277: }
1278: }
1279:
1280: protected boolean startHyperlink(JRPrintHyperlink link)
1281: throws IOException {
1282: String href = getHyperlinkURL(link);
1283: boolean isHref = (href != null);
1284:
1285: if (isHref) {
1286: writer.write("{\\field {\\*\\fldinst HYPERLINK ");
1287: writer.write(href);
1288: writer.write("}{\\fldrslt ");
1289: }
1290:
1291: return isHref;
1292: }
1293:
1294: protected String getHyperlinkURL(JRPrintHyperlink link) {
1295: String href = null;
1296: JRHyperlinkProducer customHandler = getCustomHandler(link);
1297: if (customHandler == null) {
1298: switch (link.getHyperlinkType()) {
1299: case JRHyperlink.HYPERLINK_TYPE_REFERENCE: {
1300: if (link.getHyperlinkReference() != null) {
1301: href = link.getHyperlinkReference();
1302: }
1303: break;
1304: }
1305: case JRHyperlink.HYPERLINK_TYPE_LOCAL_ANCHOR: {
1306: if (link.getHyperlinkAnchor() != null) {
1307: href = "\\\\l " + link.getHyperlinkAnchor();
1308: }
1309: break;
1310: }
1311: case JRHyperlink.HYPERLINK_TYPE_LOCAL_PAGE: {
1312: if (link.getHyperlinkPage() != null) {
1313: href = "\\\\l " + JR_PAGE_ANCHOR_PREFIX
1314: + reportIndex + "_"
1315: + link.getHyperlinkPage().toString();
1316: }
1317: break;
1318: }
1319: case JRHyperlink.HYPERLINK_TYPE_REMOTE_ANCHOR: {
1320: if (link.getHyperlinkReference() != null
1321: && link.getHyperlinkAnchor() != null) {
1322: href = link.getHyperlinkReference() + "#"
1323: + link.getHyperlinkAnchor();
1324: }
1325: break;
1326: }
1327: case JRHyperlink.HYPERLINK_TYPE_REMOTE_PAGE: {
1328: if (link.getHyperlinkReference() != null
1329: && link.getHyperlinkPage() != null) {
1330: href = link.getHyperlinkReference() + "#"
1331: + JR_PAGE_ANCHOR_PREFIX + "0_"
1332: + link.getHyperlinkPage().toString();
1333: }
1334: break;
1335: }
1336: case JRHyperlink.HYPERLINK_TYPE_NONE:
1337: default: {
1338: break;
1339: }
1340: }
1341: } else {
1342: href = customHandler.getHyperlink(link);
1343: }
1344:
1345: return href;
1346: }
1347:
1348: protected JRHyperlinkProducer getCustomHandler(JRPrintHyperlink link) {
1349: return hyperlinkProducerFactory == null ? null
1350: : hyperlinkProducerFactory.getHandler(link
1351: .getLinkType());
1352: }
1353:
1354: protected void endHyperlink() throws IOException {
1355: writer.write("}} ");
1356: }
1357:
1358: protected void writeAnchor(String anchorName) throws IOException {
1359: writer.write("{\\*\\bkmkstart ");
1360: writer.write(anchorName);
1361: writer.write("}{\\*\\bkmkend ");
1362: writer.write(anchorName);
1363: writer.write("}");
1364: }
1365:
1366: private float getXAlignFactor(JRPrintImage image) {
1367: float xalignFactor = 0f;
1368: switch (image.getHorizontalAlignment()) {
1369: case JRAlignment.HORIZONTAL_ALIGN_RIGHT: {
1370: xalignFactor = 1f;
1371: break;
1372: }
1373: case JRAlignment.HORIZONTAL_ALIGN_CENTER: {
1374: xalignFactor = 0.5f;
1375: break;
1376: }
1377: case JRAlignment.HORIZONTAL_ALIGN_LEFT:
1378: default: {
1379: xalignFactor = 0f;
1380: break;
1381: }
1382: }
1383: return xalignFactor;
1384: }
1385:
1386: private float getYAlignFactor(JRPrintImage image) {
1387: float yalignFactor = 0f;
1388: switch (image.getVerticalAlignment()) {
1389: case JRAlignment.VERTICAL_ALIGN_BOTTOM: {
1390: yalignFactor = 1f;
1391: break;
1392: }
1393: case JRAlignment.VERTICAL_ALIGN_MIDDLE: {
1394: yalignFactor = 0.5f;
1395: break;
1396: }
1397: case JRAlignment.VERTICAL_ALIGN_TOP:
1398: default: {
1399: yalignFactor = 0f;
1400: break;
1401: }
1402: }
1403: return yalignFactor;
1404: }
1405:
1406: }
|