How to create PowePoint presentation in OpenXML format with Apache Poi and XSLF? - powerpoint

If I go to Apache POI XSLF there should be samples for both OLE2 and OpenXML specs, but there are only the OLE2 based Horrible Slide Layout Format examples.
Could please anybody help me out with XML Slide Layout Format example ? The API is quite different.
It is not like with spreadsheet where one just change the implementation of HSSFWorkbook to XSSFWorkbook.
How would this look like with XSLF implementation ? POI apparently can't create a document from scratch, so we need an existing empty dummy document, right ?
//table data
String[][] data = {
{"INPUT FILE", "NUMBER OF RECORDS"},
{"Item File", "11,559"},
{"Vendor File", "300"},
{"Purchase History File", "10,000"},
{"Total # of requisitions", "10,200,038"}
};
SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide();
//create a table of 5 rows and 2 columns
Table table = new Table(5, 2);
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
TableCell cell = table.getCell(i, j);
cell.setText(data[i][j]);
RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];
rt.setFontName("Arial");
rt.setFontSize(10);
cell.setVerticalAlignment(TextBox.AnchorMiddle);
cell.setHorizontalAlignment(TextBox.AlignCenter);
}
}
//set table borders
Line border = table.createBorder();
border.setLineColor(Color.black);
border.setLineWidth(1.0);
table.setAllBorders(border);
//set width of the 1st column
table.setColumnWidth(0, 300);
//set width of the 2nd column
table.setColumnWidth(1, 150);
slide.addShape(table);
table.moveTo(100, 100);
FileOutputStream out = new FileOutputStream(file);
ppt.write(out);
out.close();

It is not implemented yet, org.apache.poi version 3.8-beta3, when it will be implemented is very unknown to me.
XMLSlideShow.java
public MasterSheet createMasterSheet() throws IOException {
throw new IllegalStateException("Not implemented yet!");
}
public Slide createSlide() throws IOException {
throw new IllegalStateException("Not implemented yet!");
}

Related

itext7 barcodes in footer

