iText 7: How can I insert diagrams into a `Document`? - itext

I am using iText 7.2.1.
According to the documentation, I can only find elements like Image, Div, List, Paragraph, Table can be inserted into Document.
I want to draw some diagrams and insert it into my document. I need them to be part of my content stream. The existing PdfCanvas or Canvas can not do that. They seems to accept only absolute positions.
Is there a way inserting diagrams in iText 7?

In a comment you clarified
I want to draw diagrams using PdfCanvas instructions. Is it possible that I don't have to specify absolute position, and the diagram automatically follow the previous paragraph, and next paragraphs automatically follow this diagram. Is SVG the only way to do this?
You can create your diagram in a PdfFormXObject which has its own coordinate system. PdfCanvas instances can also be constructed for form XObjects.
Then you can wrap that XObject in an iText Image which in turn you can add to an iText Document to be automatically positioned.
So for a PdfDocument pdfDocument and a Document document:
PdfFormXObject xobject = new PdfFormXObject(new Rectangle([... area for your diagram ...]));
PdfCanvas pdfCanvas = new PdfCanvas(xobject, pdfDocument);
[... draw diagram on pdfCanvas ...]
Image image = new Image(xobject);
document.add(image);

Related

SetFixedPosition of Parapgraph or Image results in wrong display order

With itext7 in VB.NET i create a PDF.
There I have this code-snippet:
Dim img As New Image(ImageDataFactory.Create(imagePath))
img.SetWidth(varImgWidth)
img.SetHeight(varImgHeight)
img.SetFixedPosition(100,100)
doc.add(img)
doc.add(new Paragraph("This is a test"))
The set position of the image overlaps with the text of the parapgraph. I expected, that the image is set to the document at the given position and then - afterwards - the text is "printed" above the image, because it is defined "after" the image in the code.
But what I see is, that the image positioned with SetFiexedPosition is always above other elements. I get the behaviour when positioning a text via SetFixedPosition on the Paragraph containing the text.
My question is: Is there any possibility to tell the element which is positioned, that it should be behind other elements.
Or - better question - is there any "positioning possibility" which allows a positioning of an element and considering the "order" in which it is "printed" in the code.
Do you understand what I mean?
(Sorry, it´s not easy for me to express it in English)
Thank you for any help
Regards
Benjamin

Writing to absolute position while using direct content

I am creating a pdf-document. First I add a table and some Texts to the PdfWriter. Now I want to add a costum template (including images and texts): I have to get the direct Content, which ist a layer over the PdfWriter-layer:
over= PdfWriter.getDirectContent();
I want to set the template exactly after the content on PdfWriter-layer.
I can use
writer.getVerticalPosition(true)
for my calculation of y-Position on PdfWriter-layer.
This way I can add the costum template to the upper layer at that position. Now back to PdfWriter-layer how can I set the position of PdfWriter-layer after the tempalte on over-layer?!
Can somebody help?
Thanks in advance.
Mixing content added with document.add() and direct content us always a delicate operation. You need to know the height of the custom template and then add some white space that matches that height. However: what are you going to do if the content of the custom template doesn't match the page?
I would advise against your plans, and I would recommend another approach.
I am assuming that your custom template is a PdfTemplate object. In that case, you can wrap this object inside an Image object, and use document.add() to add the template.
See for instance: Changing Font on PDF Rotated Text
In this example, we create a PdfTemplate with a bar code and some text:
PdfTemplate template = canvas.createTemplate(rect.getWidth(), rect.getHeight() + 10);
ColumnText.showTextAligned(template, Element.ALIGN_LEFT,
new Phrase("DARK GRAY", regular), 0, rect.getHeight() + 2, 0);
barcode.placeBarcode(template, BaseColor.BLACK, BaseColor.BLACK);
We want to add this template to a document with document.add(), so we wrap the template inside an Image object:
Image image = Image.getInstance(template);
We can now add this image to the document:
document.add(image);
Afterwards, we can add extra content:
Paragraph p3 = new Paragraph("SMALL", regular);
p3.setAlignment(Element.ALIGN_CENTER);
document.add(p3);
That content is added under the template at the right position. You don't need to worry anymore about getting the Y position with getVerticalPosition() and you don't need to worry about setting the Y position after adding the template. If the template doesn't fit on the current page, it will automatically be moved to the next page.
Important: Maybe you are worried about the resolution of your template. You shouldn't be. If the template consists of vector data, wrapping that data inside an Image object won't change it into raster data. The vector data will be preserved. This is important in the bar code example, because you don't want the quality of your bar code to deteriorate by making it a raster image.

