Add image to iText dynamically on PDF file - itext

Can some one please help me what is missing in my code, I am trying to add image in to PDF generation
fillFieldValue(stamper.getAcroFields(),agntCertBean);
Image image1 = Image.getInstance(bb);
image1.scaleAbsolute(25f, 25f);
PdfContentByte overContent = stamper.getOverContent(1);
AcroFields form = stamper.getAcroFields();
AcroFields.FieldPosition fldPos = (AcroFields.FieldPosition)
form.getFieldPositions("ProfilePciture");
overContent.addImage(image1);
stamper.close();
reader.close();

Looking at your code without paying too much attending, I see two major mistakes:
[1.] There's something wrong with this line:
AcroFields.FieldPosition fldPos = (AcroFields.FieldPosition)form.getFieldPositions("ProfilePciture");
The getFieldPositions() method returns a List of FieldPosition elements and you're casting that list to a FieldPosition object. That won't work, you need something like this:
AcroFields.FieldPosition fldPos = form.getFieldPositions("ProfilePicture").get(0);
[2.] You get the position of the picture field, but you're not doing anything with it! You're not setting the position of the image!
Remove these two lines:
image1.scaleAbsolute(25f, 25f);
PdfContentByte overContent = stamper.getOverContent(1);
Add these lines after you've obtained the field position:
Rectangle rect = fldPos.position;
image1.scaleToFit(rect.getWidth(), rect.getHeight());
image1.setAbsolutePosition(rect.getLeft(), rect.getBottom());
PdfContentByte overContent = stamper.getOverContent(fldPos.page);
In these lines you scale the image so that it fits the field and you set the coordinates of the image. You also get the PdfContentByte instance for the correct page instead of from the first page.
You may have other errors, but please fix these first!

Related

Placing Text on Multiple Imported PDF Pages with iTextSharp [duplicate]

I am trying to add a header to existing pdf documents in Java with iText. I can add the header at a fixed place on the document, but all the documents are different page sizes, so it is not always at the top of the page. I have tried getting the page size so that I could calculate the position of the header, but it seems as if the page size is not actually what I want. On some documents, calling reader.getPageSize(i).getTop(20) will place the text in the right place at the top of the page, however, on some different documents it will place it half way down the page. Most of the pages have been scanned be a Xerox copier, if that makes a difference. Here is the code I am using:
PdfReader reader = new PdfReader(readFilePath);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(writeFilePath));
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
PdfContentByte cb = stamper.getOverContent(i);
cb.beginText();
cb.setFontAndSize(bf, 14);
float x = reader.getPageSize(i).getWidth() / 2;
float y = reader.getPageSize(i).getTop(20);
cb.showTextAligned(PdfContentByte.ALIGN_CENTER, "Copy", x, y, 0);
cb.endText();
}
stamper.close();
PDF that works correctly
PDF that works incorrectly
Take a look at the StampHeader1 example. I adapted your code, introducing ColumnText.showTextAligned() and using a Phrase for the sake of simplicity (maybe you can change that part of your code too):
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
Phrase header = new Phrase("Copy", new Font(FontFamily.HELVETICA, 14));
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
float x = reader.getPageSize(i).getWidth() / 2;
float y = reader.getPageSize(i).getTop(20);
ColumnText.showTextAligned(
stamper.getOverContent(i), Element.ALIGN_CENTER,
header, x, y, 0);
}
stamper.close();
reader.close();
}
As you have found out, this code assumes that no rotation was defined.
Now take a look at the StampHeader2 example. I'm using your "Wrong" file and I've added one extra line:
stamper.setRotateContents(false);
By telling the stamper not to rotate the content I'm adding, I'm adding the content using the coordinates as if the page isn't rotated. Please take a look at the result: stamped_header2.pdf. We added "Copy" at the top of the page, but as the page is rotated, we see the word appear on the side. The word is rotated because the page is rotated.
Maybe that's what you want, maybe it isn't. If it isn't, please take a look at StampHeader3 in which I calculate x and y differently, based on the rotation of the page:
if (reader.getPageRotation(i) % 180 == 0) {
x = reader.getPageSize(i).getWidth() / 2;
y = reader.getPageSize(i).getTop(20);
}
else {
x = reader.getPageSize(i).getHeight() / 2;
y = reader.getPageSize(i).getRight(20);
}
Now the word "Copy" appears on what is perceived as the "top of the page" (but in reality, it could be the side of the page): stamped_header3.pdf

iText Detect Text Overflow or Copy Fit

