I am trying to use #aaronbartell example, to place the text at required (absolute) position in the PDF document. please give me some direction, thanks.
Example:
private static void absText(String text, int x, int y) {
try {
PdfContentByte cb = writer.getDirectContent();
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
cb.saveState();
cb.beginText();
cb.moveText(x, y);
cb.setFontAndSize(bf, 12);
cb.showText(text);
cb.endText();
cb.restoreState();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
If you use iText, you create a PDF document in 5 steps"
Create a Document instance
Create a PdfWriter instance
Open the document
Add content
Close the document
In your question, you do not create the PdfWriter instance (unless it's a global variable). In your comment, you do not open the document (you've skipped step 3 and this step is essential in the document creation process).
Take the code from your comment, and add the following line at the appropriate place:
document.open();
The appropriate place is after the line where you create the PdfWriter instance and before you start using the writer instance.
Update
In your comment, you are now sharing some code that contains a logical error.
Your main method pdfGeneration() (probably) contains the five steps in the creating process:
You create a Document instance
You create a PdfWriter instance that writes bytes to a file My First PDF Doc.pdf
You open the document
You call a method setPara() that is supposed to add content
You close the document (not visible in your code)
The logical error can be found in the setPara() method. In this method, you repeat the five steps. You create a new Document instance (there's no need to do this) and you create a new PdfWriter instance that creates a new file My First PDF Doc.pdf. This throws an exception, because that file is already in use!
You should change setPara() like this:
public void setPara(PdfContentByte canvas, Phrase p, float x, float y) {
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, x, y, 0);
}
You should call this method from your main method like this:
setPara(writer.getDirectContent(), new Phrase(text), x, y);
Of course: as the setPara() method is little more than a reduced version of the showTextAligned() method that already exists in iText, you may want to use that method directly. For instance: use this in your main method, instead of introducing a setPara() method:
Phrase phrase = new Phrase("Some text", new Font());
PdfContentByte canvas = writer.getDirectContent();
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, phrase, 20, 20, 0);
Related
I am creating a pdf with android itext lib. it shows complete data in single page. i want to split the single page to A4 size multiple pages with page number on bottom.
private void callDocument(File file, Bitmap screen) throws Exception {
try {
com.itextpdf.text.Rectangle pagesize = new com.itextpdf.text.Rectangle(webview.getWidth(), webview.getHeight());
Document document = new Document(pagesize, 0f, 0f, 0f, 0f);
PdfWriter.getInstance(document, new FileOutputStream(file));
document.open();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
screen.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
addImage(document, byteArray);
document.close();
sendEmailToGuest();
} catch (Exception e) {
e.printStackTrace();
}
}
want to split single page to the multiple pages
You can create your document like this:
Document pdfDoc = new Document(PageSize.A4, 0f, 0f, 0f, 0f);
if you want your page rotated to landscape you can add .Rotate() after .A4
If max height of content is reached iText will create the new page.
Have a look at this answer https://stackoverflow.com/a/11206227/5840866 on a similar question about the page number at the end of the page. You can also use PdfPageEventHelper
Also have a look at this amazing examples from the official iText site that might give you a helping hand
https://itextpdf.com/en/resources/examples/itext-7/event-handlers-and-renderers
I am trying to read one PDF and copy its data into another PDF. The first PDF contains some text and images and I wish to write an image in the second PDF exactly where the text ends(which is basically the end of the PDF file). RIght now it just prints at the top. How can I make this change?
PdfReader reader = null;
reader = new PdfReader(Var.input);
Document document=new Document();
PdfWriter writer = null;
writer = PdfWriter.getInstance(document,new FileOutputStream(Var.output));
PdfImportedPage page = writer.getImportedPage(reader, 1);
reader.close();
document.open();
PdfContentByte cb = writer.getDirectContent();
// Copy first page of existing PDF into output PDF
document.newPage();
cb.addTemplate(page, 0, 0);
// Add your new data / text here
Image image = null;
image = Image.getInstance (Var.qr);
document.add(image);
document.close();
Try this:
First get the location/co-ords of where the image needs to go, then simply add the second line from below to your code so the image is inserted at that location "X, Y"
Image image = Image.getInstance(String RESOURCE);
image.setAbsolutePosition(X, Y);
writer.getDirectContent().addImage(image);
Take a look here for some examples in iText 5: https://itextpdf.com/en/resources/examples/itext-5-legacy/chapter-3-adding-content-absolute-positions
You should use a PdfStamper instead of a PdfWriter with imported pages. Your approach throws away all interactive contents. You can use sorifiend's idea there, too.
To determine where the text on the given page ends, have a look at the iText in Action, 2nd edition example ShowTextMargins which parses a PDF and ads a rectangle showing the text margin.
I´m generating PDFs using iText and it works fine. But I need a way to import html styled informations from an existing PDF at some point.
I know i could just use the XMLWorker class to generate the text directly from html in my own document. But cause I´m not sure whether it actually supports all html features I´m looking to work around this.
Therefore a PDF is generated from html using XSLT. The content of this PDF then should be copied to my document.
There are two ways discribed in the book ("iText in Action").
One that parses the PDF and gets you the text (or other informations) from the document using PdfReaderContentParser and TextExtractionStrategy.
It looks like this:
PdfReader reader = new PdfReader(pdf);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
TextExtractionStrategy strategy;
for(int i=1;i<=reader.getNumberOfPages();i++){
strategy = parser.processContent(i, new LocationTextExtractionStrategy());
document.add(new Chunk(strategy.getResultantText()));
}
But this only prints plain text to the document. Obviously there are more ExtractionStrategys and maybe one of them does exactly what i want but i couldn´t find it yet.
The second way is to copy an itextpdf.text.Image of each side of the PDF to your document. This is obviously not a good idea, cause it will add the entire page to your document even if there is only one line of text in the existing PDF. Its done like this:
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
PdfReader reader = new PdfReader(pdf);
PdfImportedPage page;
for(int i=1;i<=reader.getNumberOfPages();i++){
page = writer.getImportedPage(reader,i);
document.add(Image.getInstance(page));
}
Like I said this copys all the empty lines at the end of the PDF aswell, but i need to continue my text immediatly after the last line of text.
If I could convert this itext.text.Image into a java.awt.BufferedImage I could use getSubImage(); and informations i can extract from the PDF to cut away all the empty lines. But i wasn´t able to find a way to to this.
This are the two ways i found. But cause none of them is suitable for my purpose as they are my question is:
Is there a way to import everything except the empty lines at the end, but including text-style informations, tables and everything else from a PDF to my document using iText?
You can trim away empty space of the XSLT generated PDF and then import the trimmed pages as in your code.
Example code
The following code borrows from the code in my answer to Using iTextPDF to trim a page's whitespace. In contrast to the code there, though, we have to manipulate the media box, not the crop box, because this is the only box respected by PdfWriter.getImportedPage.
Before importing a page from a given PdfReader, crop it using this method:
static void cropPdf(PdfReader reader) throws IOException
{
int n = reader.getNumberOfPages();
for (int i = 1; i <= n; i++)
{
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
MarginFinder finder = parser.processContent(i, new MarginFinder());
Rectangle rect = new Rectangle(finder.getLlx(), finder.getLly(), finder.getUrx(), finder.getUry());
PdfDictionary page = reader.getPageN(i);
page.put(PdfName.MEDIABOX, new PdfArray(new float[]{rect.getLeft(), rect.getBottom(), rect.getRight(), rect.getTop()}));
}
}
(excerpt from ImportPageWithoutFreeSpace.java)
The extended render listener MarginFinder is taken as is from the question linked to above. You can find a copy here: MarginFinder.java.
Example run
Using this code
PdfReader readerText = new PdfReader(docText);
cropPdf(readerText);
PdfReader readerGraphics = new PdfReader(docGraphics);
cropPdf(readerGraphics);
try ( FileOutputStream fos = new FileOutputStream(new File(RESULT_FOLDER, "importPages.pdf")))
{
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, fos);
document.open();
document.add(new Paragraph("Let's import 'textOnly.pdf'", new Font(FontFamily.HELVETICA, 12, Font.BOLD)));
document.add(Image.getInstance(writer.getImportedPage(readerText, 1)));
document.add(new Paragraph("and now 'graphicsOnly.pdf'", new Font(FontFamily.HELVETICA, 12, Font.BOLD)));
document.add(Image.getInstance(writer.getImportedPage(readerGraphics, 1)));
document.add(new Paragraph("That's all, folks!", new Font(FontFamily.HELVETICA, 12, Font.BOLD)));
document.close();
}
finally
{
readerText.close();
readerGraphics.close();
}
(excerpt from unit test method testImportPages in ImportPageWithoutFreeSpace.java)
I imported both the page from the docText document
and the page from the docGraphics document
into a new document with some text before, between, and after. The result:
As you can see, source styles are preserved but free space around is discarded.
I am producing a PDF file in a HttpServlet with itText. Adding a Text on the canvas. If I open the url the PDF is shown correctly with the text. Also if I print it direclty from the browser, the text is visible on the printed paper. If I download the PDF on the other hand, the text not shown anymore (The image still is). The PDF can be viewed here: http://www.vegantastic.de/pdfTest
My code looks like this:
Document document = new Document();
// step 2
ByteArrayOutputStream baos = new ByteArrayOutputStream();
private PdfWriter writer = PdfWriter.getInstance(document, baos);
// step 3
document.open();
Font helvetica = new Font(FontFamily.TIMES_ROMAN, 12);
BaseFont bf_helv = helvetica.getCalculatedBaseFont(false);
PdfContentByte canvas = writer.getDirectContentUnder();
canvas.setFontAndSize(bf_helv, 12);
canvas.showTextAligned(Element.ALIGN_LEFT, "Test TEXT - Why is it missing after download?", 100, 800,0);
document.close();
// setting some response headers
response.setHeader("Expires", "0");
response.setHeader("Cache-Control",
"must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
// setting the content type
response.setContentType("application/pdf");
// the contentlength
response.setContentLength(baos.size());
// write ByteArrayOutputStream to the ServletOutputStream
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
os.close();
Is there any reasonable explanation for that or this this some kind of bug? Any way to resove this?
You aren't adding the text correctly. The PDF you are creating contains a serious syntax error. Some PDF viewers will ignore this syntax error and show the text anyway (which may be why you can print the PDF from a browser); others will not show anything because you are showing text outside a text object.
There are different ways to add text at an absolute position. One way is to create a text object yourself:
canvas.beginText();
canvas.setFontAndSize(bf_helv, 12);
canvas.showTextAligned(Element.ALIGN_LEFT, "Test TEXT - Why is it missing after download?", 100, 800,0);
canvas.endText();
In this case, you need to manually begin and end the text object. That's missing in your code.
Another way, is to have iText create the text object:
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT,
new Phrase("Test TEXT - Why is it missing after download?", new Font(bf_helv, 12)),
100, 800,0);
This single line is the equivalent of the four lines above.
Important note:
You are using this canvas:
PdfContentByte canvas = writer.getDirectContentUnder();
However: if your document contains opaque elements (an image, a colored rectangle,...), then whatever text you're adding will be covered by these opaque elements. Are you sure you don't want:
PdfContentByte canvas = writer.getDirectContent();
Try this
PdfContentByte canvas = writer.getDirectContentUnder();
canvas.saveState();
canvas.beginText();
canvas.setFontAndSize(bf_helv, 12);
canvas.showTextAligned(Element.ALIGN_LEFT, "Test TEXT - Why is it missing after download?", 100, 800,0);
canvas.endText();
canvas.restoreState();
I am trying to read one PDF and copy its data into another PDF. The first PDF contains some text and images and I wish to write an image in the second PDF exactly where the text ends(which is basically the end of the PDF file). RIght now it just prints at the top. How can I make this change?
PdfReader reader = null;
reader = new PdfReader(Var.input);
Document document=new Document();
PdfWriter writer = null;
writer = PdfWriter.getInstance(document,new FileOutputStream(Var.output));
PdfImportedPage page = writer.getImportedPage(reader, 1);
reader.close();
document.open();
PdfContentByte cb = writer.getDirectContent();
// Copy first page of existing PDF into output PDF
document.newPage();
cb.addTemplate(page, 0, 0);
// Add your new data / text here
Image image = null;
image = Image.getInstance (Var.qr);
document.add(image);
document.close();
Try this:
First get the location/co-ords of where the image needs to go, then simply add the second line from below to your code so the image is inserted at that location "X, Y"
Image image = Image.getInstance(String RESOURCE);
image.setAbsolutePosition(X, Y);
writer.getDirectContent().addImage(image);
Take a look here for some examples in iText 5: https://itextpdf.com/en/resources/examples/itext-5-legacy/chapter-3-adding-content-absolute-positions
You should use a PdfStamper instead of a PdfWriter with imported pages. Your approach throws away all interactive contents. You can use sorifiend's idea there, too.
To determine where the text on the given page ends, have a look at the iText in Action, 2nd edition example ShowTextMargins which parses a PDF and ads a rectangle showing the text margin.