PDFBox - how to create table of contents - java

Is there a way to create a table of contents using Java PDFBox library?
The table of contents should be clickable (jump to the right page)
Thanks.

There's no simple method for doing this, but here's an approach. I haven't figured out how to attach links directly to text, so my approach means you have to draw the annotations as rectangles and the text separately. It's a bit rough around the edges, but it works.
// there are other types of destinations, choose what is appropriate
PDPageXYZDestination dest = new PDPageXYZDestination();
// the indexing is odd here. if you are doing this on the first page of the pdf
// that page is -1, the next is 0, the next is 1 and so on. odd.
dest.setPageNumber(3);
dest.setLeft(0);
dest.setTop(0); // link to top of page, this is the XYZ part
PDActionGoTo action = new PDActionGoTo();
action.setDestination(dest);
PDAnnotationLink link = new PDAnnotationLink();
link.setAction(action);
link.setDestination(dest);
PDRectangle rect = new PDRectangle();
// just making these x,y coords up for sample
rect.setLowerLeftX(72);
rect.setLowerLeftY(600);
rect.setUpperRightX(144);
rect.setUpperRightY(620);
PDPage page = // however you are getting your table of contents page, eg new PDPage() or doc.getDocumentCatalog().getAllPages().get(0)
page.getAnnotations().add(link);
PDPageContentStream stream = new PDPageContentStream(doc, page, true, true);
stream.beginText();
stream.setTextTranslation(85, 600); // made these up, have to test to see if padding is correct
stream.drawString("Page 1");
stream.endText();
stream.close();
Phew! That's a lotta code. That should get you on your way. You can make the rectangle the same color as your document background if you want it to look like they are just clicking a link, but that requires more experimentation.

Related

Fit iText 7 Table to Single Page with Images using JPype

I am attempting to fit all the content of a table to a single A4 PDF.
I found another SO article linked to the itextpdf page here on the same topic
However, I am not certain how it is supposed to be implemented. I have the above code converted to JPype and it seems to run. But I do not get the desired effect.
I want to be able to add images to this table, and have it size appropriately so that it maintains a single A4 page.
Source and example on my github page here:
https://github.com/krowvin/jpypeitext7example
Example PDF
Source
Suppose that this is the table to be fully fit into an A4 page:
Table table = new Table(2);
for (int i = 0; i < 100; i++) {
table.addCell(new Cell().add(new Paragraph(i + " Hello")));
table.addCell(new Cell().add(new Paragraph(i + " World")));
}
Since it's too long to be fully fit via usual layout flow (e.g. Document#add), we should somehow scale it. But first of all, let us find how much space this table occupies if the page to be placed upon is boundless:
LayoutResult result = table.createRendererSubTree().setParent(doc.getRenderer())
.layout(new LayoutContext(new LayoutArea(1, new Rectangle(10000, 10000))));
Rectangle occupiedRectangle = result.getOccupiedArea().getBBox();
Now let's create a form xobject of this table, which we will scale a few lines below:
PdfFormXObject xObject = new PdfFormXObject(new Rectangle(occupiedRectangle.getWidth(), occupiedRectangle.getHeight()));
new Canvas(xObject, pdfDoc).add(table).close();
So now we have the xObject of the table, the only question is how to fit it, e.g. which scale coefficients to apply:
double coefficient = Math.min(PageSize.A4.getWidth() / occupiedRectangle.getWidth(),
PageSize.A4.getHeight() / occupiedRectangle.getHeight());
We're almost done: now let's add the scaled version of the table to the document's page:
new PdfCanvas(pdfDoc.addNewPage())
.saveState()
.concatMatrix(coefficient, 0, 0, coefficient, 0, 0)
.addXObject(xObject)
.restoreState();
And that's it:

How to add a FormField to section without a position using iText?

In want to add interactive formfields like checkboxes to a newly created multiple page PDF, in the example from iText the code looks like this:
PdfContentByte canvas = writer.getDirectContent();
Rectangle rect = new Rectangle(180, 806 * 40, 200, 788 * 40);
RadioCheckField checkbox = new RadioCheckField(writer, rect, "box1", "Yes");
PdfFormField field = checkbox.getCheckField();
writer.addAnnotation(field);
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, new Phrase("checkbox1", normal), 210, 790 * 40, 0);
But this uses absolute positions and I don't know the position because the content before the field has optional images and text parts, where I don't know how many lines they take.
I am also using Chapters and Sections, so I would like to use something like this:
Section section = chap.addSection(new Paragraph("sectionTitel",header2));
section.add(new Paragraph("line before field"));
//add FormField
section.add(field);
section.add(new Paragraph("line after field"));
Have you an idea how to do something like this or how to get the position from the line before ?
Check this example for displaying checkboxes or radiobuttons without specifying positions. You need to use PdfPTable. http://itextpdf.com/sandbox/acroforms/CreateRadioInTable . There is one issue for displaying radiobuttons on multiple pages which I have posted here Issue with iText RadioCheckField when displayed on multiple pages and still waiting for answers

iText formatting problems