I need to put some dynamic text onto a pdf. I need to verify that the text does not overflow the boundary box I am allowed to use to place the text in.
Is there a way to detect if this is happening?
Are there any copy-fit rules that I can use to handle it when it does happen?
Thanks
iText5 is in maintenance mode and I recommend that you start your project using iText7. iText7 currently does not provide out of the box mechanisms for copy-fitting, but it can be done manually with little effort because layout engine is very flexible in iText7. Technically it can be done in iText5 as well, but I will provide an answer for iText7 for Java, and converting to C# shouldn't be a problem for you.
The basic idea is to make use of the Renderers concept and try yo layout your paragraph in the given area with different font sizes until you find the size which is OK for you. A binary search approach fits perfectly here.
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName));
Document doc = new Document(pdfDoc);
String text = "...";
Rectangle area = new Rectangle(100, 100, 200, 200);
// Just draw a black box around to verify the result visually
new PdfCanvas(pdfDoc.addNewPage()).rectangle(area).setStrokeColor(Color.BLACK).stroke();
Paragraph p = new Paragraph(text);
IRenderer renderer = p.createRendererSubTree().setParent(doc.getRenderer());
LayoutArea layoutArea = new LayoutArea(1, area);
// lFontSize means the font size which will be definitely small enough to fit all the text into the box.
// rFontSize is the maximum bound for the font size you want to use. The only constraint is that it should be greater than lFontSize
// Set rFontSize to smaller value if you don't want the font size to scale upwards
float lFontSize = 0.0001f, rFontSize = 10000;
// Binary search. Can be replaced with while (Math.abs(lFontSize - rFontSize) < eps). It is a matter of implementation/taste
for (int i = 0; i < 100; i++) {
float mFontSize = (lFontSize + rFontSize) / 2;
p.setFontSize(mFontSize);
LayoutResult result = renderer.layout(new LayoutContext(layoutArea));
if (result.getStatus() == LayoutResult.FULL) {
lFontSize = mFontSize;
} else {
rFontSize = mFontSize;
}
}
// lFontSize is guaranteed to be small enough to fit all the text. Using it.
float finalFontSize = lFontSize;
System.out.println("Final font size: " + finalFontSize);
p.setFontSize(finalFontSize);
// We need to layout the final time with the final font size set.
renderer.layout(new LayoutContext(layoutArea));
renderer.draw(new DrawContext(pdfDoc, new PdfCanvas(pdfDoc.getPage(1))));
doc.close();
The output:
Final font size: 5.7393746
Visual result:

How can I obtain the bleed box size of a PDF page?

I'm trying to get all possible page boundaries from a PDF, but when I ask for the "bleed", I get a Null value:
private void button2_Click(object sender, EventArgs e)
{
string source = #"C:\\Users\\numx\\Desktop\\TestPDF.pdf";
PdfReader reader = new PdfReader(source);
iTextSharp.text.Rectangle cropBox = reader.GetCropBox(1);
iTextSharp.text.Rectangle mediaBox = reader.GetBoxSize(1, "media");
iTextSharp.text.Rectangle trimBox = reader.GetBoxSize(1, "trim");
iTextSharp.text.Rectangle artBox = reader.GetBoxSize(1, "art");
iTextSharp.text.Rectangle bleedBox = reader.GetBoxSize(1, "bleed");
MessageBox.Show(bleedBox.ToString());
reader.Close();
}
To recap what we discussed in the comments.
When you do this:
iTextSharp.text.Rectangle bleedBox = reader.GetBoxSize(1, "bleed");
Then bleedBox is an instance of the Rectangle class when the PDF defines a bleed box; when no bleed box is defined, bleedBox is Null. In the latter case, you will get an exception when you invoke the ToString() method on it.
So, if you need the bleedBox, first check if bleedBox is Null. If it's not, work with the bleedBox object. If it isn't, use the crop box instead. If there's no crop box, use the media box.
Of all the page boundaries, only the media box is mandatory. All the other types of page boundaries are optional.

Using iText7, how do I fill an otherwise empty column with a rectangle?

