ralfstuckert/pdfbox-layout

Need to add table and markup text in a same PDF page.

Opened this issue · 6 comments

Hi ralf,
Thanks for your pdfbox-layout liabrary.
I need a help, like i want to add table using Boxable in my pdf and some text formatting by using pdfbox-layout, but i am not able to use PDContentStream object on same page which is created by Documnet() constructor. even i saved the pdf file and re read the page and insert table in blank area which created by VerticalSpacer() constructor. but table is not create in that area instead of that it prints on next page.

Please help me on the same.

If you read into other postings on this page you will find, that a free version of iText is favoured instead of redesigning pdfbox-layout.
There is little chance that you will get help or a corrected/enhanced pdfbox-layout file ...

My workaround regarding tables was a column layout with frames and fixed widths of the text elements.
Maybe this can help you ...

Hi @arnthom ! Could you give me a simple example of your workaround, please? That might help me dividing the page into two columns with a column-width other than 50%.

Let's try ...

Here I have a table with 4 columns, the first one is larger than the others.
As you see in writeTable(), you may have to define more columns than you use, so they will not interfere with the other columns ...

If you set x columns, they will have identical withs. You can set the width of a column to be larger, so the text will wrap at the column width as you defined it. You may have to set more columns to shift the column to the correct place.

So in your case, you may use three columns and set the width of the first one to 66% of the page width. Then you populate the first and the third comumn with text.

You may experience a "column shift" when a page break occurs. I hope I have set a workaround to that in my approach ...
Good luck!

// Definition of columns
private final String[] texts = new String[] { "", "", "", "", "", };

// Definition of Page
protected float myPageWidth  = new PDPage(PDRectangle.A4).getMediaBox().getWidth();
protected float myPageHeight = new PDPage(PDRectangle.A4).getMediaBox().getHeight();
protected float maxDocWidth = myPageWidth - 100;


private void write() throws IOException {
	add("text col 1", "text col 2", "test col 3", "nothing");
	writeTable()
}

private void add(String toAdd0, String toAdd1, String toAdd2, String toAdd3) {
	texts[0] = texts[0] + toAdd0 + "\n";
	texts[1] = texts[1] + toAdd1 + "\n";
	texts[2] = texts[2] + toAdd2 + "\n";
	texts[3] = texts[3] + toAdd3 + "\n";
}

public void writeTable() throws IOException {
	String[] text = { texts[0], "", texts[1], texts[2], texts[3], "", };
	float[] widths = { maxDocWidth/3, 1, maxDocWidth/4, maxDocWidth/4, maxDocWidth/4, 1, };
	Alignment[] alignments = { Alignment.Left, Alignment.Left, Alignment.Left, Alignment.Right, Alignment.Right, Alignment.Right, };
	writeTable(text, widths, alignments, Color.LIGHT_GRAY, true);
}

public void writeTable(String[] texts, float[] widths, Alignment[] alignments, Color bgColor, boolean border) throws IOException {
	if (texts.length != alignments.length || texts.length != widths.length) {
		throw new Exception("wrong Definition of table: Lenght texts=" + texts.length + " alignments=" + alignments.length + " widths=" + widths.length );
	}
	pArray = new ParagraphExt[texts.length];
	ColumnLayout col = new ColumnLayout(texts.length, 5);
	col.setRemoveLeadingEmptyVerticalSpace(false);
	doc.add(col);
	for (int i = 0; i < texts.length; i++) {
		pArray[i] = getParagraph(alignments[i], widths[i]);
		if (i == 0) {
			try {
  				addMarkup(pArray[i], texts[i]);
			} catch (NoSuchMethodError e) {
				// color does noct work on Java 1.7, 
				String text = texts[i].replaceAll("\\{color:#((0)*|(f)*)\\}", "");
   				addMarkup(pArray[i], text);
			}
			FrameExt frame = new FrameExt(pArray[i], new Float(maxDocWidth), null);
			if (border) {
				frame.setShape(new Rect());
				frame.setBorder(Color.BLACK, new Stroke(0.5F));
				frame.setPadding(5, 5, 0, 10);
   				if (bgColor != null) {
   					frame.setBackgroundColor(bgColor);
   				}
			}
			if (border) {
				doc.add(frame);
   			} else {
   				doc.add(pArray[i]);
   			}
		} else {
			addMarkup(pArray[i], texts[i]);
			doc.add(pArray[i]);
		}
		// reset text element 
		texts[i] = ""; 
		if (i < texts.length - 1) {
			doc.add(ColumnLayout.NEWCOLUMN);
		}
	}
	doc.add(new VerticalLayout());
}
    /**
     * ParagraphExt does not split on page break and tries to put the whoöle table on one page 
     */
    public class ParagraphExt extends Paragraph {
    	
    	private float neededVerticalSpace;

    	/**    	 */
    	public ParagraphExt() {
    		super();
    	}

    	public void setNeededVerticalSpace(float f) {
    		neededVerticalSpace = f;
    	}
    	
    	// @Override
    	/* (non-Javadoc)
    	 * @see rst.pdfbox.layout.elements.Paragraph#divide(float, float)
    	 */
    	public Divided divide(float remainingHeight, float nextPageHeight) throws IOException {
    		
    		if (neededVerticalSpace > 0) {
        		if (neededVerticalSpace > remainingHeight && neededVerticalSpace <= nextPageHeight) {
        			return new Divided(new VerticalSpacer(remainingHeight), this);
        		}
    		} else {
        		if (getHeight() > remainingHeight && getHeight() <= nextPageHeight) {
        			return new Divided(new VerticalSpacer(remainingHeight), this);
        		}
    		}
    		return super.divide(remainingHeight, nextPageHeight);
    	}
    }
    protected ParagraphExt getParagraph(Alignment alignment, float maxWidth) {
    	ParagraphExt p = getParagraph(alignment);
    	p.setMaxWidth(maxWidth);
    	return p;
    }
    protected ParagraphExt getParagraph(Alignment alignment) {
    	ParagraphExt p = new ParagraphExt();
    	p.setAlignment(alignment);
    	p.setMaxWidth(maxDocWidth);
    	return p;
    }

Alright, thanks!

Just a note on this issue -- I ran into this and was able to use the supplied interfaces in pdfbox-layout (see ImageElement as one example) to draw a boxable table "in-flow" with Paragraphs, ImageElements etc.

Create a class to allow pdfbox-layout to draw the table.

public class TableElement implements Element, Drawable, Dividable, WidthRespecting {

...Implement draw which gives you the object boxable needs:

@Override
    public void draw(PDDocument pdDocument, PDPageContentStream pdPageContentStream, Position position, DrawListener drawListener) throws IOException {


        //todo - add real draw class
        drawTable(pdPageContentStream, pdDocument, position);


        if (drawListener != null) {
            drawListener.drawn(this, position, this.getWidth(), this.getHeight());
        }

    }

    private void drawTable(PDPageContentStream cos, PDDocument doc, Position position) {

        PDFont fontPlain = PDType1Font.HELVETICA;
        PDPage page = doc.getPage(doc.getNumberOfPages()-1);


//do your boxable stuff here and set things like height and width to fulfill interface methods
        BaseTable table = new BaseTable(yPosition, yStartNewPage,
                bottomMargin, tableWidth, margin, doc, page, true, drawContent);

        

--Scott

@si2-scotth
thanks for the idea. I'm now able to add a table into my pdf. the problem is that after the table is added, I cannot add anything else below it until next page. Can you help me with that?