net.sf.jasperreports.engine.export.ooxml.JRDocxExporter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jasperreports Show documentation
Show all versions of jasperreports Show documentation
Free Java Reporting Library
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see .
*/
package net.sf.jasperreports.engine.export.ooxml;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.font.TextAttribute;
import java.awt.geom.Dimension2D;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.text.AttributedCharacterIterator;
import java.text.AttributedCharacterIterator.Attribute;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.jasperreports.annotations.properties.Property;
import net.sf.jasperreports.annotations.properties.PropertyScope;
import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRAbstractExporter;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRGenericElementType;
import net.sf.jasperreports.engine.JRGenericPrintElement;
import net.sf.jasperreports.engine.JRLineBox;
import net.sf.jasperreports.engine.JRPen;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPrintElementIndex;
import net.sf.jasperreports.engine.JRPrintEllipse;
import net.sf.jasperreports.engine.JRPrintFrame;
import net.sf.jasperreports.engine.JRPrintHyperlink;
import net.sf.jasperreports.engine.JRPrintImage;
import net.sf.jasperreports.engine.JRPrintLine;
import net.sf.jasperreports.engine.JRPrintPage;
import net.sf.jasperreports.engine.JRPrintRectangle;
import net.sf.jasperreports.engine.JRPrintText;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.JRStyle;
import net.sf.jasperreports.engine.JasperReportsContext;
import net.sf.jasperreports.engine.PrintPageFormat;
import net.sf.jasperreports.engine.base.JRBaseLineBox;
import net.sf.jasperreports.engine.export.CutsInfo;
import net.sf.jasperreports.engine.export.ElementGridCell;
import net.sf.jasperreports.engine.export.ExporterNature;
import net.sf.jasperreports.engine.export.GenericElementHandlerEnviroment;
import net.sf.jasperreports.engine.export.Grid;
import net.sf.jasperreports.engine.export.GridRow;
import net.sf.jasperreports.engine.export.HyperlinkUtil;
import net.sf.jasperreports.engine.export.JRExportProgressMonitor;
import net.sf.jasperreports.engine.export.JRExporterGridCell;
import net.sf.jasperreports.engine.export.JRGridLayout;
import net.sf.jasperreports.engine.export.JRHyperlinkProducer;
import net.sf.jasperreports.engine.export.JRXmlExporter;
import net.sf.jasperreports.engine.export.LengthUtil;
import net.sf.jasperreports.engine.export.OccupiedGridCell;
import net.sf.jasperreports.engine.export.zip.FileBufferedZipEntry;
import net.sf.jasperreports.engine.type.HorizontalTextAlignEnum;
import net.sf.jasperreports.engine.type.HyperlinkTypeEnum;
import net.sf.jasperreports.engine.type.LineDirectionEnum;
import net.sf.jasperreports.engine.type.ModeEnum;
import net.sf.jasperreports.engine.type.RotationEnum;
import net.sf.jasperreports.engine.type.ScaleImageEnum;
import net.sf.jasperreports.engine.util.JRStringUtil;
import net.sf.jasperreports.engine.util.JRStyledText;
import net.sf.jasperreports.engine.util.JRTextAttribute;
import net.sf.jasperreports.engine.util.JRTypeSniffer;
import net.sf.jasperreports.export.DocxExporterConfiguration;
import net.sf.jasperreports.export.DocxReportConfiguration;
import net.sf.jasperreports.export.ExportInterruptedException;
import net.sf.jasperreports.export.ExporterInputItem;
import net.sf.jasperreports.export.OutputStreamExporterOutput;
import net.sf.jasperreports.export.ReportExportConfiguration;
import net.sf.jasperreports.properties.PropertyConstants;
import net.sf.jasperreports.renderers.DataRenderable;
import net.sf.jasperreports.renderers.DimensionRenderable;
import net.sf.jasperreports.renderers.Renderable;
import net.sf.jasperreports.renderers.RenderersCache;
import net.sf.jasperreports.renderers.ResourceRenderer;
/**
* Exports a JasperReports document to DOCX format. It has binary output type and exports the document to a
* grid-based layout, therefore having the known limitations of grid exporters.
*
* It can work in batch mode and supports all types of
* exporter input and output, content filtering, and font mappings.
*
* Currently, there are the following special configurations that can be made to a DOCX
* exporter instance (see {@link net.sf.jasperreports.export.DocxReportConfiguration}):
*
* - Forcing the use of nested tables to render the content of frame elements using either
* the {@link net.sf.jasperreports.export.DocxReportConfiguration#isFramesAsNestedTables() isFramesAsNestedTables()}
* exporter configuration flag or its corresponding exporter hint called
* {@link net.sf.jasperreports.export.DocxReportConfiguration#PROPERTY_FRAMES_AS_NESTED_TABLES net.sf.jasperreports.export.docx.frames.as.nested.tables}.
* - Allowing table rows to adjust their height if more text is typed into their cells using
* the Word editor. This is controlled using either the
* {@link net.sf.jasperreports.export.DocxReportConfiguration#isFlexibleRowHeight() isFlexibleRowHeight()}
* exporter configuration flag, or its corresponding exporter hint called
* {@link net.sf.jasperreports.export.DocxReportConfiguration#PROPERTY_FLEXIBLE_ROW_HEIGHT net.sf.jasperreports.export.docx.flexible.row.height}.
* - Ignoring hyperlinks in generated documents if they are not intended for the DOCX output format. This can be
* customized using either the
* {@link net.sf.jasperreports.export.DocxReportConfiguration#isIgnoreHyperlink() isIgnoreHyperlink()}
* exporter configuration flag, or its corresponding exporter hint called
* {@link net.sf.jasperreports.export.DocxReportConfiguration#PROPERTY_IGNORE_HYPERLINK net.sf.jasperreports.export.docx.ignore.hyperlink}
*
*
* @see net.sf.jasperreports.export.DocxReportConfiguration
* @author Sanda Zaharia ([email protected])
*/
public class JRDocxExporter extends JRAbstractExporter
{
private static final Log log = LogFactory.getLog(JRDocxExporter.class);
/**
* The exporter key, as used in
* {@link GenericElementHandlerEnviroment#getElementHandler(JRGenericElementType, String)}.
*/
public static final String DOCX_EXPORTER_KEY = JRPropertiesUtil.PROPERTY_PREFIX + "docx";
public static final String EXCEPTION_MESSAGE_KEY_COLUMN_COUNT_OUT_OF_RANGE = "export.docx.column.count.out.of.range";
public static final String DOCX_EXPORTER_PROPERTIES_PREFIX = JRPropertiesUtil.PROPERTY_PREFIX + "export.docx.";
/**
* This property is used to mark text elements as being hidden either for printing or on-screen display.
* @see JRPropertiesUtil
*/
@Property(
category = PropertyConstants.CATEGORY_EXPORT,
defaultValue = PropertyConstants.BOOLEAN_FALSE,
scopes = {PropertyScope.TEXT_ELEMENT},
sinceVersion = PropertyConstants.VERSION_3_7_6,
valueType = Boolean.class
)
public static final String PROPERTY_HIDDEN_TEXT = DOCX_EXPORTER_PROPERTIES_PREFIX + "hidden.text";
/**
*
*/
public static final String JR_PAGE_ANCHOR_PREFIX = "JR_PAGE_ANCHOR_";
/**
*
*/
public static final String IMAGE_NAME_PREFIX = "img_";
protected static final int IMAGE_NAME_PREFIX_LEGTH = IMAGE_NAME_PREFIX.length();
public static final String IMAGE_LINK_PREFIX = "link_" + IMAGE_NAME_PREFIX;
/**
*
*/
protected DocxZip docxZip;
protected DocxDocumentHelper docHelper;
protected Writer docWriter;
protected Map rendererToImagePathMap;
protected RenderersCache renderersCache;
// protected Map imageMaps;
protected int reportIndex;
protected int pageIndex;
protected int startPageIndex;
protected int endPageIndex;
protected int tableIndex;
protected boolean startPage;
protected String invalidCharReplacement;
protected PrintPageFormat pageFormat;
protected JRGridLayout pageGridLayout;
protected LinkedList backcolorStack = new LinkedList();
protected Color backcolor;
protected DocxRunHelper runHelper;
protected ExporterNature nature;
protected long bookmarkIndex;
protected String pageAnchor;
protected DocxRelsHelper relsHelper;
protected PropsAppHelper appHelper;
protected PropsCoreHelper coreHelper;
protected DocxFontHelper docxFontHelper;
protected DocxFontTableHelper docxFontTableHelper;
protected DocxFontTableRelsHelper docxFontTableRelsHelper;
boolean emptyPageState;
protected class ExporterContext extends BaseExporterContext implements JRDocxExporterContext
{
DocxTableHelper tableHelper = null;
public ExporterContext(DocxTableHelper tableHelper)
{
this.tableHelper = tableHelper;
}
@Override
public DocxTableHelper getTableHelper()
{
return tableHelper;
}
}
/**
* @see #JRDocxExporter(JasperReportsContext)
*/
public JRDocxExporter()
{
this(DefaultJasperReportsContext.getInstance());
}
/**
*
*/
public JRDocxExporter(JasperReportsContext jasperReportsContext)
{
super(jasperReportsContext);
exporterContext = new ExporterContext(null);
}
@Override
protected Class getConfigurationInterface()
{
return DocxExporterConfiguration.class;
}
@Override
protected Class getItemConfigurationInterface()
{
return DocxReportConfiguration.class;
}
@Override
@SuppressWarnings("deprecation")
protected void ensureOutput()
{
if (exporterOutput == null)
{
exporterOutput =
new net.sf.jasperreports.export.parameters.ParametersOutputStreamExporterOutput(
getJasperReportsContext(),
getParameters(),
getCurrentJasperPrint()
);
}
}
@Override
public void exportReport() throws JRException
{
/* */
ensureJasperReportsContext();
ensureInput();
initExport();
ensureOutput();
OutputStream outputStream = getExporterOutput().getOutputStream();
try
{
exportReportToStream(outputStream);
}
catch (IOException e)
{
throw new JRRuntimeException(e);
}
finally
{
getExporterOutput().close();
resetExportContext();
}
}
@Override
protected void initExport()
{
super.initExport();
rendererToImagePathMap = new HashMap();//FIXMEIMAGE why this is reset at export and not report; are there any others?
// imageMaps = new HashMap();
// hyperlinksMap = new HashMap();
}
@Override
protected void initReport()
{
super.initReport();
if (jasperPrint.hasProperties() && jasperPrint.getPropertiesMap().containsProperty(JRXmlExporter.PROPERTY_REPLACE_INVALID_CHARS))
{
// allows null values for the property
invalidCharReplacement = jasperPrint.getProperty(JRXmlExporter.PROPERTY_REPLACE_INVALID_CHARS);
}
else
{
invalidCharReplacement = getPropertiesUtil().getProperty(JRXmlExporter.PROPERTY_REPLACE_INVALID_CHARS, jasperPrint);
}
DocxReportConfiguration configuration = getCurrentItemConfiguration();
nature =
new JRDocxExporterNature(
jasperReportsContext,
filter,
!configuration.isFramesAsNestedTables()
);
renderersCache = new RenderersCache(getJasperReportsContext());
}
/**
*
*/
protected void exportReportToStream(OutputStream os) throws JRException, IOException
{
docxZip = new DocxZip();
docWriter = docxZip.getDocumentEntry().getWriter();
docHelper = new DocxDocumentHelper(jasperReportsContext, docWriter);
docHelper.exportHeader();
relsHelper = new DocxRelsHelper(jasperReportsContext, docxZip.getRelsEntry().getWriter());
relsHelper.exportHeader();
appHelper = new PropsAppHelper(jasperReportsContext, docxZip.getAppEntry().getWriter());
coreHelper = new PropsCoreHelper(jasperReportsContext, docxZip.getCoreEntry().getWriter());
appHelper.exportHeader();
DocxExporterConfiguration configuration = getCurrentConfiguration();
String application = configuration.getMetadataApplication();
if( application == null )
{
application = "JasperReports Library version " + Package.getPackage("net.sf.jasperreports.engine").getImplementationVersion();
}
appHelper.exportProperty(PropsAppHelper.PROPERTY_APPLICATION, application);
coreHelper.exportHeader();
String title = configuration.getMetadataTitle();
if (title != null)
{
coreHelper.exportProperty(PropsCoreHelper.PROPERTY_TITLE, title);
}
String subject = configuration.getMetadataSubject();
if (subject != null)
{
coreHelper.exportProperty(PropsCoreHelper.PROPERTY_SUBJECT, subject);
}
String author = configuration.getMetadataAuthor();
if (author != null)
{
coreHelper.exportProperty(PropsCoreHelper.PROPERTY_CREATOR, author);
}
String keywords = configuration.getMetadataKeywords();
if (keywords != null)
{
coreHelper.exportProperty(PropsCoreHelper.PROPERTY_KEYWORDS, keywords);
}
List items = exporterInput.getItems();
boolean isEmbedFonts = Boolean.TRUE.equals(configuration.isEmbedFonts());
docxFontHelper =
new DocxFontHelper(
jasperReportsContext,
docxZip,
isEmbedFonts
);
DocxStyleHelper styleHelper =
new DocxStyleHelper(
this,
docxZip.getStylesEntry().getWriter(),
docxFontHelper
);
styleHelper.export(exporterInput);
styleHelper.close();
DocxSettingsHelper settingsHelper =
new DocxSettingsHelper(
jasperReportsContext,
docxZip.getSettingsEntry().getWriter()
);
settingsHelper.export(jasperPrint, isEmbedFonts);
settingsHelper.close();
docxFontTableHelper = new DocxFontTableHelper(jasperReportsContext, docxZip.getFontTableEntry().getWriter());
docxFontTableHelper.exportHeader();
docxFontTableRelsHelper = new DocxFontTableRelsHelper(jasperReportsContext, docxZip.getFontTableRelsEntry().getWriter());
docxFontTableRelsHelper.exportHeader();
runHelper = new DocxRunHelper(jasperReportsContext, docWriter, docxFontHelper);
pageFormat = null;
PrintPageFormat oldPageFormat = null;
for(reportIndex = 0; reportIndex < items.size(); reportIndex++)
{
ExporterInputItem item = items.get(reportIndex);
setCurrentExporterInputItem(item);
bookmarkIndex = 0;
emptyPageState = false;
List pages = jasperPrint.getPages();
if (pages != null && pages.size() > 0)
{
PageRange pageRange = getPageRange();
startPageIndex = (pageRange == null || pageRange.getStartPageIndex() == null) ? 0 : pageRange.getStartPageIndex();
endPageIndex = (pageRange == null || pageRange.getEndPageIndex() == null) ? (pages.size() - 1) : pageRange.getEndPageIndex();
JRPrintPage page = null;
for(pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++)
{
if (Thread.interrupted())
{
throw new ExportInterruptedException();
}
page = pages.get(pageIndex);
pageFormat = jasperPrint.getPageFormat(pageIndex);
if (oldPageFormat != null && oldPageFormat != pageFormat)
{
docHelper.exportSection(oldPageFormat, pageGridLayout, false);
}
exportPage(page);
oldPageFormat = pageFormat;
}
}
}
if (oldPageFormat != null)
{
docHelper.exportSection(oldPageFormat, pageGridLayout, true);
}
docHelper.exportFooter();
docHelper.close();
// if ((hyperlinksMap != null && hyperlinksMap.size() > 0))
// {
// for(Iterator it = hyperlinksMap.keySet().iterator(); it.hasNext();)
// {
// String href = (String)it.next();
// String id = (String)hyperlinksMap.get(href);
//
// relsHelper.exportHyperlink(id, href);
// }
// }
relsHelper.exportFooter();
relsHelper.close();
appHelper.exportFooter();
appHelper.close();
coreHelper.exportFooter();
coreHelper.close();
docxFontHelper.exportFonts();
docxFontTableHelper.exportFooter();
docxFontTableHelper.close();
docxFontTableRelsHelper.exportFooter();
docxFontTableRelsHelper.close();
docxZip.zipEntries(os);
docxZip.dispose();
}
/**
*
*/
protected void exportPage(JRPrintPage page) throws JRException
{
startPage = true;
pageAnchor = JR_PAGE_ANCHOR_PREFIX + reportIndex + "_" + (pageIndex + 1);
ReportExportConfiguration configuration = getCurrentItemConfiguration();
pageGridLayout =
new JRGridLayout(
nature,
page.getElements(),
pageFormat.getPageWidth(),
pageFormat.getPageHeight(),
configuration.getOffsetX() == null ? 0 : configuration.getOffsetX(),
configuration.getOffsetY() == null ? 0 : configuration.getOffsetY(),
null //address
);
exportGrid(pageGridLayout, null);
JRExportProgressMonitor progressMonitor = configuration.getProgressMonitor();
if (progressMonitor != null)
{
progressMonitor.afterPageExport();
}
}
/**
*
*/
protected void exportGrid(JRGridLayout gridLayout, JRPrintElementIndex frameIndex) throws JRException
{
CutsInfo xCuts = gridLayout.getXCuts();
Grid grid = gridLayout.getGrid();
DocxTableHelper tableHelper = null;
int rowCount = grid.getRowCount();
if (rowCount > 0 && grid.getColumnCount() > 63)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_COLUMN_COUNT_OUT_OF_RANGE,
new Object[]{grid.getColumnCount()}
);
}
// an empty page is encountered;
// if it's the first one in a series of consecutive empty pages, emptyPageState == false, otherwise emptyPageState == true
if (rowCount == 0 && (pageIndex < endPageIndex || !emptyPageState))
{
tableHelper =
new DocxTableHelper(
jasperReportsContext,
docWriter,
xCuts,
false,
pageFormat,
frameIndex
);
int maxReportIndex = exporterInput.getItems().size() - 1;
// while the first and last page in the JasperPrint list need single breaks, all the others require double-breaking
boolean twice =
(pageIndex > startPageIndex && pageIndex < endPageIndex && !emptyPageState)
||(reportIndex < maxReportIndex && pageIndex == endPageIndex);
tableHelper.getParagraphHelper().exportEmptyPage(pageAnchor, bookmarkIndex, twice);
bookmarkIndex++;
emptyPageState = true;
return;
}
tableHelper =
new DocxTableHelper(
jasperReportsContext,
docWriter,
xCuts,
frameIndex == null && (reportIndex != 0 || pageIndex != startPageIndex),
pageFormat,
frameIndex
);
tableHelper.exportHeader();
boolean isFlexibleRowHeight = getCurrentItemConfiguration().isFlexibleRowHeight();
for(int row = 0; row < rowCount; row++)
{
int emptyCellColSpan = 0;
//int emptyCellWidth = 0;
boolean allowRowResize = false;
int maxTopPadding = 0; //for some strange reason, the top margin applies to all cells in the row
int maxBottomPadding = 0; //for some strange reason, the bottom margin affects the row height; subtracting it here
GridRow gridRow = grid.getRow(row);
int rowSize = gridRow.size();
for(int col = 0; col < rowSize; col++)
{
JRExporterGridCell gridCell = gridRow.get(col);
JRLineBox box = gridCell.getBox();
if (box != null)
{
Integer topPadding = box.getTopPadding() + Math.round(box.getTopPen().getLineWidth());
if (
topPadding != null
&& maxTopPadding < topPadding
)
{
maxTopPadding = topPadding;
}
Integer bottomPadding = box.getBottomPadding();
if (
bottomPadding != null
&& maxBottomPadding < bottomPadding
)
{
maxBottomPadding = bottomPadding;
}
}
allowRowResize =
isFlexibleRowHeight
&& (allowRowResize
|| (gridCell.getElement() instanceof JRPrintText
|| (gridCell.getType() == JRExporterGridCell.TYPE_OCCUPIED_CELL
&& ((OccupiedGridCell)gridCell).getOccupier().getElement() instanceof JRPrintText)
)
);
}
tableHelper.setRowMaxTopPadding(maxTopPadding);
int rowHeight = gridLayout.getRowHeight(row) - maxBottomPadding;
if (row == 0 && frameIndex == null)
{
rowHeight -= Math.min(rowHeight, pageFormat.getTopMargin());
}
tableHelper.exportRowHeader(
rowHeight,
allowRowResize
);
for(int col = 0; col < rowSize; col++)
{
JRExporterGridCell gridCell = gridRow.get(col);
if (gridCell.getType() == JRExporterGridCell.TYPE_OCCUPIED_CELL)
{
if (emptyCellColSpan > 0)
{
//tableHelper.exportEmptyCell(gridCell, emptyCellColSpan);
emptyCellColSpan = 0;
//emptyCellWidth = 0;
}
OccupiedGridCell occupiedGridCell = (OccupiedGridCell)gridCell;
ElementGridCell elementGridCell = (ElementGridCell)occupiedGridCell.getOccupier();
tableHelper.exportOccupiedCells(elementGridCell, startPage, bookmarkIndex, pageAnchor);
if (startPage)
{
// increment the bookmarkIndex for the first cell in the sheet, due to page anchor creation
bookmarkIndex++;
}
col += elementGridCell.getColSpan() - 1;
}
else if (gridCell.getType() == JRExporterGridCell.TYPE_ELEMENT_CELL)
{
if (emptyCellColSpan > 0)
{
//writeEmptyCell(tableHelper, gridCell, emptyCellColSpan, emptyCellWidth, rowHeight);
emptyCellColSpan = 0;
//emptyCellWidth = 0;
}
JRPrintElement element = gridCell.getElement();
if (element instanceof JRPrintLine)
{
exportLine(tableHelper, (JRPrintLine)element, gridCell);
}
else if (element instanceof JRPrintRectangle)
{
exportRectangle(tableHelper, (JRPrintRectangle)element, gridCell);
}
else if (element instanceof JRPrintEllipse)
{
exportEllipse(tableHelper, (JRPrintEllipse)element, gridCell);
}
else if (element instanceof JRPrintImage)
{
exportImage(tableHelper, (JRPrintImage)element, gridCell);
}
else if (element instanceof JRPrintText)
{
exportText(tableHelper, (JRPrintText)element, gridCell);
}
else if (element instanceof JRPrintFrame)
{
exportFrame(tableHelper, (JRPrintFrame)element, gridCell);
}
else if (element instanceof JRGenericPrintElement)
{
exportGenericElement(tableHelper, (JRGenericPrintElement)element, gridCell);
}
col += gridCell.getColSpan() - 1;
}
else
{
emptyCellColSpan++;
//emptyCellWidth += gridCell.getWidth();
tableHelper.exportEmptyCell(gridCell, 1, startPage, bookmarkIndex, pageAnchor);
if (startPage)
{
// increment the bookmarkIndex for the first cell in the sheet, due to page anchor creation
bookmarkIndex++;
}
}
startPage = false;
}
// if (emptyCellColSpan > 0)
// {
// //writeEmptyCell(tableHelper, null, emptyCellColSpan, emptyCellWidth, rowHeight);
// }
tableHelper.exportRowFooter();
}
tableHelper.exportFooter();
// if a non-empty page was exported, the series of previous empty pages is ended
emptyPageState = false;
}
/**
*
*/
protected void exportLine(DocxTableHelper tableHelper, JRPrintLine line, JRExporterGridCell gridCell)
{
JRLineBox box = new JRBaseLineBox(null);
JRPen pen = null;
float ratio = line.getWidth() / line.getHeight();
if (ratio > 1)
{
if (line.getDirectionValue() == LineDirectionEnum.TOP_DOWN)
{
pen = box.getTopPen();
}
else
{
pen = box.getBottomPen();
}
}
else
{
if (line.getDirectionValue() == LineDirectionEnum.TOP_DOWN)
{
pen = box.getLeftPen();
}
else
{
pen = box.getRightPen();
}
}
pen.setLineColor(line.getLinePen().getLineColor());
pen.setLineStyle(line.getLinePen().getLineStyleValue());
pen.setLineWidth(line.getLinePen().getLineWidth());
gridCell.setBox(box);//CAUTION: only some exporters set the cell box
tableHelper.getCellHelper().exportHeader(line, gridCell);
tableHelper.getParagraphHelper().exportEmptyParagraph(startPage, bookmarkIndex, pageAnchor);
if (startPage)
{
// increment the bookmarkIndex for the first cell in the sheet, due to page anchor creation
bookmarkIndex++;
}
tableHelper.getCellHelper().exportFooter();
}
/**
*
*/
protected void exportRectangle(DocxTableHelper tableHelper, JRPrintRectangle rectangle, JRExporterGridCell gridCell)
{
JRLineBox box = new JRBaseLineBox(null);
JRPen pen = box.getPen();
pen.setLineColor(rectangle.getLinePen().getLineColor());
pen.setLineStyle(rectangle.getLinePen().getLineStyleValue());
pen.setLineWidth(rectangle.getLinePen().getLineWidth());
gridCell.setBox(box);//CAUTION: only some exporters set the cell box
tableHelper.getCellHelper().exportHeader(rectangle, gridCell);
tableHelper.getParagraphHelper().exportEmptyParagraph(startPage, bookmarkIndex, pageAnchor);
if (startPage)
{
// increment the bookmarkIndex for the first cell in the sheet, due to page anchor creation
bookmarkIndex++;
}
tableHelper.getCellHelper().exportFooter();
}
/**
*
*/
protected void exportEllipse(DocxTableHelper tableHelper, JRPrintEllipse ellipse, JRExporterGridCell gridCell)
{
JRLineBox box = new JRBaseLineBox(null);
JRPen pen = box.getPen();
pen.setLineColor(ellipse.getLinePen().getLineColor());
pen.setLineStyle(ellipse.getLinePen().getLineStyleValue());
pen.setLineWidth(ellipse.getLinePen().getLineWidth());
gridCell.setBox(box);//CAUTION: only some exporters set the cell box
tableHelper.getCellHelper().exportHeader(ellipse, gridCell);
tableHelper.getParagraphHelper().exportEmptyParagraph(startPage, bookmarkIndex, pageAnchor);
if (startPage)
{
// increment the bookmarkIndex for the first cell in the sheet, due to page anchor creation
bookmarkIndex++;
}
tableHelper.getCellHelper().exportFooter();
}
/**
*
*/
public void exportText(DocxTableHelper tableHelper, JRPrintText text, JRExporterGridCell gridCell)
{
tableHelper.getCellHelper().exportHeader(text, gridCell);
JRStyledText styledText = getStyledText(text);
int textLength = 0;
if (styledText != null)
{
textLength = styledText.length();
}
// if (styleBuffer.length() > 0)
// {
// writer.write(" style=\"");
// writer.write(styleBuffer.toString());
// writer.write("\"");
// }
//
// writer.write(">");
docHelper.write(" \n");
tableHelper.getParagraphHelper().exportProps(text);
if (startPage)
{
insertBookmark(pageAnchor, docHelper);
}
if (text.getAnchorName() != null)
{
insertBookmark(text.getAnchorName(), docHelper);
}
boolean startedHyperlink = startHyperlink(text, true);
boolean isNewLineAsParagraph = false;
if (HorizontalTextAlignEnum.JUSTIFIED.equals(text.getHorizontalTextAlign()))
{
if (text.hasProperties() && text.getPropertiesMap().containsProperty(DocxReportConfiguration.PROPERTY_NEW_LINE_AS_PARAGRAPH))
{
isNewLineAsParagraph = getPropertiesUtil().getBooleanProperty(text, DocxReportConfiguration.PROPERTY_NEW_LINE_AS_PARAGRAPH, false);
}
else
{
isNewLineAsParagraph = getCurrentItemConfiguration().isNewLineAsParagraph();
}
}
if (textLength > 0)
{
exportStyledText(
getCurrentJasperPrint().getDefaultStyleProvider().getStyleResolver().getBaseStyle(text),
styledText,
getTextLocale(text),
getPropertiesUtil().getBooleanProperty(text, PROPERTY_HIDDEN_TEXT, false),
startedHyperlink,
isNewLineAsParagraph
);
}
if (startedHyperlink)
{
endHyperlink(true);
}
docHelper.write(" \n");
tableHelper.getCellHelper().exportFooter();
}
/**
*
*/
protected void exportStyledText(JRStyle style, JRStyledText styledText, Locale locale, boolean hiddenText, boolean startedHyperlink, boolean isNewLineJustified)
{
Color elementBackcolor = null;
Map globalAttributes = styledText.getGlobalAttributes();
if (globalAttributes != null)
{
elementBackcolor = (Color)styledText.getGlobalAttributes().get(TextAttribute.BACKGROUND);
}
String text = styledText.getText();
int runLimit = 0;
AttributedCharacterIterator iterator = styledText.getAttributedString().getIterator();
while(runLimit < styledText.length() && (runLimit = iterator.getRunLimit()) <= styledText.length())
{
Map attributes = iterator.getAttributes();
boolean localHyperlink = false;
if (!startedHyperlink)
{
JRPrintHyperlink hyperlink = (JRPrintHyperlink)attributes.get(JRTextAttribute.HYPERLINK);
if (hyperlink != null)
{
localHyperlink = startHyperlink(hyperlink, true);
}
}
runHelper.export(
style,
iterator.getAttributes(),
text.substring(iterator.getIndex(), runLimit),
locale,
hiddenText,
invalidCharReplacement,
elementBackcolor,
isNewLineJustified
);
if (localHyperlink)
{
endHyperlink(true);
}
iterator.setIndex(runLimit);
}
}
/**
*
*/
public void exportImage(DocxTableHelper tableHelper, JRPrintImage image, JRExporterGridCell gridCell) throws JRException
{
int leftPadding = image.getLineBox().getLeftPadding();
int topPadding = image.getLineBox().getTopPadding() + Math.round(image.getLineBox().getTopPen().getLineWidth()); // top border eats into cell space
int rightPadding = image.getLineBox().getRightPadding();
int bottomPadding = image.getLineBox().getBottomPadding();
int availableImageWidth = image.getWidth() - leftPadding - rightPadding;
availableImageWidth = availableImageWidth < 0 ? 0 : availableImageWidth;
int availableImageHeight = image.getHeight() - topPadding - bottomPadding;
availableImageHeight = availableImageHeight < 0 ? 0 : availableImageHeight;
tableHelper.getCellHelper().exportHeader(image, gridCell);
docHelper.write("\n");//FIXMEDOCX why is this here and not further down?
tableHelper.getParagraphHelper().exportProps(image);
Renderable renderer = image.getRenderer();
if (
renderer != null
&& availableImageWidth > 0
&& availableImageHeight > 0
)
{
InternalImageProcessor imageProcessor =
new InternalImageProcessor(
image,
gridCell,
availableImageWidth,
availableImageHeight
);
InternalImageProcessorResult imageProcessorResult = null;
try
{
imageProcessorResult = imageProcessor.process(renderer);
}
catch (Exception e)
{
Renderable onErrorRenderer = getRendererUtil().handleImageError(e, image.getOnErrorTypeValue());
if (onErrorRenderer != null)
{
imageProcessorResult = imageProcessor.process(onErrorRenderer);
}
}
if (imageProcessorResult != null)
{
int renderWidth = availableImageWidth;
int renderHeight = availableImageHeight;
float xoffset = 0;
float yoffset = 0;
double cropTop = 0;
double cropLeft = 0;
double cropBottom = 0;
double cropRight = 0;
int angle = 0;
switch (image.getScaleImageValue())
{
case FILL_FRAME :
{
switch (image.getRotation())
{
case LEFT:
renderWidth = availableImageHeight;
renderHeight = availableImageWidth;
xoffset = (availableImageWidth - availableImageHeight) / 2;
yoffset = - (availableImageWidth - availableImageHeight) / 2;
angle = -90;
break;
case RIGHT:
renderWidth = availableImageHeight;
renderHeight = availableImageWidth;
xoffset = (availableImageWidth - availableImageHeight) / 2;
yoffset = - (availableImageWidth - availableImageHeight) / 2;
angle = 90;
break;
case UPSIDE_DOWN:
renderWidth = availableImageWidth;
renderHeight = availableImageHeight;
angle = 180;
break;
case NONE:
default:
renderWidth = availableImageWidth;
renderHeight = availableImageHeight;
angle = 0;
break;
}
break;
}
case CLIP :
{
double normalWidth = availableImageWidth;
double normalHeight = availableImageHeight;
Dimension2D dimension = imageProcessorResult.dimension;
if (dimension != null)
{
normalWidth = dimension.getWidth();
normalHeight = dimension.getHeight();
}
renderWidth = availableImageWidth;
renderHeight = availableImageHeight;
switch (image.getRotation())
{
case LEFT:
if (dimension == null)
{
normalWidth = availableImageHeight;
normalHeight = availableImageWidth;
}
renderWidth = availableImageHeight;
renderHeight = availableImageWidth;
xoffset = (availableImageWidth - availableImageHeight) / 2;
yoffset = - (availableImageWidth - availableImageHeight) / 2;
switch (image.getHorizontalImageAlign())
{
case RIGHT :
cropLeft = (availableImageHeight - normalWidth) / availableImageHeight;
cropRight = 0;
break;
case CENTER :
cropLeft = (availableImageHeight - normalWidth) / availableImageHeight / 2;
cropRight = cropLeft;
break;
case LEFT :
default :
cropLeft = 0;
cropRight = (availableImageHeight - normalWidth) / availableImageHeight;
break;
}
switch (image.getVerticalImageAlign())
{
case TOP :
cropTop = 0;
cropBottom = (availableImageWidth - normalHeight) / availableImageWidth;
break;
case MIDDLE :
cropTop = (availableImageWidth - normalHeight) / availableImageWidth / 2;
cropBottom = cropTop;
break;
case BOTTOM :
default :
cropTop = (availableImageWidth - normalHeight) / availableImageWidth;
cropBottom = 0;
break;
}
angle = -90;
break;
case RIGHT:
if (dimension == null)
{
normalWidth = availableImageHeight;
normalHeight = availableImageWidth;
}
renderWidth = availableImageHeight;
renderHeight = availableImageWidth;
xoffset = (availableImageWidth - availableImageHeight) / 2;
yoffset = - (availableImageWidth - availableImageHeight) / 2;
switch (image.getHorizontalImageAlign())
{
case RIGHT :
cropLeft = (availableImageHeight - normalWidth) / availableImageHeight;
cropRight = 0;
break;
case CENTER :
cropLeft = (availableImageHeight - normalWidth) / availableImageHeight / 2;
cropRight = cropLeft;
break;
case LEFT :
default :
cropLeft = 0;
cropRight = (availableImageHeight - normalWidth) / availableImageHeight;
break;
}
switch (image.getVerticalImageAlign())
{
case TOP :
cropTop = 0;
cropBottom = (availableImageWidth - normalHeight) / availableImageWidth;
break;
case MIDDLE :
cropTop = (availableImageWidth - normalHeight) / availableImageWidth / 2;
cropBottom = cropTop;
break;
case BOTTOM :
default :
cropTop = (availableImageWidth - normalHeight) / availableImageWidth;
cropBottom = 0;
break;
}
angle = 90;
break;
case UPSIDE_DOWN:
switch (image.getHorizontalImageAlign())
{
case RIGHT :
cropLeft = (availableImageWidth - normalWidth) / availableImageWidth;
cropRight = 0;
break;
case CENTER :
cropLeft = (availableImageWidth - normalWidth) / availableImageWidth / 2;
cropRight = cropLeft;
break;
case LEFT :
default :
cropLeft = 0;
cropRight = (availableImageWidth - normalWidth) / availableImageWidth;
break;
}
switch (image.getVerticalImageAlign())
{
case TOP :
cropTop = 0;
cropBottom = (availableImageHeight - normalHeight) / availableImageHeight;
break;
case MIDDLE :
cropTop = (availableImageHeight - normalHeight) / availableImageHeight / 2;
cropBottom = cropTop;
break;
case BOTTOM :
default :
cropTop = (availableImageHeight - normalHeight) / availableImageHeight;
cropBottom = 0;
break;
}
angle = 180;
break;
case NONE:
default:
switch (image.getHorizontalImageAlign())
{
case RIGHT :
cropLeft = (availableImageWidth - normalWidth) / availableImageWidth;
cropRight = 0;
break;
case CENTER :
cropLeft = (availableImageWidth - normalWidth) / availableImageWidth / 2;
cropRight = cropLeft;
break;
case LEFT :
default :
cropLeft = 0;
cropRight = (availableImageWidth - normalWidth) / availableImageWidth;
break;
}
switch (image.getVerticalImageAlign())
{
case TOP :
cropTop = 0;
cropBottom = (availableImageHeight - normalHeight) / availableImageHeight;
break;
case MIDDLE :
cropTop = (availableImageHeight - normalHeight) / availableImageHeight / 2;
cropBottom = cropTop;
break;
case BOTTOM :
default :
cropTop = (availableImageHeight - normalHeight) / availableImageHeight;
cropBottom = 0;
break;
}
angle = 0;
break;
}
break;
}
case RETAIN_SHAPE :
default :
{
double normalWidth = availableImageWidth;
double normalHeight = availableImageHeight;
Dimension2D dimension = imageProcessorResult.dimension;
if (dimension != null)
{
normalWidth = dimension.getWidth();
normalHeight = dimension.getHeight();
}
double ratioX = 1d;
double ratioY = 1d;
double imageWidth = availableImageWidth;
double imageHeight = availableImageHeight;
switch (image.getRotation())
{
case LEFT:
if (dimension == null)
{
normalWidth = availableImageHeight;
normalHeight = availableImageWidth;
}
renderWidth = availableImageHeight;
renderHeight = availableImageWidth;
ratioX = availableImageWidth / normalHeight;
ratioY = availableImageHeight / normalWidth;
ratioX = ratioX < ratioY ? ratioX : ratioY;
ratioY = ratioX;
imageWidth = (int)(normalHeight * ratioX);
imageHeight = (int)(normalWidth * ratioY);
xoffset = (availableImageWidth - availableImageHeight) / 2;
yoffset = - (availableImageWidth - availableImageHeight) / 2;
switch (image.getHorizontalImageAlign())
{
case RIGHT :
cropLeft = (availableImageHeight - imageHeight) / availableImageHeight;
cropRight = 0;
break;
case CENTER :
cropLeft = (availableImageHeight - imageHeight) / availableImageHeight / 2;
cropRight = cropLeft;
break;
case LEFT :
default :
cropLeft = 0;
cropRight = (availableImageHeight - imageHeight) / availableImageHeight;
break;
}
switch (image.getVerticalImageAlign())
{
case TOP :
cropTop = 0;
cropBottom = (availableImageWidth - imageWidth) / availableImageWidth;
break;
case MIDDLE :
cropTop = (availableImageWidth - imageWidth) / availableImageWidth / 2;
cropBottom = cropTop;
break;
case BOTTOM :
default :
cropTop = (availableImageWidth - imageWidth) / availableImageWidth;
cropBottom = 0;
break;
}
angle = -90;
break;
case RIGHT:
if (dimension == null)
{
normalWidth = availableImageHeight;
normalHeight = availableImageWidth;
}
renderWidth = availableImageHeight;
renderHeight = availableImageWidth;
ratioX = availableImageWidth / normalHeight;
ratioY = availableImageHeight / normalWidth;
ratioX = ratioX < ratioY ? ratioX : ratioY;
ratioY = ratioX;
imageWidth = (int)(normalHeight * ratioX);
imageHeight = (int)(normalWidth * ratioY);
xoffset = (availableImageWidth - availableImageHeight) / 2;
yoffset = - (availableImageWidth - availableImageHeight) / 2;
switch (image.getHorizontalImageAlign())
{
case RIGHT :
cropLeft = (availableImageHeight - imageHeight) / availableImageHeight;
cropRight = 0;
break;
case CENTER :
cropLeft = (availableImageHeight - imageHeight) / availableImageHeight / 2;
cropRight = cropLeft;
break;
case LEFT :
default :
cropLeft = 0;
cropRight = (availableImageHeight - imageHeight) / availableImageHeight;
break;
}
switch (image.getVerticalImageAlign())
{
case TOP :
cropTop = 0;
cropBottom = (availableImageWidth - imageWidth) / availableImageWidth;
break;
case MIDDLE :
cropTop = (availableImageWidth - imageWidth) / availableImageWidth / 2;
cropBottom = cropTop;
break;
case BOTTOM :
default :
cropTop = (availableImageWidth - imageWidth) / availableImageWidth;
cropBottom = 0;
break;
}
angle = 90;
break;
case UPSIDE_DOWN:
renderWidth = availableImageWidth;
renderHeight = availableImageHeight;
ratioX = availableImageWidth / normalWidth;
ratioY = availableImageHeight / normalHeight;
ratioX = ratioX < ratioY ? ratioX : ratioY;
ratioY = ratioX;
imageWidth = (int)(normalWidth * ratioX);
imageHeight = (int)(normalHeight * ratioY);
switch (image.getHorizontalImageAlign())
{
case RIGHT :
cropLeft = (availableImageWidth - imageWidth) / availableImageWidth;
cropRight = 0;
break;
case CENTER :
cropLeft = (availableImageWidth - imageWidth) / availableImageWidth / 2;
cropRight = cropLeft;
break;
case LEFT :
default :
cropLeft = 0;
cropRight = (availableImageWidth - imageWidth) / availableImageWidth;
break;
}
switch (image.getVerticalImageAlign())
{
case TOP :
cropTop = 0;
cropBottom = (availableImageHeight - imageHeight) / availableImageHeight;
break;
case MIDDLE :
cropTop = (availableImageHeight - imageHeight) / availableImageHeight / 2;
cropBottom = cropTop;
break;
case BOTTOM :
default :
cropTop = (availableImageHeight - imageHeight) / availableImageHeight;
cropBottom = 0;
break;
}
angle = 180;
break;
case NONE:
default:
renderWidth = availableImageWidth;
renderHeight = availableImageHeight;
ratioX = availableImageWidth / normalWidth;
ratioY = availableImageHeight / normalHeight;
ratioX = ratioX < ratioY ? ratioX : ratioY;
ratioY = ratioX;
imageWidth = (int)(normalWidth * ratioX);
imageHeight = (int)(normalHeight * ratioY);
switch (image.getHorizontalImageAlign())
{
case RIGHT :
cropLeft = (availableImageWidth - imageWidth) / availableImageWidth;
cropRight = 0;
break;
case CENTER :
cropLeft = (availableImageWidth - imageWidth) / availableImageWidth / 2;
cropRight = cropLeft;
break;
case LEFT :
default :
cropLeft = 0;
cropRight = (availableImageWidth - imageWidth) / availableImageWidth;
break;
}
switch (image.getVerticalImageAlign())
{
case TOP :
cropTop = 0;
cropBottom = (availableImageHeight - imageHeight) / availableImageHeight;
break;
case MIDDLE :
cropTop = (availableImageHeight - imageHeight) / availableImageHeight / 2;
cropBottom = cropTop;
break;
case BOTTOM :
default :
cropTop = (availableImageHeight - imageHeight) / availableImageHeight;
cropBottom = 0;
break;
}
angle = 0;
break;
}
}
}
if (startPage)
{
insertBookmark(pageAnchor, docHelper);
}
if (image.getAnchorName() != null)
{
insertBookmark(image.getAnchorName(), docHelper);
}
// boolean startedHyperlink = startHyperlink(image,false);
docHelper.write("\n");
docHelper.write(" \n");
docHelper.write("\n");
docHelper.write("\n");
docHelper.write("\n");
docHelper.write("\n");
docHelper.write("" + LengthUtil.emu(xoffset) + " \n");
docHelper.write(" \n");
docHelper.write("\n");
docHelper.write("" + LengthUtil.emu(yoffset + topPadding - tableHelper.getRowMaxTopPadding()) + " \n");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write("\n");
docHelper.write(" \n");
int imageId = image.hashCode() > 0 ? image.hashCode() : -image.hashCode();
String rId = IMAGE_LINK_PREFIX + getElementIndex(gridCell);
docHelper.write("\n");
if (getHyperlinkURL(image) != null)
{
docHelper.write(" \n");
}
docHelper.write(" \n");
docHelper.write("\n");
docHelper.write("\n");
docHelper.write("\n");
docHelper.write(" \n");
docHelper.write("\n");
docHelper.write(" ");
docHelper.write(" ");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write("\n");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write(" ");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write(" \n");
docHelper.write(" ");
String url = getHyperlinkURL(image);
if (url != null)
{
String targetMode = "";
switch(image.getHyperlinkTypeValue())
{
case LOCAL_PAGE:
case LOCAL_ANCHOR:
{
relsHelper.exportImageLink(rId, "#"+url.replaceAll("\\W", ""), targetMode);
break;
}
case REMOTE_PAGE:
case REMOTE_ANCHOR:
case REFERENCE:
{
targetMode = " TargetMode=\"External\"";
relsHelper.exportImageLink(rId, url, targetMode);
break;
}
default:
{
break;
}
}
}
// if (startedHyperlink)
// {
// endHyperlink(false);
// }
}
}
docHelper.write(" ");
tableHelper.getCellHelper().exportFooter();
}
private class InternalImageProcessor
{
private final JRPrintElement imageElement;
private final RenderersCache imageRenderersCache;
private final boolean needDimension;
private final JRExporterGridCell cell;
private final int availableImageWidth;
private final int availableImageHeight;
protected InternalImageProcessor(
JRPrintImage imageElement,
JRExporterGridCell cell,
int availableImageWidth,
int availableImageHeight
)
{
this.imageElement = imageElement;
this.cell = cell;
this.imageRenderersCache = imageElement.isUsingCache() ? renderersCache : new RenderersCache(getJasperReportsContext());
this.needDimension = imageElement.getScaleImageValue() != ScaleImageEnum.FILL_FRAME;
if (
imageElement.getRotation() == RotationEnum.LEFT
|| imageElement.getRotation() == RotationEnum.RIGHT
)
{
this.availableImageWidth = availableImageHeight;
this.availableImageHeight = availableImageWidth;
}
else
{
this.availableImageWidth = availableImageWidth;
this.availableImageHeight = availableImageHeight;
}
}
private InternalImageProcessorResult process(Renderable renderer) throws JRException
{
if (renderer instanceof ResourceRenderer)
{
renderer = imageRenderersCache.getLoadedRenderer((ResourceRenderer)renderer);
}
// check dimension first, to avoid caching renderers that might not be used eventually, due to their dimension errors
Dimension2D dimension = null;
if (needDimension)
{
DimensionRenderable dimensionRenderer = imageRenderersCache.getDimensionRenderable(renderer);
dimension = dimensionRenderer == null ? null : dimensionRenderer.getDimension(jasperReportsContext);
}
String imagePath = null;
// if (image.isLazy()) //FIXMEDOCX learn how to link images
// {
//
// }
// else
// {
if (
renderer instanceof DataRenderable //we do not cache imagePath for non-data renderers because they render width different width/height each time
&& rendererToImagePathMap.containsKey(renderer.getId())
)
{
imagePath = rendererToImagePathMap.get(renderer.getId());
}
else
{
JRPrintElementIndex imageIndex = getElementIndex(cell);
DataRenderable imageRenderer =
getRendererUtil().getImageDataRenderable(
imageRenderersCache,
renderer,
new Dimension(availableImageWidth, availableImageHeight),
ModeEnum.OPAQUE == imageElement.getModeValue() ? imageElement.getBackcolor() : null
);
byte[] imageData = imageRenderer.getData(jasperReportsContext);
String fileExtension = JRTypeSniffer.getImageTypeValue(imageData).getFileExtension();
String imageName = IMAGE_NAME_PREFIX + imageIndex.toString() + (fileExtension == null ? "" : ("." + fileExtension));
docxZip.addEntry(//FIXMEDOCX optimize with a different implementation of entry
new FileBufferedZipEntry(
"word/media/" + imageName,
imageData
)
);
relsHelper.exportImage(imageName);
imagePath = imageName;
//imagePath = "Pictures/" + imageName;
if (imageRenderer == renderer)
{
//cache imagePath only for true ImageRenderable instances because the wrapping ones render with different width/height each time
rendererToImagePathMap.put(renderer.getId(), imagePath);
}
}
// }
return new InternalImageProcessorResult(imagePath, dimension);
}
}
private class InternalImageProcessorResult
{
protected final String imagePath;
protected final Dimension2D dimension;
protected InternalImageProcessorResult(String imagePath, Dimension2D dimension)
{
this.imagePath = imagePath;
this.dimension = dimension;
}
}
protected JRPrintElementIndex getElementIndex(JRExporterGridCell gridCell)
{
JRPrintElementIndex imageIndex =
new JRPrintElementIndex(
reportIndex,
pageIndex,
gridCell.getElementAddress()
);
return imageIndex;
}
/*
*
*
protected void writeImageMap(String imageMapName, JRPrintHyperlink mainHyperlink, List imageMapAreas)
{
writer.write("\n");
}
protected void writeImageAreaCoordinates(JRPrintImageArea area)
{
int[] coords = area.getCoordinates();
if (coords != null && coords.length > 0)
{
StringBuilder coordsEnum = new StringBuilder(coords.length * 4);
coordsEnum.append(coords[0]);
for (int i = 1; i < coords.length; i++)
{
coordsEnum.append(',');
coordsEnum.append(coords[i]);
}
writer.write(" coords=\"" + coordsEnum + "\"");
}
}
protected void writeImageAreaHyperlink(JRPrintHyperlink hyperlink)
{
String href = getHyperlinkURL(hyperlink);
if (href == null)
{
writer.write(" nohref=\"nohref\"");
}
else
{
writer.write(" href=\"" + href + "\"");
String target = getHyperlinkTarget(hyperlink);
if (target != null)
{
writer.write(" target=\"");
writer.write(target);
writer.write("\"");
}
}
if (hyperlink.getHyperlinkTooltip() != null)
{
writer.write(" title=\"");
writer.write(JRStringUtil.xmlEncode(hyperlink.getHyperlinkTooltip()));
writer.write("\"");
}
}
*/
/**
*
*/
public static JRPrintElementIndex getPrintElementIndex(String imageName)
{
if (!imageName.startsWith(IMAGE_NAME_PREFIX))
{
throw
new JRRuntimeException(
EXCEPTION_MESSAGE_KEY_INVALID_IMAGE_NAME,
new Object[]{imageName});
}
return JRPrintElementIndex.parsePrintElementIndex(imageName.substring(IMAGE_NAME_PREFIX_LEGTH));
}
/**
* In deep grids, this is called only for empty frames.
*/
protected void exportFrame(DocxTableHelper tableHelper, JRPrintFrame frame, JRExporterGridCell gridCell) throws JRException
{
tableHelper.getCellHelper().exportHeader(frame, gridCell);
// tableHelper.getCellHelper().exportProps(gridCell);
boolean appendBackcolor =
frame.getModeValue() == ModeEnum.OPAQUE
&& (backcolor == null || frame.getBackcolor().getRGB() != backcolor.getRGB());
if (appendBackcolor)
{
setBackcolor(frame.getBackcolor());
}
try
{
JRGridLayout layout = ((ElementGridCell) gridCell).getLayout();
JRPrintElementIndex frameIndex =
new JRPrintElementIndex(
reportIndex,
pageIndex,
gridCell.getElementAddress()
);
exportGrid(layout, frameIndex);
}
finally
{
if (appendBackcolor)
{
restoreBackcolor();
}
}
tableHelper.getParagraphHelper().exportEmptyParagraph();
tableHelper.getCellHelper().exportFooter();
}
/**
*
*/
protected void exportGenericElement(DocxTableHelper tableHelper, JRGenericPrintElement element, JRExporterGridCell gridCell)
{
GenericElementDocxHandler handler = (GenericElementDocxHandler)
GenericElementHandlerEnviroment.getInstance(getJasperReportsContext()).getElementHandler(
element.getGenericType(), DOCX_EXPORTER_KEY);
if (handler != null)
{
JRDocxExporterContext exporterContext = new ExporterContext(tableHelper);
handler.exportElement(exporterContext, element, gridCell);
}
else
{
if (log.isDebugEnabled())
{
log.debug("No DOCX generic element handler for "
+ element.getGenericType());
}
}
}
/**
*
*/
protected void setBackcolor(Color color)
{
backcolorStack.addLast(backcolor);
backcolor = color;
}
protected void restoreBackcolor()
{
backcolor = backcolorStack.removeLast();
}
protected boolean startHyperlink(JRPrintHyperlink link, boolean isText)
{
String href = getHyperlinkURL(link);
if (href != null)
{
// String id = (String)hyperlinksMap.get(href);
// if (id == null)
// {
// id = "link" + hyperlinksMap.size();
// hyperlinksMap.put(href, id);
// }
//
// docHelper.write("\n");
docHelper.write(" \n");
String localType = (HyperlinkTypeEnum.LOCAL_ANCHOR == link.getHyperlinkTypeValue() ||
HyperlinkTypeEnum.LOCAL_PAGE == link.getHyperlinkTypeValue()) ? "\\l " : "";
docHelper.write(" HYPERLINK " + localType +"\"" + JRStringUtil.xmlEncode(href,invalidCharReplacement) + "\"");
String target = getHyperlinkTarget(link);//FIXMETARGET
if (target != null)
{
docHelper.write(" \\t \"" + target + "\"");
}
String tooltip = link.getHyperlinkTooltip();
if (tooltip != null)
{
docHelper.write(" \\o \"" + JRStringUtil.xmlEncode(tooltip, invalidCharReplacement) + "\"");
}
docHelper.write(" \n");
docHelper.write(" \n");
}
return href != null;
}
protected String getHyperlinkTarget(JRPrintHyperlink link)
{
String target = null;
switch(link.getHyperlinkTargetValue())
{
case SELF :
{
target = "_self";
break;
}
case BLANK :
default :
{
target = "_blank";
break;
}
}
return target;
}
protected String getHyperlinkURL(JRPrintHyperlink link)
{
String href = null;
Boolean ignoreHyperlink = HyperlinkUtil.getIgnoreHyperlink(DocxReportConfiguration.PROPERTY_IGNORE_HYPERLINK, link);
if (ignoreHyperlink == null)
{
ignoreHyperlink = getCurrentItemConfiguration().isIgnoreHyperlink();
}
if (!ignoreHyperlink)
{
JRHyperlinkProducer customHandler = getHyperlinkProducer(link);
if (customHandler == null)
{
switch(link.getHyperlinkTypeValue())
{
case REFERENCE :
{
if (link.getHyperlinkReference() != null)
{
href = link.getHyperlinkReference();
}
break;
}
case LOCAL_ANCHOR :
{
if (link.getHyperlinkAnchor() != null)
{
href = link.getHyperlinkAnchor().replaceAll("\\W", "");
}
break;
}
case LOCAL_PAGE :
{
if (link.getHyperlinkPage() != null)
{
href = JR_PAGE_ANCHOR_PREFIX + reportIndex + "_" + link.getHyperlinkPage().toString();
}
break;
}
case REMOTE_ANCHOR :
{
if (
link.getHyperlinkReference() != null &&
link.getHyperlinkAnchor() != null
)
{
href = link.getHyperlinkReference() + "#" + link.getHyperlinkAnchor();
}
break;
}
case REMOTE_PAGE :
{
if (
link.getHyperlinkReference() != null &&
link.getHyperlinkPage() != null
)
{
href = link.getHyperlinkReference() + "#" + JR_PAGE_ANCHOR_PREFIX + reportIndex + "_" + link.getHyperlinkPage().toString();
}
break;
}
case NONE :
default :
{
break;
}
}
}
else
{
href = customHandler.getHyperlink(link);
}
}
return href;
}
protected void endHyperlink(boolean isText)
{
// docHelper.write(" \n");
docHelper.write(" \n");
}
protected void insertBookmark(String bookmark, BaseHelper helper)
{
helper.write(" ");
}
@Override
protected void ensureInput()
{
super.ensureInput();
}
@Override
protected JRStyledText getStyledText(JRPrintText textElement, boolean setBackcolor)
{
return styledTextUtil.getProcessedStyledText(textElement,
setBackcolor ? allSelector : noBackcolorSelector, getExporterKey());
}
@Override
public String getExporterKey()
{
return DOCX_EXPORTER_KEY;
}
@Override
public String getExporterPropertiesPrefix()
{
return DOCX_EXPORTER_PROPERTIES_PREFIX;
}
}