Using iText7 I wish to fill an otherwise empty column with a bordered rectangle headed by some text. The border methods seem to have disappeared from Rectangle in iText7 and the only examples I can find use them. If Rectangle is the correct approach how do I do this? If not, what is the correct approach?
Please take a look at Chapter 2 of the tutorial "iText 7: Building Blocks"
In this tutorial, we create a Rectangle object and we draw it to a PdfCanvas object:
Rectangle rectangle = new Rectangle(36, 650, 100, 100);
pdfCanvas.rectangle(rectangle);
pdfCanvas.stroke();
How to get a PdfCanvas object?
Either you create it from a PdfPage object you've created yourself:
OutputStream fos = new FileOutputStream(dest);
PdfWriter writer = new PdfWriter(fos);
PdfDocument pdf = new PdfDocument(writer);
PdfPage page = pdf.addNewPage();
PdfCanvas pdfCanvas = new PdfCanvas(page);
Or you get an existing page from the PdfDocument object:
PdfCanvas canvas = new PdfCanvas(pdf, pdf.getNumberOfPages());
You can tweak the line width, dash pattern, line color,... using different methods in the PdfCanvas object.
There are other ways to draw a rectangle, but in one of your previous questions, you mentioned a ColumnDocumentRenderer. If your current question is part of the same context, you already have Rectangle objects and if you have a ColumnDocumentRenderer, you have access to a PdfCanvas object. You could easily automate your app to make it draw a rectangle around every column that is rendered.
Of course: since you never accepted my previous answer, my assumption could be wrong.
For better or worse this seemed to achieve my objective:
AreaBreak nextArea = new AreaBreak(AreaBreakType.NEXT_AREA);
document.add(nextArea);
float h = document.getRenderer().getCurrentArea().getBBox().getHeight();
float w = document.getRenderer().getCurrentArea().getBBox().getWidth();
Paragraph endB = new Paragraph(" ");
endB.setHeight(h);
endB.setWidth(w);
SolidBorder b = new SolidBorder(2);
endB.setBorder(b);
document.add(endB);

iTextSharp z-index

I'm using itextSharp to add anotations in a pdf document.
I have a pdf document that already contains an image saved in it, it's a stamp.
So I draw some stroke on this pdf in the stamp and everything is fine when I draw them in my WPF but when I send the pdf by email using iTextSharp for the conversion the line I drawed is now below the stamp.
How I can solve this problem ?
Thank you
The explanation you posted as an answer (BTW, more apropos would have been to edit your question to contain that data) explains the issue.
There are two principal types of objects visible on a PDF page:
the PDF page content;
annotations associated with the page.
The annotations are always displayed above the page content if they are displayed at all.
In your case you add the image to the PDF page content (using OverContent or UnderContent only changes where in relation to other PDF page content material your additions appear). The stamp, on the other hand, most likely is realized by means of an annotation. Thus, the stamp annotation always is above your additions.
If you want to have your additions appear above the stamp, you either have to add your additions as some kind of annotation, too, or you have to flatten the stamp annotation into the page content before adding your stuff.
Which of these varients is better, depends on the requirements you have. Are there any requirements forcing the stamp to remain a stamp annotation? Are there any requirements forcing your additions to remain part of the content? Please elaborate your requirements. As content and annotations have some different properties when displayed or printed, please state all requirements.
And furthermore, please supply sample documents.
So like I said the original pdf have a stamp saved inside it, if I open the pdf with acrobat reader I can move the stamp.
So here my code to write some strokes :
using (var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var intputStream = new FileStream(pathPdf, FileMode.Open, FileAccess.Read, FileShare.Read))
{
PdfReader reader = new PdfReader(intputStream);
using (var pdfStamper = new PdfStamper(reader, outputStream))
{
foreach (var page in pages)
{
if (page != null && page.ExportedImages.HasItems())
{
PdfContentByte pdfContent = pdfStamper.GetOverContent(page.PageIndex);
Rectangle pageSize = reader.GetPageSizeWithRotation(page.PageIndex);
PdfLayer pdfLayer = new PdfLayer(string.Format(ANNOTATIONNAMEWITHPAGENAME, page.PageIndex), pdfContent.PdfWriter);
foreach (ExporterEditPageInfoImage exportedInfo in page.ExportedImages)
{
Image image = PngImage.GetImage(exportedInfo.Path);
image.Layer = pdfLayer;
if (quality == PublishQuality.Normal || quality == PublishQuality.Medium || quality == PublishQuality.High)
{
float width = (float)Math.Ceiling((image.Width / image.DpiX) * 72);
float height = (float)Math.Ceiling((image.Height / image.DpiY) * 72);
image.ScaleAbsolute(width, height);
float x = (float)(exportedInfo.HorizontalTile * (page.TileSize * (72 / 96d)));
float y = (float)Math.Max(0, (pageSize.Height - ((exportedInfo.VerticalTile + 1) * (page.TileSize * (72 / 96d)))));
image.SetAbsolutePosition(x, y);
}
else
throw new NotSupportedException();
pdfContent.AddImage(image);
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
pdfStamper.Close();
}
}
So my strokes are saved good in the pdf the problem the stamp is always on top of everything and I think is normal so can I do a workaround for this ?