I am trying to get the x and y coordinates from a pdf document on click event. Pdf documents do not have DOM that's why I am overlaying a div on the top of the pdf document to get the coordinates from the div. I am using itextsharp library and trying to stamp a value you the pdf document. Unfortunately the x and y coordinates of the div are in pixels and I need to relate them to the values in the stamper.
The X coordinates that I am getting from the div click event are: 80, 300, 600, 880
and the X coordinates that I need to enter in the stamper are 10, 205,405,600. What ratio do I need to apply to convert the div coordinates to the stamper coordinates.
private static void InsertTextToPdf(string sourceFileName, string newFileName)
{
using (Stream pdfStream = new FileStream(sourceFileName, FileMode.Open))
{
using (Stream newpdfStream = new FileStream(newFileName, FileMode.Create, FileAccess.ReadWrite))
{
PdfReader pdfReader = new PdfReader(pdfStream);
iTextSharp.text.Rectangle pageSize = pdfReader.GetPageSize(1);
Console.Write(pageSize);
PdfStamper pdfStamper = new PdfStamper(pdfReader, newpdfStream);
PdfContentByte pdfContentByte = pdfStamper.GetOverContent(1);
BaseFont baseFont = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1250, BaseFont.NOT_EMBEDDED);
pdfContentByte.SetColorFill(BaseColor.RED);
pdfContentByte.SetFontAndSize(baseFont, 12);
pdfContentByte.BeginText();
pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "Test", 10, 190, 0);
pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "Test", 205, 190, 0);
pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "Test", 405, 190, 0);
pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "Test", 600, 190, 0);
pdfContentByte.EndText();
pdfStamper.Close();
}
}
}
Trying to get the userUnit - in my case they are null
PdfReader pdfReader = new PdfReader(pdfStream);
iTextSharp.text.Rectangle pageSize = pdfReader.GetPageSize(1);
Console.Write(pageSize);
iTextSharp.text.pdf.PdfDictionary pageDict = pdfReader.GetPageN(1);
iTextSharp.text.pdf.PdfNumber userUnit = pageDict.GetAsNumber(iTextSharp.text.pdf.PdfName.USERUNIT);
Console.Write("\nPageDict " + pageDict);
Console.Write("\nUser Unit " + userUnit);
You are making different assumptions that are wrong.
There is an FAQ on the official iText web site, where you can find questions that were answered before on Stack Overflow.
Measurement unit
The first FAQ entry you have to read is: How to get the UserUnit from a PDF file?
I quote:
FAQ What is the measurement unit in PDF documents? Most of the measurements
in PDFs are expressed in user space units. ISO-32000-1 (section 8.3.2.3) tells us
“the default for the size of the unit in default user space (1/72 inch) is
approximately the same as a point (pt), a unit widely used in the printing
industry. It is not exactly the same; there is no universal definition of a point.”
In short, 1 in. = 25.4 mm = 72 user units (which roughly corresponds to 72 pt).
By default 72 user units are 1 inch, but this default can be changed by defining a UserUnit.
Coordinate system: orientation
The second FAQ entry you have to read is: How should I interpret the coordinates of a rectangle in PDF?
Let me just copy/paste the image:
Coordinate system: origin
Finally, you have to read: Where is the origin (x,y) of a PDF page?
After reading the previous question, you might assume that the lower-left corner corresponds with the coordinate (0, 0), but that's not always true.
Why your question can't be answered
You claim that you are presenting the PDF as an image, and that you can retrieve coordinates as pixel coordinates, e.g. the 80th pixel in row 300 of all the pixel rows. However, if no one knows at which resolution the PDF is rendered when you converted the PDF (vector data) to a raster image, no one can tell you how the user units relate to pixels. That's something only you can know.
So please read the answers to the questions listed above carefully, and you'll be able to do the necessary Math.
Related
I have a very simple code that places the png image into PDF
Document pdfDoc = new Document(PageSize.A4, 25, 25, 25, 10);
string pathfile = ConfigurationManager.AppSettings["Temp_SaveLocation"];
string fileName = "SomeName.pdf";
path = pathfile + fileName;
PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream(path, FileMode.Create));
pdfDoc.Open();
Image imghead = Image.GetInstance(templateFolder + "Letterhead.png");
imghead.SetAbsolutePosition(0, 0);
pdfDoc.Add(imghead);
pdfWriter.CloseStream = true;
pdfDoc.Close();
However, no matter what position for the image I set, that image ends up on a very bottom of a document. I even tried negative values for the absolute position. Nevertheless, the image stays on the very bottom of a document. How can I bring an image to a very top?
Thank you very much in advance
I found out that image will be to the top when this code is removed.
imghead.SetAbsolutePosition(0, 0);
I agree with K J. By setting imghead.SetAbsolutePosition(0, 0), you are setting your image to be at (X,Y) co-ordinate which is mostly lower left co-ordinate of the page.
Generally, lower-left corner of the page coincides with the origin of the coordinate system (0, 0). The upper-right corner of the page coincides with the coordinate (595, 842). You either remove or comment this method imghead.SetAbsolutePosition(0, 0) or adjust the Y co-ordinate of it to move the image towards the upper side of the page.
I have 5 pages pdf need to highlight specific element based on coordinates
Have X top left,Y top left,X top right ,Y top right , X bottom right , Y bottom right ,X bottom left, Y bottom left .
I tried below code using iTextsharp please suggest how can we do this including page no
using System;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
//Create a simple test file
string outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Test.pdf");
//Create a new file from our test file with highlighting
string highLightFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Highlighted.pdf");
//Bind a reader and stamper to our test PDF
PdfReader reader = new PdfReader(outputFile);
using (FileStream fs = new FileStream(highLightFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (PdfStamper stamper = new PdfStamper(reader, fs))
{
//Create a rectangle for the highlight. NOTE: Technically this isn't used but it helps with the quadpoint calculation
iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(60.6755f, 749.172f, 94.0195f, 735.3f);
//Create an array of quad points based on that rectangle. NOTE: The order below doesn't appear to match the actual spec but is what Acrobat produces
float[] quad = { rect.Left, rect.Bottom, rect.Right, rect.Bottom, rect.Left, rect.Top, rect.Right, rect.Top };
//Create our hightlight
PdfAnnotation highlight = PdfAnnotation.CreateMarkup(stamper.Writer, rect, null, PdfAnnotation.MARKUP_HIGHLIGHT, quad);
//Set the color
highlight.Color = BaseColor.YELLOW;
//Add the annotation
stamper.AddAnnotation(highlight,1);
}
}
Output
Highlight element in rectangular.
Need to highlight 3rd page of PDF.
"boundingBox": [3.2924,7.7146,5.7564,7.7038,5.7671,7.9836,3.3032,7.9943]
this "text": "66 66 6666 6666" should get higlighted
Input File
Output File
Wrong page
First of all, you add the annotation to the wrong page.
You say
Need to highlight 3rd page of PDF.
but you put it on page 1:
stamper.AddAnnotation(highlight,1);
To fix this, change the page number there:
stamper.AddAnnotation(highlight,3);
Wrong coordinates
Neither the coordinates in your code
iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(60.6755f, 749.172f, 94.0195f, 735.3f);
nor those you gave in that JSON'ish way
"boundingBox": [3.2924,7.7146,5.7564,7.7038,5.7671,7.9836,3.3032,7.9943]
are anywhere near the location you want to highlight, at least not in the regular PDF coordinate system given by the page media box. By measuring in Adobe Acrobat I got the following approximate coordinates:
iTextSharp.text.Rectangle rect = new iTextSharp.text.Rectangle(240f, 264f, 413f, 289f);
If any of the coordinates you showed are meant to be actual coordinates of the image part to highlight, ask the provider of those coordinates about the coordinate system used and accordingly transform to coordinates in the given page's media box.
Questionable order in QuadPoints
You create quad using this order:
float[] quad = { rect.Left, rect.Bottom, rect.Right, rect.Bottom, rect.Left, rect.Top, rect.Right, rect.Top };
This results in concave caps. You probably want to use
float[] quad = { rect.Left, rect.Top, rect.Right, rect.Top, rect.Left, rect.Bottom, rect.Right, rect.Bottom };
instead which Adobe Reader shows as convex caps. For a background read this answer.
Example output
You say:
"66 66 6666 6666" should get higlighted
With the three changes above applied to your code I get this:
I have some code used to watermark PDFs using iTextSharp. The code works fine for most PDFs, but there has been one test case where the watermark is not visible on a PDF of a scanned document. (I have other scanned documents where it does appear though).
I am using the GetOverContent() method.
This is my code for adding the watermark;
using (PdfReader reader = new PdfReader(this.inputFilename))
{
// Set transparent - 1
PdfGState gstate = new PdfGState();
gstate.FillOpacity = 0.4f;
gstate.StrokeOpacity = 0.5f;
// 2
BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, Encoding.ASCII.EncodingName, false);
using (var stream = new MemoryStream())
{
var pdfStamper = new PdfStamper(reader, stream);
// Must start at 1 because 0 is not an actual page.
for (int i = 1; i <= reader.NumberOfPages; i++)
{
Rectangle pageSize = reader.GetPageSizeWithRotation(i);
// Gets the content ABOVE the PDF, Another option is GetUnderContent(...)
// which will place the text below the PDF content.
PdfContentByte pdfPageContents = pdfStamper.GetOverContent(i);
pdfPageContents.BeginText(); // Start working with text.
// 1
pdfPageContents.SaveState();
pdfPageContents.SetGState(gstate);
float hypotenuse = (float)Math.Sqrt(Math.Pow(pageSize.Width, 2) + Math.Pow(pageSize.Height, 2));
float glyphWidth = baseFont.GetWidth("My watermark text");
float fontSize = 1000 * (hypotenuse * 0.8f) / glyphWidth;
float angle = (float)(Math.Atan(pageSize.Height / pageSize.Width) * (180 / Math.PI));
// Create a font to work with
pdfPageContents.SetFontAndSize(baseFont, fontSize);
pdfPageContents.SetRGBColorFill(128, 128, 128); // Sets the color of the font, GRAY in this instance
// Note: The x,y of the Pdf Matrix is from bottom left corner.
// This command tells iTextSharp to write the text at a certain location with a certain angle.
// Again, this will angle the text from bottom left corner to top right corner and it will
// place the text in the middle of the page.
pdfPageContents.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "My watermark text", pageSize.Width / 2, pageSize.Height / 2, angle);
pdfPageContents.EndText(); // Done working with text
pdfPageContents.RestoreState();
}
pdfStamper.FormFlattening = true; // enable this if you want the PDF flattened.
pdfStamper.FreeTextFlattening = true; // enable this if you want the PDF flattened.
pdfStamper.Close(); // Always close the stamper or you'll have a 0 byte stream.
return stream.ToArray();
}
}
Does anyone have any ideas as to why the watermark may not be appearing and what I can try to fix it?
Kind regards.
The code is based on an assumption it even documents as a fact:
// Note: The x,y of the Pdf Matrix is from bottom left corner.
// This command tells iTextSharp to write the text at a certain location with a certain angle.
// Again, this will angle the text from bottom left corner to top right corner and it will
// place the text in the middle of the page.
pdfPageContents.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "My watermark text", pageSize.Width / 2, pageSize.Height / 2, angle);
The assumption that the x,y of the Pdf Matrix is from bottom left corner unfortunately is wrong: While it indeed is very often the case that the origin of the PDF coordinate system (the default user space coordinate system, to be more precise) is in the lower left corner of the page, this is not required, the origin actually can be literally anywhere (within reasonable limits).
Thus, one has to take the lower left coordinates of the Rectangle pageSize into consideration, too.
The OP meanwhile has confirmed:
I had assumed that the bottom left of the page would have co-ordinates of (0,0) but for this document the co-ordinates were (0, 7022).
I'm trying to enlarge the icon of a PDF sticky note. Here's an image showing the sticky icon that I've stamped on the first page of the PDF for context:
I was under the impression the icon was guided by a rectangle that could be manipulated. Here's my code that has not been effective yet:
using (PdfStamper stamp = new PdfStamper(reader, fs))
{
PdfWriter attachment = stamp.Writer;
foreach (string file in files_to_attach)
{
PdfFileSpecification pdfAttch = PdfFileSpecification.FileEmbedded(attachment, file, file, null);
stamp.AddFileAttachment(file, pdfAttch);
}
//Create Note for first page
Rectangle rect = new Rectangle(850, 850, 650, 650);
PdfAnnotation annotation = PdfAnnotation.CreateText(stamp.Writer, rect, "TITLE OF NOTE", "Body text of the note", false, "Comment");
//Enlarge the Sticky Note icon
PdfDictionary page = reader.GetPageN(1);
PdfArray annots = page.GetAsArray(PdfName.ANNOTS);
PdfDictionary sticky = annots.GetAsDict(0);
PdfArray stickyRect = sticky.GetAsArray(PdfName.RECT);
PdfRectangle stickyRectangle = new PdfRectangle(
stickyRect.GetAsNumber(0).FloatValue - 50, stickyRect.GetAsNumber(1).FloatValue - 20,
stickyRect.GetAsNumber(2).FloatValue, stickyRect.GetAsNumber(3).FloatValue - 30);
sticky.Put(PdfName.RECT, stickyRectangle);
//Apply the Note to the first page
stamp.AddAnnotation(annotation, 1);
stamp.Close();
}
I thought I could change the float values and that would change the shape of the icon but so far it has not effected it all. Thank you for any suggestions.
You can't. The icon that is displayed for the "Comment" annotation is supplied by the viewer. The rect property is only used to define the lower left corner of where the icon gets placed on the page by the viewer. According to the PDF specification for annotations with the type "Text", "Conforming readers shall provide predefined icon appearances for at least the following standard names: Comment, Key, Note, Help, NewParagraph, Paragraph, Insert.
You can, however, create your own image, of any size, and use it as the appearance for a "Stamp" annotation. It can even look exactly like a "Comment" icon, just bigger. It would end up functioning in the same way for the end user.
I have a problem with regards on the page orientation of the paper size.
I have a pdf file which contains portrait and landscape page.
this code works perfectly.
string FileLocation = "c:\\Temp\\SomeFile.pdf";
string WatermarkLocation = "c:\\Temp\\watermark.gif";
Document document = new Document();
PdfReader pdfReader = new PdfReader(FileLocation);
PdfStamper stamp = new PdfStamper(pdfReader, new FileStream(FileLocation.Replace(".pdf","[temp][file].pdf"), FileMode.Create));
iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(WatermarkLocation);
img.SetAbsolutePosition(250,300); // set the position in the document where you want the watermark to appear (0,0 = bottom left corner of the page)
PdfContentByte waterMark;
for (int page = 1; page <= pdfReader.NumberOfPages; page++)
{
waterMark = stamp.GetUnderContent(page);
waterMark.AddImage(img);
}
stamp.FormFlattening = true;
stamp.Close();
// now delete the original file and rename the temp file to the original file
File.Delete(FileLocation);
File.Move(FileLocation.Replace(".pdf", "[temp][file].pdf"), FileLocation);
since I'm using absolute value to set the image position.
img.SetAbsolutePosition(250,300);
How can T set the image position if the page is landscape or portrait?
note: One pdf with landscape and portrait page orientation.
Is there by chance that I can use if statement?
if (//paper is landscape)
{
//code here
}
else
{
//code here
}
What do you want to achieve?
Normally, iText takes into account the value of the page rotation. This means that when a page is rotated, the coordinates will be rotated too.
If you want to overrule this, you can add this line:
stamper.RotateContents = false;
This is explained in Chapter 6 of my book. You can try this example to see the difference:
No rotation, text added normally: hello1.pdf
Rotation, text added normally ( = rotated): hello2.pdf
Rotation, text added with rotation ignored: hello3.pdf
Of course, this assumes that a rotation was defined for the pages. Sometimes, landscape is mimicked by defining a different page size instead of defining a rotation.
In that case, you should also read Chapter 6 because it explains how to get the MediaBox of a document. see the example PageInformation that introduces methods such as GetPageSize(), GetRotation() and GetPageSizeWithRotation().
This is all documented, but if it doesn't answer your question, please clarify. As demonstrated in the example, the rotation is taken into account by default when adding new content, so maybe I misunderstood the question.