Not seeing blank signature field added to PDF - itext

I am replacing TextFields to Signature fields and not able to see these blank signature fields in the generated PDF.
These blank fields will be needed to digitally signed by client at later stages.
/// <summary>
/// Adds a text field to the report that the user can update signatures to the specified location.
/// </summary>
/// <param name="writer">pdfwriter of document.</param>
/// <param name="xPosition">The lower left x position of the text field.</param>
/// <param name="yPosition">The lower left y position of the text field.</param>
/// <param name="width">The width of the text field.</param>
/// <param name="height">The height of the text field.</param>
/// <param name="fieldId"></param>
protected virtual void AddTextField(iTextSharp.text.pdf.PdfWriter writer, String fieldId, float xPosition, float yPosition, float width, float height)
{
Rectangle position = new Rectangle(xPosition, yPosition, xPosition + width, Math.Max(yPosition - height, 0));
iTextSharp.text.pdf.TextField field = new iTextSharp.text.pdf.TextField(writer, position, fieldId);
// Requirement is to change existing textFields to blank Signature fields
// In the method, memoryStream, reader and stamper are not available.
// Below is the textField I need to transform into Signature field.
// field.Text = String.Empty;
// field.Font = FontFactory.GetFont("Arial Narrow").BaseFont;
// field.TextColor = Color.WHITE;
// field.FontSize = 9;
// Not seeing the signature field appear on the pdf.
// Don't know exactly the reason
PdfFormField sig = PdfFormField.CreateSignature(writer);
sig.SetWidget(position, null);
sig.Flags = PdfAnnotation.FLAGS_PRINT;
sig.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g"));
sig.FieldName = fieldId;
sig.SetPage();
writer.AddAnnotation(sig);
//Also tried below code
//PdfFormField pfield = PdfFormField.CreateSignature(writer);
//pfield.FieldName = fieldId;
//pfield.SetFieldFlags(PdfAnnotation.FLAGS_PRINT);
//pfield.SetWidget(position, null);
//pfield.SetPage();
//pfield.MKBorderColor = Color.BLACK;
//pfield.MKBackgroundColor = Color.BLUE;
//PdfAppearance tp = PdfAppearance.CreateAppearance(writer, width, height);
//tp.Rectangle(position);
//tp.Stroke();
//pfield.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp);
//writer.AddAnnotation(pfield);
}
Second quest:
*Do I really need a signature field if - client will add signature text to these field at later stages (using 3rd party tool like DocuSign)? or simple PDFTextFields would really work?
Adding above question with the query as this may be helpful in relating my scenario.
Thanks in advance for the help.