Find location last object on PDF page using iTextSharp

How can I find the location and the height of the last object on a PDF page? There is no footer. I'm wanting to stamp a template below the last item. Not in the footer but directly below the last line of text. The amount of text may vary so I need to calculate if there is enough room at the bottom of the page to insert my template.
Thanks for any help,
Aaron
To determine where text and (bitmap) images on a given page end, have a look at the iText in Action, 2nd edition example ShowTextMargins which parses a PDF and adds a rectangle showing the text and (bitmap) images margin.
PdfReader reader = new PdfReader(src);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(RESULT));
TextMarginFinder finder;
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
finder = parser.processContent(i, new TextMarginFinder());
PdfContentByte cb = stamper.getOverContent(i);
cb.rectangle(finder.getLlx(), finder.getLly(),
finder.getWidth(), finder.getHeight());
cb.stroke();
}
stamper.close();
reader.close();
Be aware, though, that this mechanism ignores vector graphics (often also used for underlining text, colored backgrounds, and decorative separating lines) because the underlying iText parser package still (as of iText version 5.4.5) ignores them.
Update: As of version 5.5.6 iText extends the parser package to also include vector graphics parsing. This allows for an extension of the original TextMarginFinder class implementing the new ExtRenderListener methods as presented in this answer resulting in an analogous class MarginFinder which does not only consider text but also other kind of content, e.g. bitmap images and vector graphics.

How to add a table to a new page in an ItextSharp PdfStamper

I'm using ItextSharp to populate a Pdf template with data. The template is a single page form with a number of input fields. I can create a PdfStamper and populate the fields with no problem, however, I want to add a second page to the stamper and then add a dynamically created PdfPtable to that page. I can add a page using stamper.InsertPage(2,reader.GetpageSize()) but I can not work out how to add the table to the page.
Any help would be much appreciated.
Get your new page's PdfContentByte, then use PdfPTable.WriteSelectedRows(). There are 4 different overrides providing you with various options.
WriteSelectedRows just takes row [& column] numbers to draw, an X/Y location, and a PdfContentByte or array of same. This means it won't do any page breaking or width validation or what have you. It'll just draw what you ask it to draw, where you ask it to draw it. You have to do all the layout yourself.

How to create single PDF document with both portrait and landscape page using iTextSharp

I have been able to create portrait pages, and landscape pages in separate documents, but now require to do this in one document. I am using ITextSharp library and the document.setpagesize seems to apply to all pages. Is this correct?
I was using PDFLib and changing page orientation was not a problem in that library.
Any suggestions?
Paul.
It should only apply to pages rendered after that call.
Document doc = new Document(PageSize.WHAT_EVER);
PdfWriter writer = new PdfWriter( doc, outputStream );
doc.open();
// so long as you set the page size before add()ing anything, it should ignore the
// page sized used in the constructor.
doc.setPageSize(PageSize.LETTER); // 8.5" x 11"
// actually, I think you need to call newPage or actually add enough stuff to start a new page
// for setPageSize to take effect. setPageSize by itself won't do the trick.
doc.add(stuffToFillALetterPageButNotStartANewOne);
doc.setPageSize(new Rectangle(792f, 612f)); // 11" x 8.5"
doc.add(moreStuffToFillALandscapePageThusStartingANewPage);
doc.close();
The resulting PDF should have two pages. The will be 8.5x11, the other 11x8.5. Note that iText[sharp] won't generate rotated pages (8.5"x11" # 90 degrees (or 270... shudder)). It's... sharper than that.
Dealing with rotated pages is Not Fun. At least I've never run into one that was 8.5x11 at 180 rotation in my TOO_MANY_YEARS of experience with PDF. I'd just have to fly into a murderous rage at that point. Or maybe I should generate some PDFs that way just to see who I could catch with their pants down.
[insert fiendish cackle here]