Context
I've been working on dynamic PDF generation for a while now, and I've come across my final requirement. Alas, it's a nightmare. I'm using the iText library, version 2.1.7.
I'm basically trying to get a formatting like the top row (which I just mocked up in paint). The other rows are how it looks at the moment, but I'm having some real trouble with getting them to line up properly!
Code
The code being used to generate each color coded block is here:
String currentPrice = p.getPrice();
String timeStr = p.getTime();
Chunk price = new Chunk(currentPrice);
Chunk time = (Chunk) generatePdfElement("Timestamp", timeStr);
if (priceDbl > lastPrice) {
// set color to blue.
price.setBackground(WebColors.getRGBColor("#7777FF"));
time.setBackground(WebColors.getRGBColor("#7777FF"));
} else if (priceDbl < lastPrice) {
// set to red.
price.setBackground(WebColors.getRGBColor("#FF0000"));
time.setBackground(WebColors.getRGBColor("#FF0000"));
}
Paragraph pricePara = new Paragraph();
pricePara.add(price);
pricePara.add(generateBreakLine());
pricePara.add(time);
pricePara.add(generateBreakLine());
// Add the new price data to the list of all the prices for this cell.
allPrices.add(pricePara);
allPrices is then added to a paragraph and put into the cell:
Paragraph pricesCellValue = new Paragraph();
pricesCellValue.addAll(allPrices);
PdfPCell pricesCell = new PdfPCell(pricesCellValue);
pricesCell.setBackgroundColor(WebColors.getRGBColor(getRowStr()));
selectionsTable.addCell(pricesCell);
// Add each cell to the table to create the row.
The approaches I've tried
I tried the obvious, which was removing the last breakline from each Chunk. This didn't work, and it just looked exactly the same, although each Chunk was closer together.
I also tried changing from Paragraph to Phrase, which means the code looked like this:
Phrase pricePara = new Phrase();
pricePara.add(price);
pricePara.add(generateBreakLine());
pricePara.add(time);
//pricePara.add(generateBreakLine());
// Add the new price data to the list of all the prices for this cell.
allPrices.add(pricePara);
And this was the result:
So now I'm fresh out of ideas! Does anyone else have any suggestions, or some experience with iText in this area?
Edit
Just for clarity, generateBreakLine() generates a new empty Paragraph object.
I used a nested PdfPTable in the last cell, to format the positioning of each Phrase. Works like a dream!

Drawing directed edges programmatically in Prefuse

I use the following code to display a graph:
graph = new Graph(true);
vis = new Visualization();
vis.add(GRAPH, graph);
CustomLabelRenderer re = new CustomLabelRenderer();
re.setImageField(NODE_TYPE_IMAGE);
re.setImagePosition(Constants.TOP);
EdgeRenderer edgeRenderer = new EdgeRenderer(Constants.EDGE_TYPE_LINE, Constants.EDGE_ARROW_FORWARD);
edgeRenderer.setArrowType(Constants.EDGE_ARROW_FORWARD);
edgeRenderer.setArrowHeadSize(10, 10);
DefaultRendererFactory factory = new DefaultRendererFactory(re, edgeRenderer);
factory.add(new InGroupPredicate(EDGE_DECORATORS), new LabelRenderer(VisualItem.LABEL));
vis.setRendererFactory(factory);
As you can see instantiate the graph to use directed edges. Afterwards I set the EdgeRenderer to use arrow heads. However, I can't see any arrows on my edges, but just plain lines. What am I doing wrong?
That's how I add edges:
graph.addEdge(node1, node2);
You need to set the FILLCOLOR for edges:
filter.add(new ColorAction(edges, VisualItem.FILLCOLOR,
ColorLib.rgb(100,100,100));
I reproduce the problem with the RadialGraphView demo and I did not need any changes to the source code except for this line. (Though, I had to change the data file.)

iText 5 header and footer

how I can add in my PDF page the header and the footer?
I wanna a table with 3 column in header and other table, 3 column in the footer.
My page could be A3 or A4, and landscape or portrait.
Can anyone help me? I can not found on internet good examples.
Thanks!
Tommaso
Create a class MyPageEventListener that extends PdfPageEventHelper
Add a page event listener to the PdfWriter object
In the onEndPage method of MyPageEventListener class, put the code
for header/footer
Example:
public class MyPageEventListener extends PdfPageEventHelper {
. . .
#Override
public void onEndPage(PdfWriter writer, Document document) {
//code skeleton to write page header
PdfPTable tbl = new PdfPTable(3);
tbl.addCell("1st cell");
tbl.addCell("2nd cell");
tbl.addCell("3rd cell");
float x = document.leftMargin();
float hei = getMyHeaderHeight(); //custom method that return header's height
//align bottom between page edge and page margin
float y = document.top() + hei;
//write the table
tbl.writeSelectedRows(0, -1, x, y, writer.getDirectContent());
}
}
to register the listener simply do
writer.setPageEvent(new MyPageEventListener());
The easiest way to do this is first generate the contents of your entire PDF in memory, then once all the pages have been created you need to open the in-memory PDF in the pdfStamper and iterate through all the pages adding in the header and footer objects are the correct coordinates.
If you do a quick google search of adding page numbers in itextPDF you will find a number of examples that you can quickly adapt for your needs.
The key is that it is done after you create the pdf, not before.

Categories

Resources