I just tested your code using
public void AddSignatureFieldLikePrashantJha()
{
Document document = new Document();
Stream stream = new FileStream(#"emptySignatureFieldLikePrashantJha.pdf", FileMode.Create);
PdfWriter pdfWriter = PdfWriter.GetInstance(document, stream);
document.Open();
AddTextField(pdfWriter, "Signature", 100, 100, 400, 50);
document.Close();
}
In the result Adobe Reader DC clearly indicated the signature field position by an arrow:
Putting the focus to that field (e.g. by pressing TAB) the field even is given a frame:
Earlier Adobe Reader versions show it even clearer, e.g. 9.5:
Thus, I cannot reproduce that you are
not able to see these blank signature fields in the generated PDF
If you want to have the field area appear somehow more pronounced, you can indeed use a PdfAppearance, e.g.
protected virtual void AddFancySignatureField(iTextSharp.text.pdf.PdfWriter writer, String fieldId, float xPosition, float yPosition, float width, float height)
{
Rectangle position = new Rectangle(xPosition, yPosition, xPosition + width, Math.Max(yPosition - height, 0));
iTextSharp.text.pdf.TextField field = new iTextSharp.text.pdf.TextField(writer, position, fieldId);
PdfFormField sig = PdfFormField.CreateSignature(writer);
sig.SetWidget(position, null);
sig.Flags = PdfAnnotation.FLAGS_PRINT;
sig.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g"));
sig.FieldName = fieldId;
sig.SetPage();
PdfAppearance tp = PdfAppearance.CreateAppearance(writer, width, height);
PdfShading radial = PdfShading.SimpleRadial(writer, 0, height / 2, 0, 0, height / 2, width, BaseColor.RED, BaseColor.GREEN);
tp.PaintShading(radial);
sig.SetAppearance(PdfAnnotation.APPEARANCE_NORMAL, tp);
writer.AddAnnotation(sig);
}
The result looks like this:
Second quest: *Do I really need a signature field if - client will add signature text to these field at later stages (using 3rd party tool like DocuSign)? or simple PDFTextFields would really work?
That depends very much on the exact 3rd party tool used. Some such tools require signature fields, some require a text marker in the content, some want the position given by coordinate...

Related

iTextSharp IExtRenderListener and boundingbox [duplicate]

I have a pdf which comprises of some data, followed by some whitespace. I don't know how large the data is, but I'd like to trim off the whitespace following the data
PdfReader reader = new PdfReader(PDFLOCATION);
Rectangle rect = new Rectangle(700, 2000);
Document document = new Document(rect);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(SAVELCATION));
document.open();
int n = reader.getNumberOfPages();
PdfImportedPage page;
for (int i = 1; i <= n; i++) {
document.newPage();
page = writer.getImportedPage(reader, i);
Image instance = Image.getInstance(page);
document.add(instance);
}
document.close();
Is there a way to clip/trim the whitespace for each page in the new document?
This PDF contains vector graphics.
I'm usung iTextPDF, but can switch to any Java library (mavenized, Apache license preferred)
As no actual solution has been posted, here some pointers from the accompanying itext-questions mailing list thread:
As you want to merely trim pages, this is not a case of PdfWriter + getImportedPage usage but instead of PdfStamper usage. Your main code using a PdfStamper might look like this:
PdfReader reader = new PdfReader(resourceStream);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("target/test-outputs/test-trimmed-stamper.pdf"));
// Go through all pages
int n = reader.getNumberOfPages();
for (int i = 1; i <= n; i++)
{
Rectangle pageSize = reader.getPageSize(i);
Rectangle rect = getOutputPageSize(pageSize, reader, i);
PdfDictionary page = reader.getPageN(i);
page.put(PdfName.CROPBOX, new PdfArray(new float[]{rect.getLeft(), rect.getBottom(), rect.getRight(), rect.getTop()}));
stamper.markUsed(page);
}
stamper.close();
As you see I also added another argument to your getOutputPageSize method to-be. It is the page number. The amount of white space to trim might differ on different pages after all.
If the source document did not contain vector graphics, you could simply use the iText parser package classes. There even already is a TextMarginFinder based on them. In this case the getOutputPageSize method (with the additional page parameter) could look like this:
private Rectangle getOutputPageSize(Rectangle pageSize, PdfReader reader, int page) throws IOException
{
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
TextMarginFinder finder = parser.processContent(page, new TextMarginFinder());
Rectangle result = new Rectangle(finder.getLlx(), finder.getLly(), finder.getUrx(), finder.getUry());
System.out.printf("Text/bitmap boundary: %f,%f to %f, %f\n", finder.getLlx(), finder.getLly(), finder.getUrx(), finder.getUry());
return result;
}
Using this method with your file test.pdf results in:
As you see the code trims according to text (and bitmap image) content on the page.
To find the bounding box respecting vector graphics, too, you essentially have to do the same but you have to extend the parser framework used here to inform its listeners (the TextMarginFinder essentially is a listener to drawing events sent from the parser framework) about vector graphics operations, too. This is non-trivial, especially if you don't know PDF syntax by heart yet.
If your PDFs to trim are not too generic but can be forced to include some text or bitmap graphics in relevant positions, though, you could use the sample code above (probably with minor changes) anyways.
E.g. if your PDFs always start with text on top and end with text at the bottom, you could change getOutputPageSize to create the result rectangle like this:
Rectangle result = new Rectangle(pageSize.getLeft(), finder.getLly(), pageSize.getRight(), finder.getUry());
This only trims top and bottom empty space:
Depending on your input data pool and requirements this might suffice.
Or you can use some other heuristics depending on your knowledge on the input data. If you know something about the positioning of text (e.g. the heading to always be centered and some other text to always start at the left), you can easily extend the TextMarginFinder to take advantage of this knowledge.
Recent (April 2015, iText 5.5.6-SNAPSHOT) improvements
The current development version, 5.5.6-SNAPSHOT, extends the parser package to also include vector graphics parsing. This allows for an extension of iText's original TextMarginFinder class implementing the new ExtRenderListener methods like this:
#Override
public void modifyPath(PathConstructionRenderInfo renderInfo)
{
List<Vector> points = new ArrayList<Vector>();
if (renderInfo.getOperation() == PathConstructionRenderInfo.RECT)
{
float x = renderInfo.getSegmentData().get(0);
float y = renderInfo.getSegmentData().get(1);
float w = renderInfo.getSegmentData().get(2);
float h = renderInfo.getSegmentData().get(3);
points.add(new Vector(x, y, 1));
points.add(new Vector(x+w, y, 1));
points.add(new Vector(x, y+h, 1));
points.add(new Vector(x+w, y+h, 1));
}
else if (renderInfo.getSegmentData() != null)
{
for (int i = 0; i < renderInfo.getSegmentData().size()-1; i+=2)
{
points.add(new Vector(renderInfo.getSegmentData().get(i), renderInfo.getSegmentData().get(i+1), 1));
}
}
for (Vector point: points)
{
point = point.cross(renderInfo.getCtm());
Rectangle2D.Float pointRectangle = new Rectangle2D.Float(point.get(Vector.I1), point.get(Vector.I2), 0, 0);
if (currentPathRectangle == null)
currentPathRectangle = pointRectangle;
else
currentPathRectangle.add(pointRectangle);
}
}
#Override
public Path renderPath(PathPaintingRenderInfo renderInfo)
{
if (renderInfo.getOperation() != PathPaintingRenderInfo.NO_OP)
{
if (textRectangle == null)
textRectangle = currentPathRectangle;
else
textRectangle.add(currentPathRectangle);
}
currentPathRectangle = null;
return null;
}
#Override
public void clipPath(int rule)
{
}
(Full source: MarginFinder.java)
Using this class to trim the white space results in
which is pretty much what one would hope for.
Beware: The implementation above is far from optimal. It is not even correct as it includes all curve control points which is too much. Furthermore it ignores stuff like line width or wedge types. It actually merely is a proof-of-concept.
All test code is in TestTrimPdfPage.java.