I'm working on a rather complex solution that takes an html-like input and converts it to a pdf. One of the many items that I'm trying to solve for is adding barcodes (all types, 3 of 9, PDF417, and qr code) to the footer of documents.
A couple details that give me pause on how to implement:
Bar code will contain current page number
Bar code will contain total page count
Bar code will be inside other itext elements (like a table cell or paragraph) and (in the final solution) needs to be parsed out ahead of time
Knowing those details, I'm struggling a bit on how to combine barcodes with something like the page x of y strategy of using a template to replace page count after rendering all the content.
I assume that each bar code will need it's own template because of the page count, and keep track of the templates until all the content is rendered and then update each individual template with the appropriate bar code. But because the footer is parsed out ahead of time, I need a template that represents a bar code so that the footer will have the correct height and content can be adjusted appropriately.
I believe that each of these pieces need to be handled in the event handler for end of page, is that a correct assessment?
UPD Edited to include code sample. I pulled out quite a bit of the other stuff I was trying to accomplish from this example. As for the parsed ahead of time, instead of going over a loop from 1 to 20 and creating random elements, some other process creates all the elements that need to be present on the document and will pass in that list of elements to the renderer. That does include the footer content as well. In this case I'm creating the footer table in the constructor of the HeaderHandler as that is close to the same concept. The reason I bring this up is that I won't be able to create the table in the HandleEvent of the handler like in most examples I have seen about tables in footers. Hope that makes sense.
void Main()
{
PdfDocument pdf = new PdfDocument(new PdfWriter(Dest));
PageSize pageSize = PageSize.A4;
Document doc = new Document(pdf, pageSize, true);
HeaderHandler hh = new HeaderHandler(doc);
...
some other object generation
...
// create random paragraphs to fill up multiple pages in the final solution this would have already happened.
for (var i = 0; i < 20; i++)
AddItemToList(elementList, i, objects);
// add random elements back to the document
foreach (var e in elementList)
{
... add each item just added to elementList to the document ...
}
renderer.Flush();
hh.UpdateTotal(pdf);
// I think I need to update all the barcodes and print them out here so that page count part of the barcode can be written
doc.Close();
}
class HeaderHandler : IEventHandler
{
Table Footer;
Document Doc;
public Margin First;
public Margin Middle;
public Margin Last;
public Dictionary<int, Margin> PageMargins { get; set; }
public float HeaderHeight { get; }
public float FooterHeight { get; }
PdfFormXObject PgCount;
Text PageNumber;
Dictionary<string, PdfFormXObject> BarcodeImages;
public HeaderHandler(Document doc)
{
Doc = doc;
Footer = new Table(new float[] { 4, 2, 4}).SetAutoLayout();
PageMargins = new Dictionary<int, Margin>();
BarcodeImages = new Dictionary<string, PdfFormXObject>();
var pageSize = Doc.GetPdfDocument().GetDefaultPageSize();
var width = pageSize.GetRight() - pageSize.GetLeft() - Doc.GetLeftMargin() - Doc.GetRightMargin();
// page total
PgCount = new PdfFormXObject(new Rectangle(0,0, 13, 13));
Footer.AddCell(new Cell().Add(new Paragraph("info 1")));
PageNumber = new Text("{page}");
var cell = new Cell().Add(new Paragraph().Add(PageNumber).Add(" of ").Add(new Image(PgCount)).Add(" pages").SetTextAlignment(TextAlignment.CENTER));
Footer.AddCell(cell);
Footer.AddCell(new Cell().Add(new Paragraph("info 2")));
Footer.AddCell("footer 1");
Footer.AddCell("footer 2");
// I think I need to add a template here for the barcode as a placeholder so that when the renderersubtree is ran it provides space for the barcode
Footer.AddCell(new Cell().Add(new Paragraph("{barcode} {qr code - {page} | {pagect} | doc name}")));
TableRenderer fRenderer = (TableRenderer)Footer.CreateRendererSubTree();
using (var s = new MemoryStream())
{
fRenderer.SetParent(new Document(new PdfDocument(new PdfWriter(s))).GetRenderer());
FooterHeight = fRenderer.Layout(new LayoutContext(new LayoutArea(0, PageSize.A4))).GetOccupiedArea().GetBBox().GetHeight();
}
}
public void UpdateTotal(PdfDocument pdf) {
Canvas canvas = new Canvas(PgCount, pdf);
canvas.ShowTextAligned(pdf.GetNumberOfPages().ToString(), 0, -3, TextAlignment.LEFT);
}
//draw footer and header tables
public void HandleEvent(Event e)
{
PdfDocumentEvent docEvent = e as PdfDocumentEvent;
if (docEvent == null)
return;
PdfDocument pdf = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
PdfCanvas pdfCanvas = new PdfCanvas(page.GetLastContentStream(), page.GetResources(), pdf);
int pageNum = pdf.GetPageNumber(page);
var pageSize = Doc.GetPdfDocument().GetDefaultPageSize();
Margin activeMargin = new Margin();
if (PageMargins.ContainsKey(pageNum))
activeMargin = PageMargins[pageNum];
var width = pageSize.GetRight() - pageSize.GetLeft() - activeMargin.Left - activeMargin.Right;
Header.SetWidth(width);
Footer.SetWidth(width);
var pageReferences = new List<TextRenderer>();
// update page number text so it can be written to in the footer
PageNumber.SetText(pageNum.ToString());
// draw the footer
rect = new Rectangle(pdf.GetDefaultPageSize().GetX() + activeMargin.Left, activeMargin.Bottom - GetFooterHeight(), 100, GetFooterHeight());
canvas = new Canvas(pdfCanvas, pdf, rect);
// I think it's here that I need to be able to add a barcode placeholder to something that can be called
canvas.Add(Footer);
}
public float GetFooterHeight()
{
return FooterHeight;
}
}

How to retrieve column names from a excel sheet?

