I am trying to extract test output results in excel format. I want the results to be summarized in neat columns and row formats and want to display results graphically using a Pie chart.
To do this, I have used Apache POI API(Excel edits) and JFreeChart(for Pie chart creation).
I have been able to do all this, and the results are generated in .xls format.
When I tried to convert it to xlsx format after all of this, its doing the job, but the Pie chart and other excel stylings are missed to be written to .xlsx output file.
The code I have used for conversion from .xls to .xlsx is as follows:
package excelFileGenerate6;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
//import com.aspose.cells.SaveFormat;
public class conversion_to_xlsx {
public static void main(String[] args) throws InvalidFormatException,
IOException {
String inpFn = "C:\\Users\\Username\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\report.xls";
String outFn = "C:\\Users\\Username\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\converted_report.xlsx";
FileInputStream in = new FileInputStream(inpFn);
try {
Workbook wbIn = new HSSFWorkbook(in);
File outF = new File(outFn);
if (outF.exists())
outF.delete();
Workbook wbOut = new XSSFWorkbook();
int sheetCnt = wbIn.getNumberOfSheets();
for (int i = 0; i < sheetCnt; i++) {
Sheet sIn = wbIn.getSheetAt(i);
//Sheet sOut = wbOut.getSheet(null);
Sheet sOut = wbOut.createSheet(sIn.getSheetName());
Iterator<Row> rowIt = sIn.rowIterator();
while (rowIt.hasNext()) {
Row rowIn = rowIt.next();
Row rowOut = sOut.createRow(rowIn.getRowNum());
Iterator<Cell> cellIt = rowIn.cellIterator();
while (cellIt.hasNext()) {
Cell cellIn = cellIt.next();
Cell cellOut = rowOut.createCell(
cellIn.getColumnIndex(), cellIn.getCellType());
switch (cellIn.getCellType()) {
case Cell.CELL_TYPE_BLANK:
break;
case Cell.CELL_TYPE_BOOLEAN:
cellOut.setCellValue(cellIn.getBooleanCellValue());
break;
case Cell.CELL_TYPE_ERROR:
cellOut.setCellValue(cellIn.getErrorCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
cellOut.setCellFormula(cellIn.getCellFormula());
break;
case Cell.CELL_TYPE_NUMERIC:
cellOut.setCellValue(cellIn.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING:
cellOut.setCellValue(cellIn.getStringCellValue());
break;
}
{
CellStyle styleIn = cellIn.getCellStyle();
CellStyle styleOut = cellOut.getCellStyle();
styleOut.setDataFormat(styleIn.getDataFormat());
}
cellOut.setCellComment(cellIn.getCellComment());
// HSSFCellStyle cannot be cast to XSSFCellStyle
// cellOut.setCellStyle(cellIn.getCellStyle());
}
}
}
FileOutputStream out = new FileOutputStream(outF);
try {
wbOut.write(out);
} finally {
out.close();
}
} finally {
in.close();
}
}
}
I have generated the excel reports and associated Pie chart using HSSF workbook style which gives the excel output in .xls format. Tried the online help to convert the HSSF objects to XSSF objects , but the pie chart creation gave a sun/image/codec error.
Attaching the Screenshots of code snippets and excel output files.
Any code/direction for converting my .xls results to .xlsx format will highly be of help for me..
Thanks
The code used to create Pie Chart :
package excelFileGenerate6;
import java.awt.Color;
import java.io.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.ChartUtilities;
import java.util.Iterator;
public class CreatePieChartExample {
public void createPie(String Filename) throws IOException {
/* Read Excel and the Chart Data */
FileInputStream chart_file_input = new FileInputStream(new File(Filename));
/* Read data into HSSFWorkbook */
HSSFWorkbook my_workbook = new HSSFWorkbook(chart_file_input);
/* This worksheet contains the Pie Chart Data */
HSSFSheet my_sheet = my_workbook.getSheetAt(0);
/* Create JFreeChart object that will hold the Pie Chart Data */
DefaultPieDataset my_pie_chart_data = new DefaultPieDataset();
/* We now iterate over the Excel Workbook data and Populate Pie Chart Data */
/* Create an Iterator object */
Iterator<Row> rowIterator = my_sheet.iterator();
/* Loop through worksheet data and populate Pie Chart Dataset */
String chart_label="a";
Number chart_data=0;
while(rowIterator.hasNext()) {
//Read Rows from Excel document
Row row = rowIterator.next();
//Read cells in Rows and get chart data
Iterator<Cell> cellIterator = row.cellIterator();
while(cellIterator.hasNext()) {
Cell cell = cellIterator.next();
switch(cell.getCellType()) {
case Cell.CELL_TYPE_NUMERIC:
chart_data=cell.getNumericCellValue();
break;
case Cell.CELL_TYPE_STRING:
chart_label=cell.getStringCellValue();
break;
}
}
/* Add data to the data set */
my_pie_chart_data.setValue(chart_label,chart_data);
}
/* Create a logical chart object with the chart data collected */
JFreeChart myPieChart=ChartFactory.createPieChart("Test Results",my_pie_chart_data,true,true,false);
// Add custom colors
PiePlot plot = (PiePlot) myPieChart.getPlot();
//To create chart labels with only values on pie
PieSectionLabelGenerator gen = new StandardPieSectionLabelGenerator("{1}");
plot.setLabelGenerator(gen);
plot.setSectionPaint("Passed", Color.GREEN);
plot.setSectionPaint("Failed", Color.RED);
plot.setSectionPaint("Pending", Color.black);
plot.setSectionPaint("Total Time taken (ms)", Color.pink);
plot.setSectionPaint("Skipped", Color.blue);
plot.setSectionPaint("How many Sub headers are Passed", Color.yellow);
plot.setSectionPaint("Total TC's", Color.CYAN);
/* Specify the height and width of the Pie Chart */
int width=640; /* Width of the chart */
int height=480; /* Height of the chart */
float quality=1; /* Quality factor */
/* We don't want to create an intermediate file. So, we create a byte array output stream
and byte array input stream
And we pass the chart data directly to input stream through this */
/* Write chart as JPG to Output Stream */
ByteArrayOutputStream chart_out = new ByteArrayOutputStream();
ChartUtilities.writeChartAsJPEG(chart_out,quality,myPieChart,width,height);
/* We now read from the output stream and frame the input chart data */
InputStream feed_chart_to_excel=new ByteArrayInputStream(chart_out.toByteArray());
byte[] bytes = IOUtils.toByteArray(feed_chart_to_excel);
/* Add picture to workbook */
int my_picture_id = my_workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
/* We can close Piped Input Stream. We don't need this */
feed_chart_to_excel.close();
/* Close PipedOutputStream also */
chart_out.close();
/* Create the drawing container */
HSSFPatriarch drawing = my_sheet.createDrawingPatriarch();
/* Create an anchor point */
ClientAnchor my_anchor = new HSSFClientAnchor();
/* Define top left corner, and we can resize picture suitable from there */
my_anchor.setCol1(4);
my_anchor.setRow1(5);
/* Invoke createPicture and pass the anchor point and ID */
HSSFPicture my_picture = drawing.createPicture(my_anchor, my_picture_id);
/* Call resize method, which resizes the image */
my_picture.resize();
/* Close the FileInputStream */
chart_file_input.close();
/* Write changes to the workbook */
FileOutputStream out = new FileOutputStream(new File(Filename));
my_workbook.write(out);
out.close();
}
public static void main(String args[]) throws IOException {
CreatePieChartExample chart = new CreatePieChartExample();
chart.createPie("C:\\Users\\user\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\report.xls");
}
}
The code used for .xls to .xlsx conversion:
package excelFileGenerate6;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
//import com.aspose.cells.SaveFormat;
public class conversion_to_xlsx {
public static void main(String[] args) throws InvalidFormatException,
IOException {
String inpFn = "C:\\Users\\user\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\report.xls";
String outFn = "C:\\Users\\user\\JavaProjects\\workspace\\Sample2\\src\\excelFileGenerate6\\converted_report.xlsx";
FileInputStream in = new FileInputStream(inpFn);
try {
Workbook wbIn = new HSSFWorkbook(in);
File outF = new File(outFn);
if (outF.exists())
outF.delete();
Workbook wbOut = new XSSFWorkbook();
int sheetCnt = wbIn.getNumberOfSheets();
for (int i = 0; i < sheetCnt; i++) {
Sheet sIn = wbIn.getSheetAt(i);
//Sheet sOut = wbOut.getSheet(null);
Sheet sOut = wbOut.createSheet(sIn.getSheetName());
Iterator<Row> rowIt = sIn.rowIterator();
while (rowIt.hasNext()) {
Row rowIn = rowIt.next();
Row rowOut = sOut.createRow(rowIn.getRowNum());
Iterator<Cell> cellIt = rowIn.cellIterator();
while (cellIt.hasNext()) {
Cell cellIn = cellIt.next();
Cell cellOut = rowOut.createCell(
cellIn.getColumnIndex(), cellIn.getCellType());
switch (cellIn.getCellType()) {
case Cell.CELL_TYPE_BLANK:
break;
case Cell.CELL_TYPE_BOOLEAN:
cellOut.setCellValue(cellIn.getBooleanCellValue());
break;
case Cell.CELL_TYPE_ERROR:
cellOut.setCellValue(cellIn.getErrorCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
cellOut.setCellFormula(cellIn.getCellFormula());
break;
case Cell.CELL_TYPE_NUMERIC:
cellOut.setCellValue(cellIn.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING:
cellOut.setCellValue(cellIn.getStringCellValue());
break;
}
{
CellStyle styleIn = cellIn.getCellStyle();
CellStyle styleOut = cellOut.getCellStyle();
styleOut.setDataFormat(styleIn.getDataFormat());
}
cellOut.setCellComment(cellIn.getCellComment());
// HSSFCellStyle cannot be cast to XSSFCellStyle
// cellOut.setCellStyle(cellIn.getCellStyle());
}
}
}
FileOutputStream out = new FileOutputStream(outF);
try {
wbOut.write(out);
} finally {
out.close();
}
} finally {
in.close();
}
}
}
Related
my picture in SVG format include the latest data 122.6 but in JPEG format the last data point is 122.1
How can I convert the image in svg-format to jpeg-format without the lost of the latest data
renderer ?
padding margins ?
size ?
What is wrong in my code ??
best ghost
package helix;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.fop.svg.PDFTranscoder;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.ext.awt.image.codec.*;
public class genesisMATPIsvg2jpg {
public static void main(String[] args) throws Exception {
//Step -1: We read the input SVG document into Transcoder Input
String svg_URI_input = new File(basePath + "/var/gWebClient/Materialkostenindex2015=100.svg").toURL().toString();
TranscoderInput input_svg_image = new TranscoderInput(svg_URI_input);
//Step-2: Define OutputStream to JPG file and attach to TranscoderOutput
OutputStream jpg_ostream = new FileOutputStream(basePath + "/var/gWebClient/Materialkostenindex2015=100.jpeg");
TranscoderOutput output_jpg_image = new TranscoderOutput(jpg_ostream);
// Step-3: Create JPEGTranscoder and define hints
JPEGTranscoder my_converter = new JPEGTranscoder();
Object jpegQuality1 = new Float(800);
Object jpegQuality2 = new Float(600);
my_converter.addTranscodingHint(JPEGTranscoder.KEY_WIDTH, jpegQuality1);
my_converter.addTranscodingHint(JPEGTranscoder.KEY_HEIGHT, jpegQuality2);
my_converter.addTranscodingHint(JPEGTranscoder.KEY_QUALITY,new Float(0.9));
// Step-4: Write output
my_converter.transcode(input_svg_image, output_jpg_image);
// Step 5- close / flush Output Stream
jpg_ostream.flush();
jpg_ostream.close();
}
}
i used this code to create a databar :
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFDataBarFormatting;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
public class ConditionalFormattingDataBars {
public static void applyDataBars(SheetConditionalFormatting sheetCF, String region, ExtendedColor color) throws Exception {
CellRangeAddress[] regions = { CellRangeAddress.valueOf(region) };
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule(color);
DataBarFormatting dbf = rule.getDataBarFormatting();
dbf.getMinThreshold().setRangeType(ConditionalFormattingThreshold.RangeType.MIN);
dbf.getMaxThreshold().setRangeType(ConditionalFormattingThreshold.RangeType.MAX);
dbf.setWidthMin(0); //cannot work for XSSFDataBarFormatting, see https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDataBarFormatting.java?view=markup#l57
dbf.setWidthMax(100); //cannot work for XSSFDataBarFormatting, see https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDataBarFormatting.java?view=markup#l64
if (dbf instanceof XSSFDataBarFormatting) {
Field _databar = XSSFDataBarFormatting.class.getDeclaredField("_databar");
_databar.setAccessible(true);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataBar ctDataBar =
(org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataBar)_databar.get(dbf);
ctDataBar.setMinLength(0);
ctDataBar.setMaxLength(100);
}
sheetCF.addConditionalFormatting(regions, rule);
}
public static void main(String[] args) throws Exception {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("new sheet");
java.util.List<Double> list = java.util.Arrays.asList(0.279, 0.252, 0.187, 0.128, 0.078, 0.043, 0.022, 0.012, 0.011, 0.0, 0.0);
for (int i = 0; i < list.size(); i++) {
sheet.createRow(i+1).createCell(1).setCellValue(list.get(i));
}
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
ExtendedColor color = workbook.getCreationHelper().createExtendedColor();
color.setARGBHex("FF80C279");
applyDataBars(sheetCF, "B2:B12", color);
sheet.setColumnWidth(1, 50*256);
FileOutputStream out = new FileOutputStream("ConditionalFormattingDataBars.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
And i fond it on the question provided Hear
And it is working !
However i tried to modify it to add negative value Like This :
but i did not fond any Class Or Object To do this !
is this even possible ?
This is a similar problem as this one: How to make solid color for databar in apache.poi.
The settings for negative values in data bars were not available when Office Open XML was published. It is a later added feature. Since apache poi uses the published features of Office Open XML only, this feature is not available directly. Also it is not available using the underlying org.openxmlformats.schemas.spreadsheetml.x2006.main.* classes as those also only are created from published Office Open XML.
How to see this? All Office Open XML files are ZIP archives. One can unzip them and have a look at the XML. So we set data bar settings as needed in Excel and save the *.xlsx file. Then we unzip the *.xlsx file and have a look at /xl/worksheets/sheet1.xml. There we find the settings for conditional formatting.
So we only can solve this problem the same way as in the linked answer above.
Complete example:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFDataBarFormatting;
import org.apache.poi.xssf.usermodel.XSSFConditionalFormattingRule;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
public class ConditionalFormattingDataBars {
public static void applyDataBars(SheetConditionalFormatting sheetCF, String region, ExtendedColor colorPos, ExtendedColor colorNeg) throws Exception {
CellRangeAddress[] regions = { CellRangeAddress.valueOf(region) };
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule(colorPos);
DataBarFormatting dbf = rule.getDataBarFormatting();
dbf.getMinThreshold().setRangeType(ConditionalFormattingThreshold.RangeType.MIN);
dbf.getMaxThreshold().setRangeType(ConditionalFormattingThreshold.RangeType.MAX);
dbf.setWidthMin(0); //cannot work for XSSFDataBarFormatting, see https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDataBarFormatting.java?view=markup#l57
dbf.setWidthMax(100); //cannot work for XSSFDataBarFormatting, see https://svn.apache.org/viewvc/poi/tags/REL_4_0_1/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDataBarFormatting.java?view=markup#l64
if (dbf instanceof XSSFDataBarFormatting) {
Field _databar = XSSFDataBarFormatting.class.getDeclaredField("_databar");
_databar.setAccessible(true);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataBar ctDataBar =
(org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataBar)_databar.get(dbf);
ctDataBar.setMinLength(0);
ctDataBar.setMaxLength(100);
}
// use extension from x14 namespace to set data bars having setting for negative value
if (rule instanceof XSSFConditionalFormattingRule) {
Field _cfRule = XSSFConditionalFormattingRule.class.getDeclaredField("_cfRule");
_cfRule.setAccessible(true);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCfRule ctRule =
(org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCfRule)_cfRule.get(rule);
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExtensionList extList =
ctRule.addNewExtLst();
org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExtension ext = extList.addNewExt();
String extXML =
"<x14:id"
+ " xmlns:x14=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\">"
+ "{00000000-000E-0000-0000-000001000000}"
+ "</x14:id>";
org.apache.xmlbeans.XmlObject xlmObject = org.apache.xmlbeans.XmlObject.Factory.parse(extXML);
ext.set(xlmObject);
ext.setUri("{B025F937-C7B1-47D3-B67F-A62EFF666E3E}");
Field _sh = XSSFConditionalFormattingRule.class.getDeclaredField("_sh");
_sh.setAccessible(true);
XSSFSheet sheet = (XSSFSheet)_sh.get(rule);
extList = sheet.getCTWorksheet().addNewExtLst();
ext = extList.addNewExt();
extXML =
"<x14:conditionalFormattings xmlns:x14=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\">"
+ "<x14:conditionalFormatting xmlns:xm=\"http://schemas.microsoft.com/office/excel/2006/main\">"
+ "<x14:cfRule type=\"dataBar\" id=\"{00000000-000E-0000-0000-000001000000}\">"
+ "<x14:dataBar minLength=\"" + 0 + "\" maxLength=\"" + 100 + "\" border=\"1\" negativeBarBorderColorSameAsPositive=\"0\">"
+ "<x14:cfvo type=\"min\"/>"
+ "<x14:cfvo type=\"max\"/>"
+ "<x14:borderColor rgb=\"" + colorPos.getARGBHex() + "\"/>"
+ "<x14:negativeFillColor rgb=\"" + colorNeg.getARGBHex() + "\"/>"
+ "<x14:negativeBorderColor rgb=\"" + colorNeg.getARGBHex() + "\"/>"
+ "<x14:axisColor theme=\"1\"/>"
+ "</x14:dataBar>"
+ "</x14:cfRule>"
+ "<xm:sqref>" + region + "</xm:sqref>"
+ "</x14:conditionalFormatting>"
+ "</x14:conditionalFormattings>";
xlmObject = org.apache.xmlbeans.XmlObject.Factory.parse(extXML);
ext.set(xlmObject);
ext.setUri("{78C0D931-6437-407d-A8EE-F0AAD7539E65}");
}
sheetCF.addConditionalFormatting(regions, rule);
}
public static void main(String[] args) throws Exception {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("new sheet");
java.util.List<Double> list = java.util.Arrays.asList(0.279, -0.252, 0.187, -0.128, 0.078, 0.043, -0.022, 0.012, 0.011, 0.0, 0.0);
for (int i = 0; i < list.size(); i++) {
sheet.createRow(i+1).createCell(1).setCellValue(list.get(i));
}
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
ExtendedColor colorPos = workbook.getCreationHelper().createExtendedColor();
colorPos.setARGBHex("FF80C279");
ExtendedColor colorNeg = workbook.getCreationHelper().createExtendedColor();
colorNeg.setARGBHex("FFFF0000");
applyDataBars(sheetCF, "B2:B12", colorPos, colorNeg);
sheet.setColumnWidth(1, 50*256);
FileOutputStream out = new FileOutputStream("ConditionalFormattingDataBars.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
This code will only work properly always for new created XSSFWorkbook. If the XSSFWorkbook was created from an existing workbook, the this could contain org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExtensionList for x14 extensions already. If so, then these must be taken into account. But that would be a much more complex and challenging project.
Here is my code
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
#Service
#Slf4j
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class FileConverterService {
public void convertPptToImages() throws Exception {
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("Sylon_GuidedPath_Sprint22Deck.ppt").getFile());
Document pdfDocument = new Document();
// PdfWriter pdfWriter = PdfWriter.getInstance(pdfDocument, new FileOutputStream(""));
FileInputStream is = new FileInputStream(file);
HSLFSlideShow ppt = new HSLFSlideShow(is);
is.close();
Dimension pgsize = ppt.getPageSize();
pdfDocument.setPageSize(new Rectangle((float) pgsize.getWidth(), (float) pgsize.getHeight()));
// convert to images
int idx = 1;
for (HSLFSlide slide : ppt.getSlides()) {
BufferedImage img =
new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setRenderingHint(
RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(
RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.setRenderingHint(
RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
// clear the drawing area
graphics.setPaint(Color.white);
graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
// render
slide.draw(graphics);
// save the output
ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpgWriteParam.setCompressionQuality(1f);
jpgWriter.setOutput(new FileImageOutputStream(
new File("slide-" + idx + ".jpg")));
IIOImage outputImage = new IIOImage(img, null, null);
jpgWriter.write(null, outputImage, jpgWriteParam);
jpgWriter.dispose();
idx++;
}
}
I based my code off this documentation, http://poi.apache.org/components/slideshow/how-to-shapes.html#Render
I have tried both jpeg and png, and the image seems to be fairly low resolution and the text is difficult to read compared to the original .ppt. Is there any way to increase the resolution/quality of the images?
What you can try
Applying RenderingHints to the graphics, below is a sample I created comparing the image with/without rendering hint. You can see that the character looks better with rendering hint.
Increase the compression quality for the jpeg image.
Following program demonstrates how to generate image with/without rendering hint and create image with 100% compression quality.
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.FileImageOutputStream;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
public class ImproveSlideConvertToImageQuality {
public static void main(String[] args) throws Exception {
convertPptToImages(true);
convertPptToImages(false);
}
public static void convertPptToImages(boolean withRenderHint) throws Exception {
File file = new File("test.ppt");
String suffix = withRenderHint ? "-with-hint" : "-without-hint";
try (FileInputStream is = new FileInputStream(file); HSLFSlideShow ppt = new HSLFSlideShow(is)) {
Dimension pgsize = ppt.getPageSize();
int idx = 1;
for (HSLFSlide slide : ppt.getSlides()) {
BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
if (withRenderHint) {
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics.setRenderingHint(
RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
graphics.setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(
RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
graphics.setRenderingHint(
RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
}
// render
slide.draw(graphics);
final ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
writer.setOutput(new FileImageOutputStream(
new File("slide-" + idx + suffix + ".jpeg")));
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(1f);
// writes the file with given compression level
// from your JPEGImageWriteParam instance
IIOImage image = new IIOImage(img, null, null);
writer.write(null, image, jpegParams);
writer.dispose();
idx++;
}
}
}
}
References:
Controlling Rendering Quality
Setting jpg compression level with ImageIO in Java
I want to write a comment to a existing word document programmatically using apache poi. I have successfully added comments to the paragraph by the method mentioned here, but when adding comments to the table, I don't know how to associate it with real comments
BigInteger cId = BigInteger.ZERO;
ctComment = comments.addNewComment();
ctComment.setAuthor("Axel Ríchter");
ctComment.setInitials("AR");
ctComment.setDate(new GregorianCalendar(Locale.US));
ctComment.addNewP().addNewR().addNewT().setStringValue("The first comment.");
ctComment.setId(cId);
paragraph = document.createParagraph();
paragraph.getCTP().addNewCommentRangeStart().setId(cId);
run = paragraph.createRun();
run.setText("Paragraph with the first comment.");
paragraph.getCTP().addNewCommentRangeEnd().setId(cId);
paragraph.getCTP().addNewR().addNewCommentReference().setId(cId);
in paragraph, we can use paragraph.getCTP().addNewR().addNewCommentReference().setId() to link a comment, but there seems no similar method in table. what should i do? I am a beginner to apache poi, any suggestions are greatly appreciated.
The short answer to your question how to comment a whole table is: You get the first paragraph in first cell of that table to set the CommentRangeStart as the first element in that paragraph. Then you get the last paragraph in last cell of that table to set the CommentRangeEnd as the last element in that paragraph.
But if you wants changing a already present Word document, then much more needs to be taken into account. What if there are comment already? My example you are linking is for creating a new Word document from scratch. So there cannot be comments already before. I have provided also How to manipulate content of a comment with Apache POI. But this rely on already present comments. Now we have to use a combination of both. This needs to take into account already present comments as well as a not already present comments document which then needs to be new created.
Additional there is difficulty to to set the CommentRangeStart as the first element in a already present paragraph. There are no methods for this. So we need using very low level XML manipulating to achieve this.
The following example needs a WordDocument.docx having at least one table. This whole table gets commented then.
import java.io.*;
import org.apache.poi.*;
import org.apache.poi.ooxml.*;
import org.apache.poi.openxml4j.opc.*;
import org.apache.xmlbeans.*;
import org.apache.poi.xwpf.usermodel.*;
import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import javax.xml.namespace.QName;
import java.math.BigInteger;
import java.util.GregorianCalendar;
import java.util.Locale;
public class WordCommentWholeTable {
//a method to get or create the CommentsDocument /word/comments.xml in the *.docx ZIP archive
private static MyXWPFCommentsDocument createCommentsDocument(XWPFDocument document) throws Exception {
MyXWPFCommentsDocument myXWPFCommentsDocument = null;
//trying to get the CommentsDocument
for (POIXMLDocumentPart.RelationPart rpart : document.getRelationParts()) {
String relation = rpart.getRelationship().getRelationshipType();
if (relation.equals(XWPFRelation.COMMENT.getRelation())) {
POIXMLDocumentPart part = rpart.getDocumentPart();
myXWPFCommentsDocument = new MyXWPFCommentsDocument(part.getPackagePart());
String rId = document.getRelationId(part);
document.addRelation(rId, XWPFRelation.COMMENT, myXWPFCommentsDocument);
}
}
//create a new CommentsDocument if there is not one already
if (myXWPFCommentsDocument == null) {
OPCPackage oPCPackage = document.getPackage();
PackagePartName partName = PackagingURIHelper.createPartName("/word/comments.xml");
PackagePart part = oPCPackage.createPart(
partName,
"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml");
myXWPFCommentsDocument = new MyXWPFCommentsDocument(part);
document.addRelation(null, XWPFRelation.COMMENT, myXWPFCommentsDocument);
}
return myXWPFCommentsDocument;
}
//a method to get the next comment Id from CTComments
private static BigInteger getCommentId(CTComments comments) {
BigInteger cId = BigInteger.ZERO;
for (CTComment ctComment : comments.getCommentList()) {
if (ctComment.getId().compareTo(cId) == 1) {
cId = ctComment.getId();
}
}
cId = cId.add(BigInteger.ONE);
return cId;
}
//method to set CommentRangeStart as first element in paragraph
private static CTMarkupRange insertCommentRangeStartAsFirstElement(XWPFParagraph paragraph) {
String uri = CTMarkupRange.type.getName().getNamespaceURI();
String localPart = "commentRangeStart";
XmlCursor cursor = paragraph.getCTP().newCursor();
cursor.toFirstChild();
cursor.beginElement(localPart, uri);
cursor.toParent();
CTMarkupRange commentRangeStart = (CTMarkupRange)cursor.getObject();
cursor.dispose();
return commentRangeStart;
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument(new FileInputStream("WordDocument.docx"));
MyXWPFCommentsDocument myXWPFCommentsDocument = createCommentsDocument(document);
CTComments comments = myXWPFCommentsDocument.getComments();
CTComment ctComment;
XWPFParagraph paragraph;
XWPFRun run;
//comment for the table
BigInteger cId = getCommentId(comments);
ctComment = comments.addNewComment();
ctComment.setAuthor("Axel Ríchter");
ctComment.setInitials("AR");
ctComment.setDate(new GregorianCalendar(Locale.US));
ctComment.addNewP().addNewR().addNewT().setStringValue("This is a comment for whole table.");
ctComment.setId(cId);
//get first paragraph in first table cell to set CommentRangeStart
XWPFTable table = document.getTables().get(0);
XWPFTableRow row = table.getRow(0);
XWPFTableCell cell = row.getCell(0);
paragraph = cell.getParagraphArray(0);
CTMarkupRange commentRangeStart = insertCommentRangeStartAsFirstElement(paragraph);
commentRangeStart.setId(cId);
//get last paragraph in last table cell to set CommentRangeEnd and CommentReference
row = table.getRows().get(table.getRows().size()-1);
cell = row.getTableCells().get(row.getTableCells().size()-1);
paragraph = cell.getParagraphs().get(cell.getParagraphs().size()-1);
paragraph.getCTP().addNewCommentRangeEnd().setId(cId);
paragraph.getCTP().addNewR().addNewCommentReference().setId(cId);
FileOutputStream out = new FileOutputStream("WordDocumentWithComments.docx");
document.write(out);
out.close();
document.close();
}
//a wrapper class for the CommentsDocument /word/comments.xml in the *.docx ZIP archive
private static class MyXWPFCommentsDocument extends POIXMLDocumentPart {
private CTComments comments;
private MyXWPFCommentsDocument(PackagePart part) throws Exception {
super(part);
try {
comments = CommentsDocument.Factory.parse(part.getInputStream(), DEFAULT_XML_OPTIONS).getComments();
} catch (Exception ex) {
// there was no comments yet
}
if (comments == null) comments = CommentsDocument.Factory.newInstance().addNewComments();
}
private CTComments getComments() {
return comments;
}
#Override
protected void commit() throws IOException {
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTComments.type.getName().getNamespaceURI(), "comments"));
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
comments.save(out, xmlOptions);
out.close();
}
}
}
I'm tring to to read large excel file (size~10MB,.xlsx) .
I'm using below code
Workbook xmlworkbook =WorkbookFactory.create(OPCPackage.openOrCreate(root_path_name_file));
But it's showing Heap memory issue.
I have also seen other solution on StackOverflow some of them given to increase the JVM but i dont want to increase jvm.
Issue 1) We can't use SXSSF (Streaming Usermodel API) because this is only for writing or creating new workbook.
My sole objective to get the number of NamedRange of sheet, Total number of sheet and their sheet name for large excel file.
If the requirement is only to get the named ranges and sheet names, then only the /xl/workbook.xml from the *.xlsx ZIPPackage must be parsed since those informations are all stored there.
This is possible by getting the appropriate PackagePart and parsing the XML from this. For parsing XML my favorite is using StAX.
Example code which gets all sheet names and defined named ranges:
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.XMLEvent;
import javax.xml.namespace.QName;
import java.io.File;
import java.util.regex.Pattern;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
class StaxReadOPCPackageParts {
public static void main(String[] args) {
try {
File file = new File("file.xlsx");
OPCPackage opcpackage = OPCPackage.open(file);
//get the workbook package part
PackagePart workbookpart = opcpackage.getPartsByName(Pattern.compile("/xl/workbook.xml")).get(0);
//create reader for package part
XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(workbookpart.getInputStream());
List<String> sheetNames = new ArrayList<>();
Map<String, String> definedNames = new HashMap<>();
boolean isInDefinedName = false;
String sheetName = "";
String definedNameName = "";
StringBuffer definedNameFormula = new StringBuffer();
while(reader.hasNext()){ //loop over all XML in workbook.xml
XMLEvent event = (XMLEvent)reader.next();
if(event.isStartElement()) {
StartElement startElement = (StartElement)event;
QName startElementName = startElement.getName();
if(startElementName.getLocalPart().equalsIgnoreCase("sheet")) { //start element of sheet definition
Attribute attribute = startElement.getAttributeByName(new QName("name"));
sheetName = attribute.getValue();
sheetNames.add(sheetName);
} else if (startElementName.getLocalPart().equalsIgnoreCase("definedName")) { //start element of definedName
Attribute attribute = startElement.getAttributeByName(new QName("name"));
definedNameName = attribute.getValue();
isInDefinedName = true;
}
} else if(event.isCharacters() && isInDefinedName) { //character content of definedName == the formula
definedNameFormula.append(((Characters)event).getData());
} else if(event.isEndElement()) {
EndElement endElement = (EndElement)event;
QName endElementName = endElement.getName();
if(endElementName.getLocalPart().equalsIgnoreCase("definedName")) { //end element of definedName
definedNames.put(definedNameName, definedNameFormula.toString());
definedNameFormula = new StringBuffer();
isInDefinedName = false;
}
}
}
opcpackage.close();
System.out.println("Sheet names:");
for (String shName : sheetNames) {
System.out.println("Sheet name: " + shName);
}
System.out.println("Named ranges:");
for (String defName : definedNames.keySet()) {
System.out.println("Name: " + defName + ", Formula: " + definedNames.get(defName));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}