How to decide the right coordinates in the middle of a PDF page?

I am new to iText and I looked at its many examples. The thing I have hard time to figure it out is the rectangle. On the page
http://developers.itextpdf.com/examples/form-examples-itext5/multiline-fields
there are many examples with hard-coded values for Rectangle objects. For example:
Rectangle rect = new Rectangle(36, 770, 144, 806);
My problem is that I create one Paragraph and I would like to add a fillable text input box (multi-lines) beneath it. How do I know the exact values for creating a Rectangle object that can be nicely put just after the paragraph. The size of the text of a Paragraph can change. So I cannot assume any hard-coded value.
In iText 5, iText keeps track of the coordinates of the content when using document.add(). You could take control yourself by adding content at absolute positions (e.g. by using ColumnText), but that's hard, because then you have to keep track of many things yourself (for instance: you have to introduce page breaks yourself when the content reaches the bottom of the page).
If you leave the control of the coordinates to iText, you can get access to these coordinates by using page events.
Take a look at the example below, where we keep track of the start and the end of a Paragraph in the onParagraph() and onParagraphEnd() method. This code sample is not easy to understand, but it's the only way to get the coordinates of a Paragraph in iText 5 for instance if we want to draw a rectangle around a block of text. As you can read at the bottom of that page, iText 7 makes it much easier to meet this requirement.
If you stick to iText 5, it's much easier to use generic tags to define locations. See the GenericFields example, where we use empty Chunks that result in fields. If you want to see a screen shot of the result, see Add PdfPCell to Paragraph
In your case, I'd create a Paragraph containing a Chunk that spans different lines, and I'd add the field in the onGenericTag() method of a page event.
Suppose that we have the following text file: jekyll_hyde.txt
How do we convert it to a PDF that looks like this:
Note the blue border that is added to the titles, and the page number at the bottom of each page. In iText 5, these elements are added using page events:
class MyPageEvents extends PdfPageEventHelper {
protected float startpos = -1;
protected boolean title = true;
public void setTitle(boolean title) {
this.title = title;
}
#Override
public void onEndPage(PdfWriter writer, Document document) {
Rectangle pagesize = document.getPageSize();
ColumnText.showTextAligned(
writer.getDirectContent(),
Element.ALIGN_CENTER,
new Phrase(String.valueOf(writer.getPageNumber())),
(pagesize.getLeft() + pagesize.getRight()) / 2,
pagesize.getBottom() + 15,
0);
if (startpos != -1)
onParagraphEnd(writer, document,
pagesize.getBottom(document.bottomMargin()));
startpos = pagesize.getTop(document.topMargin());
}
#Override
public void onParagraph(PdfWriter writer, Document document,
float paragraphPosition) {
startpos = paragraphPosition;
}
#Override
public void onParagraphEnd(PdfWriter writer, Document document,
float paragraphPosition) {
if (!title) return;
PdfContentByte canvas = writer.getDirectContentUnder();
Rectangle pagesize = document.getPageSize();
canvas.saveState();
canvas.setColorStroke(BaseColor.BLUE);
canvas.rectangle(
pagesize.getLeft(document.leftMargin()),
paragraphPosition - 3,
pagesize.getWidth() - document.leftMargin() - document.rightMargin(),
startpos - paragraphPosition);
canvas.stroke();
canvas.restoreState();
}
}
We can use the following code to convert a text file to a PDF and introduce the page event to the PdfWriter:
public void createPdf(String dest)
throws DocumentException, IOException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
MyPageEvents events = new MyPageEvents();
writer.setPageEvent(events);
document.open();
BufferedReader br = new BufferedReader(new FileReader(TEXT));
String line;
Paragraph p;
Font normal = new Font(FontFamily.TIMES_ROMAN, 12);
Font bold = new Font(FontFamily.TIMES_ROMAN, 12, Font.BOLD);
boolean title = true;
while ((line = br.readLine()) != null) {
p = new Paragraph(line, title ? bold : normal);
p.setAlignment(Element.ALIGN_JUSTIFIED);
events.setTitle(title);
document.add(p);
title = line.isEmpty();
}
document.close();
}
Source: developers.itextpdf.com