Using EPPlus I'm writing data to multiple sheets. If a sheet is not created I'm adding a sheet else I'm retrieving the used rows and adding data from that row and saving it
FileInfo newFile = new FileInfo("Excel.xlsx");
using (ExcelPackage xlPackage = new ExcelPackage(newFile))
{
var ws = xlPackage.Workbook.Worksheets.FirstOrDefault(x => x.Name == language.Culture);
if (ws == null)
{
worksheet = xlPackage.Workbook.Worksheets.Add(language.Culture);
//writing data
}
else
{
worksheet = xlPackage.Workbook.Worksheets[language.Culture];
colCount = worksheet.Dimension.End.Column;
rowCount = worksheet.Dimension.End.Row;
//write data
}
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
xlPackage.Save();
And it is working great.
Now I want to retrieve the column names of each sheet in the excel using LinqToExcel and this is my code
string sheetName = language.Culture;
var excelFile = new ExcelQueryFactory(excelPath);
IQueryable<Row> excelSheetValues = from workingSheet in excelFile.Worksheet(sheetName) select workingSheet;
string[] headerRow = excelFile.GetColumnNames(sheetName).ToArray();
At header row it is throwing me an exception
An OleDbException exception was caught
External table is not in the expected format.
But I don't want to use Oledb and want to work with Linq To Excel.
Note: When I'm working with single sheet rather than multiple sheets
it is working fine and retrieving all columns. Where am I going wrong.
(Based on OP's Comments)
The AutoFitColumn function has always been a little touchy. The important thing to remember is to call it AFTER you load the cell data.
But if you want a use a minimum width (when columns are very narrow and you want to use a minimum) I find EPP to be unreliable. It seems to always use DefualtColWidth of the worksheet even if you pass in a minimumWidth to one of the function overloads.
Here is how I get around it:
[TestMethod]
public void Autofit_Column_Range_Test()
{
//http://stackoverflow.com/questions/31165959/how-to-retrieve-column-names-from-a-excel-sheet
//Throw in some data
var datatable = new DataTable("tblData");
datatable.Columns.Add(new DataColumn("Nar", typeof(int))); //This would not be autofitted without the workaround since the default width of a new ws, usually 8.43
datatable.Columns.Add(new DataColumn("Wide Column", typeof(int)));
datatable.Columns.Add(new DataColumn("Really Wide Column", typeof(int)));
for (var i = 0; i < 20; i++)
{
var row = datatable.NewRow();
row[0] = i;
row[1] = i * 10;
row[2] = i * 100;
datatable.Rows.Add(row);
}
var existingFile2 = new FileInfo(#"c:\temp\temp.xlsx");
if (existingFile2.Exists)
existingFile2.Delete();
using (var package = new ExcelPackage(existingFile2))
{
//Add the data
var ws = package.Workbook.Worksheets.Add("Sheet1");
ws.Cells.LoadFromDataTable(datatable, true);
//Keep track of the original default of 8.43 (excel default unless the user has changed it in their local Excel install)
var orginaldefault = ws.DefaultColWidth;
ws.DefaultColWidth = 15;
//Even if you pass in a miniumWidth as the first parameter like '.AutoFitColumns(15)' EPPlus usually ignores it and goes with DefaultColWidth
ws.Cells[ws.Dimension.Address].AutoFitColumns();
//Set it back to what it was so it respects the user's local setting
ws.DefaultColWidth = orginaldefault;
package.Save();
}
}

adding images to a gridpane javafx

I'm adding a list of images from a directory using an arraylist.When images are added,my ScrollPane gets crowded.How can I keep spacings between images ?
here's my code
File file = new File("D:\\SERVER\\Server Content\\Apps\\icons");
File[] filelist1 = file.listFiles();
ArrayList<File> filelist2 = new ArrayList<>();
hb = new HBox();
for (File file1 : filelist1) {
filelist2.add(file1);
}
System.out.println(filelist2.size());
gridpane.setPadding(new Insets(50,50,50,50));
gridpane.setHgap(20);
gridpane.setVgap(20);
int imageCol = 0;
int imageRow = 0;
for (int i = 0; i < filelist2.size(); i++) {
System.out.println(filelist2.get(i).getName());
image = new Image(filelist2.get(i).toURI().toString());
pic = new ImageView();
pic.setFitWidth(130);
pic.setFitHeight(130);
pic.setImage(image);
hb.getChildren().add(pic);
gridpane.add(pic, imageCol, imageRow );
imageCol++;
// To check if all the 4 images of a row are completed
if(imageCol > 2){
// Reset Column
imageCol=0;
// Next Row
imageRow++;
}
Try using HBox and VBox.
Basically, they are like little containers where you store your stuff and you can add gaps into it!
HBox ab = new HBox(10); <--The 10 is adding space (Answer to your question)
If you want to add stuff into HBox, simply write
ab.getChildren().addAll(your content here);

Reading Excel spreasheet using EPPlus

Could someone point me in the right direction on how to read a Excel spreasheet, loop through all the rows and columns to retreive value using EPPlus and MVC? So fare I see examples to create a spreasheet, but did not find any on opening an excel file and read values from it. Any help would be appreciated.
TIA
Sue..
Simple example
// Get the file we are going to process
var existingFile = new FileInfo(filePath);
// Open and read the XlSX file.
using (var package = new ExcelPackage(existingFile))
{
// Get the work book in the file
var workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
// Get the first worksheet
var currentWorksheet = workBook.Worksheets.First();
// read some data
object col1Header = currentWorksheet.Cells[1, 1].Value;
A simple example how you can read excel file using EPPlus in .net 4.5
public void readXLS(string FilePath)
{
FileInfo existingFile = new FileInfo(FilePath);
using (ExcelPackage package = new ExcelPackage(existingFile))
{
//get the first worksheet in the workbook
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int colCount = worksheet.Dimension.End.Column; //get Column Count
int rowCount = worksheet.Dimension.End.Row; //get row count
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= colCount; col++)
{
Console.WriteLine(" Row:" + row + " column:" + col + " Value:" + worksheet.Cells[row, col].Value.ToString().Trim());
}
}
}
}

PDFBox Out of memory when adding image

I am using PDFBox to extract data from my webapp and put it into a PDF. I have a method that draws the header on each PDF page. However, when I add an image to the each page, the document runs out of memory. I was wondering if anybody had any ideas on a solution? Here is my drawHeader method:
public static void drawHeader(PDDocument doc, PDPage page, PDPageContentStream contentStream, int[] columnWidths, int pageNumber) throws IOException {
contentStream.beginText();
PDFont font = PDType1Font.HELVETICA_BOLD;
contentStream.setFont(font, 24);
contentStream.moveTextPositionByAmount(50, 750);
contentStream.drawString("Producer License Report");
contentStream.endText();
contentStream.beginText();
contentStream.moveTextPositionByAmount(550, 750);
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 8);
contentStream.drawString("Page " + pageNumber);
contentStream.endText();
contentStream.drawLine(50, 740, 340, 740);
contentStream.drawLine(16, 680, 595, 680);
List<String> headerList = new LinkedList<String>();
headerList.add("NPN");
headerList.add("First Name");
headerList.add("Last Name");
headerList.add("Suffix");
headerList.add("License State");
headerList.add("Resident State");
headerList.add("License Number");
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 9);
float textx = 15;
float texty = 685;
InputStream in = new FileInputStream(new File("logo.jpg"));
PDJpeg img = new PDJpeg(doc, in);
contentStream.drawImage(img, 375, 720);
for (int i = 0; i < headerList.size(); i++) {
String text = headerList.get(i);
contentStream.beginText();
contentStream.moveTextPositionByAmount(textx, texty);
contentStream.drawString(text);
contentStream.endText();
textx += (columnWidths[i] * 6.5);
}
}
I found a solution! You have to create the Image-Object before opening the contentStream.
Example:
/* Step 1: Prepare the document.
*/
doc = new PDDocument();
PDPage page = new PDPage();
doc.addPage(page);
/* Step 2: Prepare the image
* PDJpeg is the class you use when dealing with jpg images.
* You will need to mention the jpg file and the document to which it is to be added
* Note that if you complete these steps after the creating the content stream the PDF
* file created will show "Out of memory" error.
*/
PDXObjectImage image = null;
image = new PDJpeg(doc, new FileInputStream("image.jpg"));
PDPageContentStream contentStream = new PDPageContentStream(doc,
page);
....
I'm trying to comment the answer by Timo Hoen but don't have enough rep yet...
Another issue I've found with the "out of memory" error is if the image is large, or you have tried to draw it off the page.
Start with your coordinates as 100, 100 and then work from there.
e.g. contentStream.drawImage(img, 100, 100);
Cheers,
Sam

Resources