-
-
Notifications
You must be signed in to change notification settings - Fork 154
Home
Welcome to the boxable wiki!
- Creating text outside of the table
- Creating simple table
- Creating image
- How to set A4 Landscape?
- How to set A4 Portrait?
- How to get table height dynamically?
- Retrieving current table page
- Retrieving current y position after multipage table
- How to draw two tables with same y position?
- How to make inner table?
Okay, first things first. What we always need is our PDDocument and PDPage :
PDPage myPage = new PDPage(PDRectangle.A4);
PDDocument mainDocument = new PDDocument();
If we want to add something else in our PDF document except tables (i.e some text, image etc.) then we will need content stream:
PDPageContentStream contentStream = new PDPageContentStream(mainDocument, myPage);
That is something that we always need. Now, how about random text in PDF document, i.e our document title
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 22);
contentStream.newLineAtOffset(50, 700);
contentStream.showText("Document title");
contentStream.endText();
Also it is pretty easy to write some text inside PDF Document with PDStreamUtils.write(final PDPageContentStream stream, final String text, final PDFont font, final float fontSize, final float x, final float y, final Color color)
method where :
- text - The text which will be displayed.
- font - The font of the text
- fontSize - The font size of the text
- x - Start X coordinate for text.
- y - Start Y coordinate for text.
- color - Color of the text
Maybe it is better to put that in some context, here is second example how to write document title with method mention above.
[...]
private PDPageContentStream cos;
private PDPage page;
private PDFont font = PDType1Font.HELVETICA;
private float leftMargin = 50;
private marginBetweenYElements = 10;
private float titleFontSize = 18;
[...]
private void drawPageTitle() throws IOException {
// draw document title first
PDStreamUtils.write(cos, "Document title", font, titleFontSize, leftMargin, yPosition,
Color.BLACK);
// drop Y position with default margin between vertical elements
yPosition -= marginBetweenYElements;
}
What about simple table? Say no more:
//Dummy Table
float margin = 50;
// starting y position is whole page height subtracted by top and bottom margin
float yStartNewPage = myPage.getMediaBox().getHeight() - (2 * margin);
// we want table across whole page width (subtracted by left and right margin ofcourse)
float tableWidth = myPage.getMediaBox().getWidth() - (2 * margin);
boolean drawContent = true;
float yStart = yStartNewPage;
float bottomMargin = 70;
// y position is your coordinate of top left corner of the table
float yPosition = 550;
BaseTable table = new BaseTable(yPosition, yStartNewPage, bottomMargin, tableWidth, margin, mainDocument, myPage, true, drawContent);
Row<PDPage> headerRow = table.createRow(15f);
Cell<PDPage> cell = headerRow.createCell(100, "Header");
table.addHeaderRow(headerRow);
Row<PDPage> row = table.createRow(12);
cell = row.createCell(30, "Data 1");
cell = row.createCell(70, "Some value");
table.draw();
contentStream.close();
mainDocument.addPage(myPage);
mainDocument.save("testfile.pdf");
mainDocument.close();
It is very similar process just like writing text. All work is done by ''Ìmage.draw(final PDDocument doc, final PDPageContentStream stream, float x, float y)'' method where:
- doc - PDDocument where drawing will be applied
- stream - PDPageContentStream where drawing will be applied
- x - X coordinate for image drawing
- y - Y coordinate for image drawing
Lets put that in context, for example, drawing logo on our PDF document:
[...]
Image image = new Image(ImageIO.read(new File("/../logo.png")));
// imagine we have pretty big logo and we want scale that a little bit
float imageWidth = 75;
image = image.scaleByWidth(imageWidth);
image.draw(document, contentStream, xPosition, yPosition)
Important Always close your contentStream before saving the document!
[...]
contentStream.close();
// Save the document
File file = new File("test.pdf");
System.out.println("Sample file saved at : " + file.getAbsolutePath());
Files.createParentDirs(file);
doc.save(file);
doc.close();
If you don’t do this you will be getting something like:
java.lang.IllegalStateException: Cannot read while there is an open stream writer
at org.apache.pdfbox.cos.COSStream.createRawInputStream(COSStream.java:128)
[...]
Some other interesting methods for drawing and image scaling are:
draw(final PDDocument doc, final PDPageContentStream stream, float x, float y)
scaleByWidth(float width)
scaleByHeight(float height)
scale(float boundWidth, float boundHeight)
And that’s it! You are ready to go!
PDPage page = new PDPage(new PDRectangle(PDRectangle.A4.getHeight(), PDRectangle.A4.getWidth()));
PDPage page = new PDPage(PDRectange.A4);
float tableHeight = table.getHeaderAndDataHeight();
IMPORTANT: Use this method witch caution! Method doesn't acknowledge possible page break !!
If table is displayed on multiple pages the current page can be obtained with table.getCurrentPage()
.
Something like :
[...]
// did we change the page?
if (table.getCurrentPage() != page) {
cos.close();
page = table.getCurrentPage();
cos = new PDPageContentStream(document, page, true, true);
}
It's pretty straightforward as:
yStart = table.draw();
This gives you yStart position exactly on the end of table so it would be better to secure more space for drawing another table,text,image with additional, let's say 50 --> yStart = table.draw() - 50
;
Let's say that we want two tables by each other (pay attention on spaceBetweenTables
variable and x/y positioning of the tables!)
int startNewPageY = 700;
int bottomMargin = 100;
int leftMargin = 25;
PDPage currentPage = new PDPage();
int spaceBetweenTables = 50;
// we want 2 tables so our table width is 50% of page width without left and right margin AND provided space between tables
float tableWidth = 0.5f * (currentPage.getMediaBox().getWidth() - (2 * leftMargin)- spaceBetweenTables);
PDDocument document = new PDDocument();
document.addPage(currentPage);
BaseTable table1 = new BaseTable(700, startNewPageY, bottomMargin, tableWidth, leftMargin, document,
currentPage, true, true);
[...]
table1.draw();
// pay attention where start x position for this table -> left margin + first table width + space between our tables
BaseTable table2 = new BaseTable(700, startNewPageY, bottomMargin, tableWidth, leftMargin + tableWidth + spaceBetweenTables, document,
currentPage, true, true);
[...]
table2.draw();
(Same principle is if you go with DataTable
implementation)
Then we should get something like this:
The same principle is for multiple tables where we need only to adjust tableWidth
variable and BaseTable
's argument that is responsible for x positioning.
The best way to make inner table is using TableCell
class with related HTML tags (<table>, <tr>, <td>
)
Something like (making 2x2 inner table):
Cell<PDPage> cell = row.createTableCell((100 / 3f),"<table><tr><td>First row, first value</td><td>First row, second value</td></tr><tr><td>Second row, first value</td><td>Second row, second value</td></tr></table>",
doc, page, yStart, topMargin, bottomMargin);
And that's it! You just created inner 2x2 table. If you want to see more please check SampleTest10()
for more.
Here is small PDF output from SampleTest10()
Special thanks to :
=======
Copyright 2017
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.