Total page number with itextpdf

I am using itextpdf-5.5.6 for publish my data.
I'm trying to set page numbers in PdfPCell of my pdf using following format : page_num/total_page_num
For this I use PdfTemplate object filling inside total page number before close document.
It warks, but PdfTemplate exceeds PdfPCell border.
Is it possible that all content of cell stay inside of cell properly ?
PdfTemplate pageNumTemplate;
#Test
public void quick_test() throws FileNotFoundException, DocumentException {
String filename = "C:\\test.pdf";
File file = new File(filename);
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
PageNumberEvent pageNumberEvent = new PageNumberEvent();
writer.setPageEvent(pageNumberEvent);
document.open();
for(int i = 0; i < 10000; i++){
document.add(new Paragraph("This is my paragraph"));
document.newPage();
}
document.close();
}
public class PageNumberEvent extends PdfPageEventHelper {
#Override
public void onEndPage(PdfWriter writer, Document document) {
if(pageNumTemplate == null){
pageNumTemplate = writer.getDirectContent().createTemplate(0.1f, 0.1f);
}
PdfPTable table = new PdfPTable(1);
table.setSpacingBefore(50);
Paragraph para = new Paragraph();
Chunk pageNum = new Chunk(writer.getPageNumber() + "/");
para.add(pageNum);
Image totalPageNumImg = null;
try {
totalPageNumImg = Image.getInstance(pageNumTemplate);
} catch (BadElementException e) {
e.printStackTrace();
}
Chunk totalPageNumImgChunk = new Chunk(totalPageNumImg, 0, -1, true);
para.add(totalPageNumImgChunk);
para.setIndentationLeft(370);
PdfPCell cell = new PdfPCell(para);
cell.addElement(para);
table.addCell(cell);
try {
document.add(table);
} catch (DocumentException e) {
e.printStackTrace();
}
}
#Override
public void onCloseDocument(PdfWriter writer,Document document) {
String totalPageNumString = String.valueOf(writer.getPageNumber() - 1);
float widthPoint = totalPageNumString.length() * 10;
float heightPoint = totalPageNumString.length() * 20;
Phrase totalPageNumPhrase = new Phrase(totalPageNumString);
Rectangle templRect = pageNumTemplate.getBoundingBox();
Rectangle rectangle = new Rectangle(templRect.getLeft(), templRect.getBottom(), widthPoint, heightPoint + 2);
pageNumTemplate.setBoundingBox(rectangle);
ColumnText.showTextAligned(pageNumTemplate, Element.ALIGN_LEFT, totalPageNumPhrase, 0, 1, 0);
}
}
Early, in the first onEndPage call, you create a minute template (0.1x0.1) to start with
pageNumTemplate = writer.getDirectContent().createTemplate(0.1f, 0.1f);
which fits into your cell. At the end though, in onCloseDocument, after everything has been layout'ed to a fixed position, you resize this template which makes it grow to the left:
Rectangle templRect = pageNumTemplate.getBoundingBox();
Rectangle rectangle = new Rectangle(templRect.getLeft(), templRect.getBottom(), widthPoint, heightPoint + 2);
pageNumTemplate.setBoundingBox(rectangle);
If you want your template to remain in your table cell, you have to initialize it with a width which most likely will be enough to hold the number of pages, e.g.
pageNumTemplate = writer.getDirectContent().createTemplate(30f, 0.1f);
Here you may have to play around a bit...
As the OP indicated in a comment, not only keeping all content of cell stay inside of cell is required but the content also is expected to be right aligned in the cell.
This second requirement obviously cannot be fulfilled by the OP's code which draws the number of pages into the template using ALIGN_LEFT. Furthermore it does not mix and match with resizing the template on the right size because it has already been positioned on the pages.
To fulfill it, therefore, the OP should
horizontally initialize the template with a size large enough for any expected number of pages (onEndPage);
fill the table cell with right alignment (instead of some pseudo right alignment by means of setIndentationLeft) (onEndPage);
leave the horizontal size of the template as is (onCloseDocument); and
show the number of pages right aligned to the right template border (onCloseDocument).

