I have a use case that I cannot figure out how to implement.
I'm using headless chrome to export a rich text editor as a pdf and then I need to cut out a part of the created PDF and embed it as a pdf annotation in another parent pdf such that the annotation looks exactly the same as the section I cut out from the created PDF.
I'm able to correctly calculate and cut the precise area I need from the created PDF using instructions provided by:
https://developers.itextpdf.com/examples/stamping-content-existing-pdfs-itext5/cut-and-paste-content-page
PdfTemplate template2 = cb.createTemplate(pageSize.getWidth(), pageSize.getHeight());
template2.rectangle(toMove.getLeft(), toMove.getBottom(), toMove.getWidth(), toMove.getHeight());
template2.clip();
template2.newPath();
template2.addTemplate(page, 0, 0);
cb.addTemplate(template1, 0, 0);
cb.addTemplate(template2, -20, -2);
I would like to add the PDFTemplate via a PdfStamper.
Is this possible? If not now can I achieve this with another method?
In the example you refer to, you obtain cb like this:
PdfContentByte cb = writer.getDirectContent();
When using PdfStamper, you can obtain cb like this:
PdfContentByte cb = stamper.getUnderContent(p);
Or like this:
PdfContentByte cb = stamper.getOverContent(p);
The former method will add the new content under the existing content; the latter method will add the new content on top of the existing content. In these lines p is a page number (from 1 to the total number of pages of the existing document). See How to superimpose pages from existing documents into another document? for an example.
If you want to add new pages to an existing document, use the insertPage() method as explained in How to add blank pages to an existing PDF in java? Once you have added a blank page, you can add a PdfTemplate to it.
Related
I'm using IText to generate a pdf for my project. Using help from this
How to generate a Table of Contents "TOC" with iText?, I was able to generate a pdf with TOC. However I'm unable to figure out how can I navigate to a page when page number is clicked. I tried adding action inside the pdf template but that doesn't seem to work. Thanks in advance for your help.
This is what I've added to the answer already given in the linked question:
final PdfTemplate template2 = this.tocPlaceholder.get("Test");
template2.beginText();
template2.setFontAndSize(baseFont, 12);
template2.setTextMatrix(50 - this.baseFont.getWidthPoint(String.valueOf(writer.getPageNumber()), 12), 0);
template2.showText(String.valueOf(writer.getPageNumber()));
PdfAction action = PdfAction.gotoLocalPage(writer.getPageNumber(),new PdfDestination(0),writer);
template2.setAction(action , 0,0,0,0);
template2.endText();
I am using PdfFormXObject pageCopy = sourcePage.CopyAsFormXObject(pdf); to then insert pageCopy into a new PDF page using pdfCanvas.AddXObjectFittedIntoRectangle. The copied page is visible in the new PDF as expected, but it how has it's 'hidden' OCGs visible.
The reason I am doing this is to be able to take a PDF page, scale and crop it and add it to a new PDF where it may be collated with other contents.
Is there a way to remove OCG PDF content prior to create the XObject, or is there a different way of achieving my goal without using the XObject route that allows me to maintain the 'off' status of hidden OCGs
OCG removal functionality is not yet available in iText 7.
There is, however, a workaround that you can try to apply: we can copy all the information about OCGs from your source document to the target document which should create the same OCGs in the target document and preserve default on/off states.
To copy the OCGs, you can copy a page from one document to another one (which is going to copy all the OCGs) and then remove that page.
When the OCG removal functionality becomes available in iText the approach would become cleaner but for now you can use the code similar to the following:
PdfDocument sourceDocument = new PdfDocument(new PdfReader(sourcePdfPath));
PdfDocument targetDocument = new PdfDocument(new PdfWriter(targetPdfPath));
PdfFormXObject pageCopy = sourceDocument.getFirstPage().copyAsFormXObject(targetDocument);
PdfPage page = targetDocument.addNewPage();
PdfCanvas canvas = new PdfCanvas(page);
canvas.addXObject(pageCopy);
// Workaround: copying the page from source document to destination document also copies OCGs
sourceDocument.copyPagesTo(1, 1, targetDocument);
// Workaround: remove the page that we only copied to make sure OCGs are copied
targetDocument.removePage(targetDocument.getNumberOfPages());
sourceDocument.close();
targetDocument.close();
I need to create a small tool that adds a hyperlink on the first page of a PDF file. I'm using Apache PDFBox to read the pdf files.
Any ideas how to add a hyperlink on a page using this library?
I found this question: how to set hyperlink in content using pdfbox, but this doesn't work.
I just want to add a hyperlink on the first page of a pdf file.
File file = new File(filename);
PDDocument doc = PDDocument.load(file);
PDPage page = doc.getPage(0);
...
I have at least 2 problems with the solution that I found on this question:
The method drawString(String) in the type PDPageContentStream is not applicable for the arguments (PDAnnotationLink)
colourBlue is not initialized
I would prefer to add the hyperlink at the bottom of the page with the URL centered. But for the moment any suggestion will help
First of all, you need to create a PDAnnotationLink like this:
PDAnnotationLink link = new PDAnnotationLink();
The link should have an action:
PDActionURI actionURI = new PDActionURI();
actionUri.setURI("http://www.Google.com");
link.setAction(action);
Finally, you need to define a rectangle at the desired position and finally add the link to the page's annotations.
PDRectangle pdRectangle = new PDRectangle();
pdRectangle.setLowerLeftX(...);
pdRectangle.setLowerLeftY(...);
pdRectangle.setUpperRightX(...);
pdRectangle.setUpperRightY(...);
link.setRectangle(pdRectangle);
page.getAnnotations().add(link);
If you want you can also add an underline for the link by calling the setBorderStyle(...) methid.
Hope this works for you !
If you want to add some text, then you need to create a PDPageContentStream like this:
PDPageContentStream contentStream = new PDPageContentStream(doc, page);
contentStream.beginText();
contentStream.newLineAtOffset(..., ...);
contentStream.showText(...);
contentStream.endText();
contentStream.close();
The newLineAtOffset(..., ...) method is used for positioning the text at the desired location.
P.S. Sorry for the bad indentation but it is pretty hard to write on the mobile. If you need any further help you can even write me a private message in Romanian.
I am developing a Java program with the following requirements:
The application will take 5 input fields and 3 images (browse and "attach" to the Java application).
Once the "form" is completed it will be submitted using a button called "submit".
Once submitted the JAVA application will create a PDF file with the 5 inputed text and the 3 attached images.
I should be able to control which goes to which page number.
How do I implement such a solution with iText?
The application will take 5 input fields and 3 images (browse and "attach" to the Java application).
Once the "form" is completed it will be submitted using a button called "submit".
These first two requirements are unclear; are they to be implemented in a Java GUI (AWT? Swing? FX?), in some independent web UI (Plain HTML? Vaadin?), or in some derived UI (Portlet? ...)?
But as the question title "Creating PDF using JAVA (Netbeans) with images and multi pages" focuses on the PDF creation, let's look at the third and fourth requirements.
Once submitted the JAVA application will create a PDF file with the 5 inputed text and the 3 attached images.
I should be able to control which goes to which page number.
Let's assume you already have those inputs in the variables
String text1, text2, text3, text4, text5;
byte[] image1, image2, image3;
The framework
With iText you now create the document like this:
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfWriter;
...
// where you want to create the PDF;
// use a FileOutputStream for creating the PDF in the file system
// use a ByteArrayOutputStream for creating the PDF in a byte[] in memory
OutputStream output = ...;
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, output);
document.open();
// Add content for the first page(s)
...
// Start e new page
document.newPage();
// Add content for the next page(s)
...
// Start a new page
document.newPage();
// etc etc
document.close();
Adding text
You can add text in one of the Add content for the ... page(s) sections using
import com.itextpdf.text.Paragraph;
...
document.add(new Paragraph(text1));
Adding an image
You can add an image in one of the Add content for the ... page(s) sections using
import com.itextpdf.text.Image;
...
document.add(Image.getInstance(image1));
Adding at a given position
Adding text or images as described above leaves the layout details to iText, and iText fills the page from top to bottom except some margins.
If you want to control the positioning of the content yourself (which also means you have to take care that the content parts do not overlap or are drawn outside the page area), you can do so like this:
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.Phrase;
...
PdfContentByte canvas = writer.getDirectContent();
Phrase phrase = new Phrase(text2);
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, 200, 572, 0);
Image img = Image.getInstance(image2);
img.setAbsolutePosition(200, 200);
canvas.addImage(img);
And there are many more options how to manipulate your content, e.g. choosing a font, choosing text sizes, scaling images, rotating content, ..., simply have a look at the iText samples from the book iText in Action - Second Edition.
You can use XSL-FO. A basic example here. After this, you can search and add other options for your PDF.
I try to fill a PDF form with PDFBox and I managed to do it well with a portrait oriented document. But I have a problem when filling a document in landscape mode. The fields are filled up, but the text orientation is not good. It appear vertically like if it was still in portrait but in a rotation of 90 degrees.
Here is my simplified code:
PDDocument pdfDoc = PDDocument.load(MY_FILE);
PDDocumentCatalog docCatalog = pdfDoc.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
acroForm.getField("aAddressLine1").setValue("ADDRESS1_HERE");
acroForm.getField("aAddressLine2").setValue("ADDRESS1_HERE");
acroForm.getField("country").setValue("COUNTRY_HERE");
pdfDoc.save(PATH_HERE);
pdfDoc.close();
Did you manage to fill a PDF document in landscape mode?
Thanks for your help.
The short answer
I'm afraid PDFBox does not yet (as of version 1.8.2) allow you to fill in landscape PDFs like the one you provided because it does not seem to query and factor in informations about the page the form field is located on.
The long answer
There are different ways you can define a page to be A4 landscape:
You can define it to have the A4 landscape dimensions directly by means of a media box definition:
/MediaBox [0, 0, 842, 595]
In this case the coordinates of your aAddressLine1 would be
/Rect[23.1711 86.8914 292.121 100.132]
or you can define it to have the A4 portrait dimensions and being rotated by 90° (or 270° obviously):
/MediaBox [0, 0, 595, 842]
/Rotate 90
In this case the coordinates of your aAddressLine1 are
/Rect[86.8914 23.1711 100.132 292.121]
Your example document uses the latter method.
Now PDFBox, when creating an appearance stream for that field, only looks at the rectangle defining the field but ignores the properties of the page. Thus, PDFBox sees a very narrow and very high textfield and fills it in just like that. It is completely unaware that the result will be rotated in a PDF viewer.
What it should have done is to also look at the page the field is located on. If that page has a /Rotate entry, it should create an appearance stream for the field which displays the text rotated in the opposite direction.
Alternatives
In a comment you also asked
Do you know another library I could use if PDFBox can't do what I want?
I have tested the feat with iText 5.4.2:
PdfReader reader = new PdfReader(MY_FILE);
OutputStream os = new FileOutputStream(PATH_HERE);
PdfStamper stamper = new PdfStamper(reader, os);
AcroFields acroFields = stamper.getAcroFields();
acroFields.setField("aAddressLine1", "ADDRESS1_HERE");
acroFields.setField("aAddressLine2", "ADDRESS1_HERE");
stamper.close();
(The free iText version is licensed under the AGPL; you have to decide whether that's ok for your project. There is a commercial license, too, if it's not ok.)
I'm sure other PDF libraries also can do that, it's not too exotic a feature after all...
But I also tested PDF Clown 0.1.3 (trunk version), which did not work either:
File file = new File(MY_FILE);
Document document = file.getDocument();
Form form = document.getForm();
form.getFields().get("aAddressLine1").setValue("ADDRESS1_HERE");
form.getFields().get("aAddressLine2").setValue("ADDRESS1_HERE");
file.save(new java.io.File(PATH_HERE), SerializationModeEnum.Incremental);
file.close();