I am just fiddeling around with Flying Saucer to generate a PDF from a plain HTML Template I wrote.
Unfortunately, flying saucer seems to generate 1/2 empty page on my first page so the main content actually just begins on the second half of the first page.
There is really not much to show as I am working with a normal html page that lies in a String Object consisting of some table and well-formed html. Displaying the html shows exactly what I want and the part that gets rendered does also look great and as expected - but there is half an empty page...
Document document = new Document(PageSize.A4, 0, 0, 0, 0);
PdfWriter writer;
PdfImportedPage page;
byte[] pdfDaten;
writer = PdfWriter.getInstance(document, baos);
document.open();
PdfContentByte cb = writer.getDirectContent();
PdfReader pdfPage = pdfBuilder.doRenderGeneratorToPDF(html_page);
document.setPageSize(PageSize.A4);
page = writer.getImportedPage(pdfPage, 1);
document.newPage();
cb.addTemplate(page, 0, 0);
document.close();
baos.flush();
pdfDaten = baos.toByteArray();
baos.close();
return pdfDaten;
Did anybody else experience this problem and has a hint or solution?
Related
I'm using iText library for generating PDFs where I have a table that spans across pages. In order to continue my text splits across pages, i'v used setSplitLate as false. In some generated PDFs, last line of page 1 gets repeated in first line of page 2.
Is there any property that needs to be set to avoid duplication of lines across pages?
e.g. code
Document document = new Document(PageSize.A4, 0, 0,0, 45);
document.open();
PdfWriter writer;
PdfPTable table = new PdfPTable(2);
table.setWidthPercentage(100);
table.setSplitLate(false);
//added stuff in table
document.add(table);
adding footer in onEndPage():
PdfPTable footer = new PdfPTable(1);
footer.setTotalWidth(595);
PdfPCell footerCell = new PdfPCell();
footerCell.setPaddingTop(10f);
footerCell.setBorder(Rectangle.NO_BORDER);
footer.addCell(footerCell);
footer.writeSelectedRows(0, -1, 0, document.bottom(), writer.getDirectContent());
I tried to overlap a model pdf, to see the differences between that and my new pdf.
here is my code:
PdfReader reader = new PdfReader(WorkDir + "\\model.pdf");
PdfImportedPage page = writer.GetImportedPage(reader, 1);
pdfOut.NewPage();
if (checkBox1.Checked) writer.DirectContent.AddTemplate(page, 0, 0);
I only want to put the page only if I check the checkbox1.
But if checkbox1 is not checked, the outout pdf file is very large and the overlapped file is not visible.
I removed the overlap part:
PdfReader reader = new PdfReader(WorkDir + "\\model.pdf");
//PdfImportedPage page = writer.GetImportedPage(reader, 1);
pdfOut.NewPage();
//if (checkBox1.Checked) writer.DirectContent.AddTemplate(page, 0, 0);
and the file size is now ok.
What am I doing wrong?
I think that the DirectContent element adds the page, but is not visible.
That can explain why the output file is so big( with overlap part file size is 700KB, without only 4KB)
The data of the page are already added to the new document when importing the page
PdfImportedPage page = writer.GetImportedPage(reader, 1);
The later writer.DirectContent.AddTemplate(page, 0, 0); only makes it visible.
Thus, you might want
PdfReader reader = new PdfReader(WorkDir + "\\model.pdf");
pdfOut.NewPage();
if (checkBox1.Checked)
{
PdfImportedPage page = writer.GetImportedPage(reader, 1);
writer.DirectContent.AddTemplate(page, 0, 0);
}
I've found many solutions in here and in the 'iText in Action' book, to merge PDF's using the PDFCopy and PDFSmartCopy classes, but the only similar question asked I've seen, the guy worked it out himself but didn't post the answer. This post Add an existing PDF from file to an unwritten document using iTextSharp asks the same question but its at the end, so they suggest closing the existing document and then use PDFCopy, here I'd like to insert it anywhere. So here goes.
I'm creating an iTextSharp document with text and images using normal Sections, Phrases, Document and PDFWriter classes. This is code written over many years and works fine. Now we need to insert an existing PDF while creating this document as either a new Section or Chapter if that isn't possible. I have the PDF as a Byte array, so no problems getting a PDFReader. However, I cannot work out how to read that PDF and insert it into the existing document at the point I'm at. I can get access to the PDFWriter if need be, but for the rest of the document all access is via Sections. This is as far as I've got and I can add the PDFWriter as another parameter if necessary.
I've made some progress since the original post and amend the code accordingly.
internal static void InsertPDF( Section section, Byte[] pdf )
{
this.document.NewPage();
PdfReader pdfreader = new PdfReader( pdf );
Int32 pages = pdfreader.NumberOfPages;
for ( Int32 page = 1; page <= pages; page++ )
{
PdfImportedPage page = this.writer.GetImportedPage( planreader, pagenum );
PdfContentByte pcb = this.writer.DirectContentUnder;
pcb.AddTemplate( page, 0, 0 );
this.document.NewPage();
}
}
It is close to doing what I want, but as I obviously don't understand the full workings of iText wonder if this is the correct way or there is a better way to do it.
If there is any other information I can provide, let me know.
Any pointers would be appreciated.
Just adding a little more meat to the answer. The solution ended up being found by researching what methods worked with a PdfTemplate which is what a PdfImportedPage is derived from. I've added a little more to show how it interacts with the rest of the document being built up. I hope this helps someone else.
internal static void InsertPDF( PdfWriter writer, Document document, Section section, Byte[] pdf )
{
Paragraph para = new Paragraph();
// Add note to show blank page is intentional
para.Add( new Phrase( "PDF follows on the next page.", <your font> ) );
section.Add( para );
// Need to update the document so we render this page.
document.Add( section );
PdfReader reader = new PdfReader( pdf );
PdfContentByte pcb = writer.DirectContentUnder;
Int32 pages = planreader.NumberOfPages;
for ( Int32 pagenum = 1; pagenum <= pages; pagenum++ )
{
document.NewPage();
PdfImportedPage page = writer.GetImportedPage( reader, pagenum );
// Render their page in our document.
pcb.AddTemplate( page, 0, 0 );
}
}
for insert existing pdf into new page, i've change order newpage
PdfImportedPage page2 = writer.GetImportedPage(pdf, 1);
cb.AddTemplate(page2, 0, 0);
document.NewPage();
I am adding text to an already created pdf document using this method.
ITextSharp insert text to an existing pdf
Basically it uses the PdfContentByte and then adds the content template to the page.
I am finding that in some areas of the file, the text doesn't show up.
It seems that the text I am adding is showing up behind the content that is already on the page? I flattened the pdf document down to it just being images but I am still having the same issue happen with the flattened file.
Has anyone had any issues adding text being hidden using Itextsharp?
I also tried using DirectContentUnder as was suggested in this link to no avail..
iTextSharp hides text when write
Here is the code I am using...With this I am trying to basically overlay graph paper on top of the PDF. In this example, there is a box in the upper left corner of every page that doesn't get populated. There is an image in the original pdf in this spot. And on the 4th and 5th pages, there are boxes that don't get populated, but they don't seem to be images.
PdfReader reader = new PdfReader(oldFile);
iTextSharp.text.Rectangle size = reader.GetPageSizeWithRotation(1);
Document document = new Document(size);
// open the writer
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write);
PdfWriter writer = PdfWriter.GetInstance(document, fs);
document.Open();
// the pdf content
PdfContentByte cb = writer.DirectContent;
for (int i = 0; i < reader.NumberOfPages; i++)
{
document.NewPage();
// select the font properties
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
cb.SetFontAndSize(bf, 4);
cb.SetColorStroke(BaseColor.GREEN);
cb.SetLineWidth(1f);
for (int j = 10; j < 600; j += 10)
{
WriteToDoc(ref cb, j.ToString(), j, 10);//Write the line number
WriteToDoc(ref cb, j.ToString(), j, 780);//Write the line number
if (j % 20 == 0)
{
cb.MoveTo(j, 20);
cb.LineTo(j, 760);
cb.Stroke();
}
}
for (int j = 10; j < 800; j += 10)
{
WriteToDoc(ref cb, j.ToString(), 5, j);//Write the line number
WriteToDoc(ref cb, j.ToString(), 590, j);//Write the line number
if (j % 20 == 0)
{
cb.MoveTo(15, j);
cb.LineTo(575, j);
cb.Stroke();
}
}
// create the new page and add it to the pdf
PdfImportedPage page = writer.GetImportedPage(reader, i + 1);
cb.AddTemplate(page, 0, 0);
}
// close the streams and voilá the file should be changed :)
document.Close();
fs.Close();
writer.Close();
reader.Close();
Thanks for any of the help you can provide...I really appreciate it!
-Greg
First of all: If you are trying to basically overlay graph paper on top of the PDF, why do you first draw the graph paper and stamp the original page onto it? You essentially are underlaying graph paper, not overlaying it.
Depending on the content of the page, your graph paper this way may easily get covered. E.g. if there is a filled rectangle in the page content, in the result there is a box in the upper left corner of every page that doesn't get populated.
Thus, simply first add the old page content, then add overlay changes.
This being said, for the task of applying changes to an existing PDF, using PdfWriter and GetImportedPage is less than optimal. This actually is a task for the PdfStamper class which its made for stamping additional content on existing PDFs.
E.g. have a look at the sample StampText, the pivotal code being:
PdfReader reader = new PdfReader(resource);
using (var ms = new MemoryStream())
{
using (PdfStamper stamper = new PdfStamper(reader, ms))
{
PdfContentByte canvas = stamper.GetOverContent(1);
ColumnText.ShowTextAligned( canvas, Element.ALIGN_LEFT, new Phrase("Hello people!"), 36, 540, 0 );
}
return ms.ToArray();
}
I am able to insert an Image inside an existing pdf document, but the problem is,
The image is placed at the bottom of the page
The page becomes white with the newly added text showing on it.
I am using following code.
List<PDPage> pages = pdDoc.getDocumentCatalog().getAllPages();
if(pages.size() > 0){
PDJpeg img = new PDJpeg(pdDoc, in);
PDPageContentStream stream = new PDPageContentStream(pdDoc,pages.get(0));
stream.drawImage(img, 60, 60);
stream.close();
}
I want the image on the first page.
PDFBox is a low-level library to work with PDF files. You are responsible for more high-level features. So in this example, you are placing your image at (60, 60) starting from lower-left corner of your document. That is what stream.drawImage(img, 60, 60); does.
If you want to move your image somewhere else, you have to calculate and provide the wanted location (perhaps from dimensions obtained with page.findCropBox(), or manually input your location).
As for the text, PDF document elements are absolutely positioned. There are no low-level capabilities for re-flowing text, floating or something similar. If you write your text on top of your image, it will be written on top of your image.
Finally, for your page becoming white -- you are creating a new content stream and so overwriting the original one for your page. You should be appending to the already available stream.
The relevant line is:
PDPageContentStream stream = new PDPageContentStream( pdDoc, pages.get(0));
What you should do is call it like this:
PDPageContentStream stream = new PDPageContentStream( pdDoc, pages.get(0), true, true);
The first true is whether to append content, and the final true (not critical here) is whether to compress the stream.
Take a look at AddImageToPDF sample available from PDFBox sources.
Try this
doc = PDDocument.load( inputFileName );
PDXObjectImage ximage = null;
ximage = new PDJpeg(doc, new FileInputStream( image )
PDPage page = (PDPage)doc.getDocumentCatalog().getAllPages().get(0);
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true);
contentStream.drawImage( ximage, 425, 675 );
contentStream.close();
This prints the image in first page. If u want to print in all pages just put on a for loop with a condition of number of pages as the limit.
This worked for me well!
So late answer but this is for who works on it in 2020 with Kotlin: drawImage() is getting float values inside itself so try this:
val file = File(getPdfFile(FILE_NAME))
val document = PDDocument.load(file)
val page = document.getPage(0)
val contentStream: PDPageContentStream
contentStream = PDPageContentStream(document, page, true, true)
// Define a content stream for adding to the PDF
val bitmap: Bitmap? = ImageSaver(this).setFileName("sign.png").setDirectoryName("signature").load()
val mediaBox: PDRectangle = page.mediaBox
val ximage: PDImageXObject = JPEGFactory.createFromImage(document, bitmap)
contentStream.drawImage(ximage, mediaBox.width - 4 * 65, 26f)
// Make sure that the content stream is closed:
contentStream.close()
// Save the final pdf document to a file
pdfSaveLocation = "$directoryPDF/$UPDATED_FILE_NAME"
val pathSave = pdfSaveLocation
document.save(pathSave)
document.close()
I am creating a new PDF and running below code in a loop - to add one image per page and below co-ordinates and height and width values work well for me.
where out is BufferedImage reference variable
PDPage page = new PDPage();
outputdocument.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(outputdocument, page, AppendMode.APPEND, true);
PDImageXObject pdImageXObject = JPEGFactory.createFromImage(outputdocument, out);
contentStream.drawImage(pdImageXObject, 5, 2, 600, 750);
contentStream.close();
This link gives you details about Class PrintImageLocations.
This PrintImageLocations will give you the x and y coordinates of the images.
Usage: java org.apache.pdfbox.examples.util.PrintImageLocations input-pdf