Itext rectangle from milimeters

I try draw a A5 rentangle in a PDF with Itext using Rectangle class and Utilities.milimetersToPoints method but when i print the PDF and measure the rectangle the measurments is not the A5 dimensions.
public static boolean createPDF(String pathPDF) {
Document document = new Document(PageSize.A4);
try {
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pathPDF));
writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE);
document.open();
createRectangle(writer, 30.75f, 11, 148.5f, 210, Color.RED);
document.close();
} catch (Exception e) {
logger.error("Error , e);
return false;
}
return true;
}
private static void createRectangle(PdfWriter writer, float x, float y, float width, float height, Color color) {
float posX = Utilities.millimetersToPoints(x);
float posY = Utilities.millimetersToPoints(y);
float widthX = Utilities.millimetersToPoints(width+x);
float heightY = Utilities.millimetersToPoints(height+y);
Rectangle rect = new Rectangle(posX, posY, widthX, heightY);
PdfContentByte canvas = writer.getDirectContent();
rectangle.setBorder(Rectangle.BOX);
rectangle.setBorderWidth(1);
rectangle.setBorderColor(color);
canvas.rectangle(rectangle);
}
what i'm doing wrong?
I use Itext 2.1.7
Many Thanks
I just ran your SSCCE (Short, Self Contained, Correct (Compilable), Example), and printed the resulting PDF from Adobe Reader. I measured the red rectangle both on-screen using the Adobe Reader measuring tool and on-paper.
The result on screen:
matches your parameters
createRectangle(writer, 30.75f, 11, 148.5f, 210, Color.RED);
------------------------------------^^^^^^--^^^
exactly, and the measurement on-paper matches as exactly as measurement with rulers can be.
Possible causes of the problem on your side:
I use a current iText version. But while there have been quite a lot of improvements and fixes since 2.1.7, I doubt any fixes had been applied here.
Different printers; some printers are known to scale while printing.
Different viewer from which you print; some viewers may always scale.
Different scaling settings in printer dialog.

iTextSharp - Some pages not stamped as expected

I'm using iTextSharp 5.0.6 to read an existing PDF, iterate each page stamping text on each, and then writing out the newly stamped PDF. The issue I'm faced with is that this isn't working 100% of the time. For some PDFs every page is stamped as expected, for others most pages are stamped while some are not. Seems as if there's potentially an issue where the stamper's GetOverContent() is not returning the top-most layer, but that's just an assumption. Has anyone had a similar issue?
using iTextSharp.text;
using iTextSharp.text.pdf;
const string WATERMARK_TEXT = "John Doe";
static void Main(string[] args)
{
string masterPdf = "master.pdf";
string pdfToCreate = "watermark.pdf";
byte[] bytes = StampPDF(masterPdf);
using (FileStream stream = new FileStream(pdfToCreate, FileMode.Create))
{
stream.Write(bytes, 0, bytes.Length);
}
}
static byte[] StampPDF(string PdfPath)
{
using (MemoryStream memoryStream = new MemoryStream())
{
PdfReader reader = new PdfReader(PdfPath);
int pageCount = reader.NumberOfPages;
PdfStamper stamper = new PdfStamper(reader, memoryStream);
float fontSize = 9;
float textAngle = 0f;
BaseFont font = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.WINANSI, BaseFont.EMBEDDED);
BaseColor backgroundColor = new BaseColor(0, 0, 0);
BaseColor fontColor = new BaseColor(255, 255, 255);
float padding = 2f;
float fontWidth = font.GetWidthPoint(WATERMARK_TEXT, fontSize);
iTextSharp.text.Rectangle pageSize;
PdfContentByte pageContents;
for (int i = 1; i <= pageCount; i++)
{
pageSize = reader.GetPageSize(i);
pageContents = stamper.GetOverContent(i);
//draw a rectangle
pageContents.SetColorFill(backgroundColor);
pageContents.MoveTo(pageSize.Width - (fontWidth + padding), 0f);
pageContents.LineTo(pageSize.Width, 0f);
pageContents.LineTo(pageSize.Width, 14f);
pageContents.LineTo(pageSize.Width - (fontWidth + padding), 14f);
pageContents.Fill();
//drop our watermark on top of the rectangle we just created
pageContents.BeginText();
pageContents.SetColorFill(fontColor);
pageContents.SetFontAndSize(font, fontSize);
pageContents.ShowTextAligned(PdfContentByte.ALIGN_LEFT, WATERMARK_TEXT, pageSize.Width - fontWidth, 4, textAngle);
pageContents.EndText();
}
stamper.Close();
reader.Close();
return memoryStream.ToArray();
}
}
For those that may encounter the same problem the key is inspecting the CropBox. Since the dimensions of a PDF's CropBox may be less than that of its PageSize you need to conditionally use one or the other. So, based on the code sample above the for loop would be altered as so:
for (int i = 1; i <= pageCount; i++)
{
mediaBox = reader.GetPageSize(i);
cropBox = reader.GetCropBox(i);
overContent = stamper.GetOverContent(i);
if (cropBox != null && (cropBox.Width < mediaBox.Width || cropBox.Height < cropBox.Height))
mediaBox = cropBox;
//draw a rectangle
overContent.SetColorFill(backgroundColor);
overContent.MoveTo(mediaBox.Right - (fontWidth + fontPadding), mediaBox.Bottom);
overContent.LineTo(mediaBox.Right, mediaBox.Bottom);
overContent.LineTo(mediaBox.Right, mediaBox.Bottom + rectangleHeight);
overContent.LineTo(mediaBox.Right - (fontWidth + fontPadding), mediaBox.Bottom + rectangleHeight);
overContent.ClosePathFillStroke();
//drop our watermark on top of the rectangle we just created
overContent.BeginText();
overContent.SetColorFill(fontColor);
overContent.SetFontAndSize(font, fontSize);
overContent.ShowTextAligned(PdfContentByte.ALIGN_LEFT, WATERMARK_TEXT, mediaBox.Right - fontWidth, mediaBox.Bottom + (rectangleHeight - fontSize), textAngle);
overContent.EndText();
}
You've made two mistakes:
You're assuming that the pages aren't rotated, but they can be: 90, 180, 270. Note that I've never seen a 180 page, but its legal. When drawing to a rotated page, you have to take that rotation into account when drawing on it. Fun with transformation matrices.
You're assuming that the page's (unrotated) lower left corner is 0,0. You're basing your measurements on the page's width and height (close), but aren't adjusting for any offset in that bottom left corner.
There are three ways to do a landscape page:
11"x8.5"
8.5"x11" # 90 degrees rotation
8.5"x11" # 270 degrees rotation
Technically, a 4th way is to build an 11x8.5 # 180, but anyone writing such code should be Punished. A lot.
There are various SO questions floating about that give details on how to deal with page rotation. Going by your code, I'd say you'll figure out the llx,lly thing pretty quickly.