"At least one signature is invalid" After adding stamp in Signed PDF - c#

I need to add stamp or image annotation in a signed PDF but it gives me an "invalid signature" error and, after moving this annotation, it gives me an "at least one signature required validating" error. How can I solve this?
I also found a solution but for text annotation in this question.
It worked fine with text annotation but I cannot do the same for the stamp.
iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(#"D:\\11.jpg");
float w = 100;
float h = 100;
iTextSharp.text.Rectangle location = new iTextSharp.text.Rectangle(36, 770 - h, 36 + w, 770);
PdfAnnotation stamp = PdfAnnotation.CreateStamp(stamper.Writer, location, null, "ITEXT");
img.SetAbsolutePosition(0, 0);
PdfContentByte cb = stamper.GetOverContent(1);
PdfAppearance app = cb.CreateAppearance(100, 100);
app.AddImage(img);
stamp.SetAppearance(PdfName.N, app);
stamper.AddAnnotation(stamp, 1);

This
PdfContentByte cb = stamper.GetOverContent(1);
is the line causing the invalidation of the signature.
Calling stamper.GetOverContent (or stamper.GetUnderContent) already prepares the page contents for the addition of new content. This preparation already is considered a change of page content. As page content changes to a signed PDF are forbidden, this invalidates the signature.
You only use this PdfContentByte cb to create a PdfAppearance for your stamp annotation:
PdfAppearance app = cb.CreateAppearance(100, 100);
Fortunately you don't need cb to create a PdfAppearance, there also is a static PdfAppearance method to do so. Thus, simply replace
PdfContentByte cb = stamper.GetOverContent(1);
PdfAppearance app = cb.CreateAppearance(100, 100);
by
PdfAppearance app = PdfAppearance.CreateAppearance(stamper.Writer, 100, 100);

The wrong way :
var pdfContentByte = st.GetOverContent(1);
Image sigimage = Image.GetInstance(bytes);
pdfContentByte.AddImage(sigimage);
Calling stamper.GetOverContent (or stamper.GetUnderContent) caused the problem. I was adding signature images as an independent content to the PDF pdfContentByte, which is altering the document content, thus invalidating existing signatures.
The solution was to add the images with the stamp like this:
First, allow incremental updates (
PdfStamper st = PdfStamper.CreateSignature(reader, new FileStream(output, FileMode.Create, FileAccess.ReadWrite), '\0', null, true);
Second, add the image with the signature appearance itself
Image sigimage = Image.GetInstance(bytes);
sap.Image = sigimage; // sap is the signature appearance
Last, set the renderer to Description( so you can get both the text and the image you added to the signature appearance
sap.Render = PdfSignatureAppearance.SignatureRender.Description;
Hope this helps

Related

Is it possible to change the appearance of the signature within the document after signing it?

Before calculating the hash of the document for signing I am adding the TextField in my document using the below code. as I am following this link
Changing signature appearance after signing pdf file with iTextSharp
Here is a code that adds signature on all pages and adds a text field on the first page.
the purpose of the text field is to extract the "IssuedTo" from the certificate and display it on the signature appearance.
Before esign open pdf in update mode:
XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signatures");
string signature = nodeList[0].FirstChild.InnerText;
string src = Server.MapPath("~/ESignFiles/" + file_withoutExtn + "_temp.pdf");
string dest = Server.MapPath("~/ESignFiles/" + file_withoutExtn + "_multiple_signed.pdf");
///add text
AddText(src, dest);
///add text
using (PdfReader reader = new PdfReader(src))
{
using (FileStream os = new FileStream(dest, FileMode.Create))
{
byte[] encodedSignature = Convert.FromBase64String(signature);
IExternalSignatureContainer external = new MyExternalSignatureContainer(encodedSignature);
MakeSignature.SignDeferred(reader, "sign1", os, external);
}
}
Code that add text to temp pdf
public void AddText(String src, String dest) {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create), '\0', true);
ColumnText.ShowTextAligned(stamper.GetOverContent(1), Element.ALIGN_LEFT, new Phrase("client name"), 200, 380, 0);
stamper.Close();
}
First of all, as has been discussed in comments to the question and to Bharat's answer:
The need to update signature appearances after applying the signature indicates a bad architecture of the signing solution.
In the case at hand this bad architecture appears to be a result of the requirements ("appearances must include certificate information" in combination with "certificate is not available before signing"). Nonetheless this is a bad architecture and should be improved after reviewing and revising the requirements.
But it indeed is possible under benign circumstances to update signature appearances: If the existing signatures allow for "form fill-ins and annotation changes" and do not completely lock the respective signature fields, the appearances of signatures can be updated in an incremental update without invalidating the signatures (validators may warn about a change, though).
Updating generic PDF signatures
The PDF specification does not specifically define a structure for the appearance of a signature field, a generic solution simply has to replace the appearance stream of each signature field widget annotation with a new one. This can be done like this using iText 5.5.x for .Net:
using (PdfReader pdfReader = new PdfReader(SRC))
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(DEST, FileMode.Create, FileAccess.Write), '\0', true))
{
AcroFields acroFields = pdfStamper.AcroFields;
foreach (String signatureName in acroFields.GetSignatureNames())
{
PdfPKCS7 pkcs7 = acroFields.VerifySignature(signatureName);
X509Certificate signerCert = pkcs7.SigningCertificate;
String signerName = CertificateInfo.GetSubjectFields(signerCert).GetField("CN");
PdfAppearance appearance = PdfAppearance.CreateAppearance(pdfStamper.Writer, 100, 100);
ColumnText columnText = new ColumnText(appearance);
Chunk chunk = new Chunk();
chunk.SetSkew(0, 12);
chunk.Append("Signed by:");
columnText.AddElement(new Paragraph(chunk));
chunk = new Chunk();
chunk.SetTextRenderMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, 1, BaseColor.BLACK);
chunk.Append(signerName);
columnText.AddElement(new Paragraph(chunk));
columnText.SetSimpleColumn(0, 0, 100, 100);
columnText.Go();
PdfDictionary appDict = new PdfDictionary();
appDict.Put(PdfName.N, appearance.IndirectReference);
AcroFields.Item field = acroFields.GetFieldItem(signatureName);
for (int i = 0; i < field.Size; i++)
{
PdfDictionary widget = field.GetWidget(i);
PdfArray rect = widget.GetAsArray(PdfName.RECT);
float x = Math.Min(rect.GetAsNumber(0).FloatValue, rect.GetAsNumber(0).FloatValue);
float y = Math.Min(rect.GetAsNumber(1).FloatValue, rect.GetAsNumber(3).FloatValue);
widget.Put(PdfName.RECT, new PdfArray(new float[] { x, y, x + 100, y + 100 }));
}
field.WriteToAll(PdfName.AP, appDict, AcroFields.Item.WRITE_WIDGET);
field.MarkUsed(acroFields, AcroFields.Item.WRITE_WIDGET);
}
}
As you can see the code extracts the subject's common name from the signer certificate and writes it (prefixed by a "Signed by:" line) to the new appearance. If you need other data in your your replacement appearance, simply change the data added to the columnText and/or the appearance accordingly.
Furthermore, the code replace all appearances with new ones which are 100×100 in size. You of course can adapt this to your requirements, too.
This essentially is a port of code from this answer to C#.
Updating PDF signatures using the Adobe specific layers
Adobe Acrobat Reader uses a specific scheme to build its signature appearances and even adds a certain functionality to signatures built according to an older version of this scheme. As mentioned above, the PDF specification does not prescribe any such scheme; actually it even forbids such a functionality, cf. this answer.
Nonetheless many stack overflow questions in particular from India seem to indicate that signatures following that obsolete scheme are often required there by clients.
If one follows this scheme, the appearance itself is constructed as a hierarchy of form XObjects, in particular a set of so called "layers" n0 through n4 from which n2 is the layer onto which a signer is expected to apply its identity.
The generic solution above can be adapted as follows to comply with this scheme:
using (PdfReader pdfReader = new PdfReader(SRC))
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(DEST, FileMode.Create, FileAccess.Write), '\0', true))
{
AcroFields acroFields = pdfStamper.AcroFields;
foreach (String signatureName in acroFields.GetSignatureNames())
{
PdfPKCS7 pkcs7 = acroFields.VerifySignature(signatureName);
X509Certificate signerCert = pkcs7.SigningCertificate;
String signerName = CertificateInfo.GetSubjectFields(signerCert).GetField("CN");
AcroFields.Item field = acroFields.GetFieldItem(signatureName);
for (int i = 0; i < field.Size; i++)
{
PdfDictionary widget = field.GetWidget(i);
Rectangle rect = PdfReader.GetNormalizedRectangle(widget.GetAsArray(PdfName.RECT));
PdfAppearance appearance = PdfAppearance.CreateAppearance(pdfStamper.Writer, rect.Width, rect.Height);
ColumnText columnText = new ColumnText(appearance);
Chunk chunk = new Chunk();
chunk.SetSkew(0, 12);
chunk.Append("Signed by:");
columnText.AddElement(new Paragraph(chunk));
chunk = new Chunk();
chunk.SetTextRenderMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE, 1, BaseColor.BLACK);
chunk.Append(signerName);
columnText.AddElement(new Paragraph(chunk));
columnText.SetSimpleColumn(0, 0, rect.Width, rect.Height - 15);
columnText.Go();
PdfDictionary xObjects = GetAsDictAndMarkUsed((PdfStamperImp)pdfStamper.Writer, widget, PdfName.AP, PdfName.N, PdfName.RESOURCES, PdfName.XOBJECT, PdfName.FRM, PdfName.RESOURCES, PdfName.XOBJECT);
xObjects.Put(PdfName.N2, appearance.IndirectReference);
}
}
}
making use of the following helper method:
PdfDictionary GetAsDictAndMarkUsed(PdfStamperImp writer, PdfDictionary dictionary, params PdfName[] names)
{
PRIndirectReference reference = null;
foreach (PdfName name in names)
{
if (dictionary != null)
{
dictionary = dictionary.GetDirectObject(name) as PdfDictionary;
if (dictionary != null)
{
if (dictionary.IndRef != null)
reference = dictionary.IndRef;
}
}
}
if (reference != null)
writer.MarkUsed(reference);
return dictionary;
}
(Beware: This code assumes the signatures to follow the Adobe scheme; if you are not sure that your input does, add some sanity checks and default to the generic solution above.)
Since appearance is part of document while calculating hash to be signed, changing appearance will change hash and invalidate the signature already done.

iTextSharp CreateInk method: curves and corners

I'm using iTextSharp to draw markup graphics in PDF documents, using PdfAnnotation.CreateInk. I'm trying to draw rectangles, passing in an array of five co-ordinates. I know iTextSharp has a dedicated function for drawing rectangles, but I'm trying to use just one method to draw the various kinds of markup lines I need, and it seems that CeateInk should be able to do that.
The problem is that CreateInk is drawing the rectangle with curves rather than corners. I haven't been able to figure out how to change this. This answer suggests that the solution might be to create a PdfAppearance; I haven't yet figured out whether that will work. Here's my code (the first bit converts a list of list of points to an array of arrays, which InkList requires):
public void MarkupInk(List<List<float>> InkList){
float[][] Coords = new float[InkList.Count][];
for (int i = 0; i < InkList.Count; i++) {
float[] thisarr = InkList [i].ToArray ();
Coords[i] = new float[InkList[i].Count];
System.Array.Copy (thisarr, Coords [i], InkList [i].Count);
}
using(MemoryStream ms = new MemoryStream ()){
PdfReader reader = new PdfReader (textmaster.pdfDocArr);
PdfStamper stamper = new PdfStamper (reader, ms);
pagerect = reader.GetPageSize (textmaster.currentfirstpage + 1);
PdfAnnotation an2 = PdfAnnotation.CreateInk (stamper.Writer, pagerect, "", Coords);
an2.Color = strokeColor;
an2.BorderStyle = new PdfBorderDictionary (strokeWeight, PdfBorderDictionary.STYLE_SOLID);
stamper.AddAnnotation (an2, textmaster.currentfirstpage+1);
stamper.Close ();
textmaster.pdfDocArr = ms.ToArray ();
reader.Close ();
}
}
Any suggestions are much appreciated. Thanks!
EDIT: following #mkl's code I now have code that creates PDFAnnotations with appearances. And most of those annotations show up correctly in the viewing applications I use. But there is one odd behavior that I have not been able to fix.
What's happening is that the most recently created annotation does not appear in the viewing applications until I've created another annotation. So if I create annotation A, it's invisible until I create annotation B, at which point annotation A appears and B does not. Creating annotation C causes annotation B to appear, and so on.
This behavior persists even if I close the pdf file and the viewing application and re-load from disk. So the data describing the last-created annotation exists as part of the pdf file, but it doesn't render until I've created a new annotation.
I suspect there's something I'm still missing in the code I'm using to create the annotations and pdfAppearances. Here's code that creates a single line annotation:
public void WriteLineAnnotation(List<float> polyCoords){
using (MemoryStream ms = new MemoryStream ()) {
PdfReader reader = new PdfReader (textmaster.pdfDocArr);
PdfStamper stamper = new PdfStamper (reader, ms) { AnnotationFlattening = true };
pagerect = reader.GetPageSize (textmaster.currentfirstpage + 1);
//Create the pdfAnnotation polyline
PdfAnnotation polyann = PdfAnnotation.CreatePolygonPolyline (stamper.Writer, pagerect, "", false, new PdfArray (polyCoords.ToArray ()));
polyann.Color = strokeColor;
polyann.BorderStyle = new PdfBorderDictionary (strokeWeight, PdfBorderDictionary.STYLE_SOLID);
polyann.Flags = iTextSharp.text.pdf.PdfAnnotation.FLAGS_PRINT;
//create the PdfAppearance and set attributes
PdfAppearance app = PdfAppearance.CreateAppearance (stamper.Writer, pagerect.Width, pagerect.Height);
app.SetColorStroke (strokeColor);
app.MoveTo (polyCoords [0], polyCoords [1]);
app.LineTo (polyCoords [2], polyCoords [3]);
app.Stroke ();
//set the annotation's appearance, add annotation, clean up
polyann.SetAppearance (PdfName.N, app);
stamper.AddAnnotation (polyann, textmaster.currentfirstpage + 1);
stamper.Close ();
reader.Close ();
//create bytearray from memorystream and send to pdf renderer
textmaster.pdfDocArr = ms.ToArray ();
}
}
[/code]
Is there something obvious that I'm missing? Thanks in advance for any help.
Which annotation type to use
I know iTextSharp has a dedicated function for drawing rectangles, but I'm trying to use just one method to draw the various kinds of markup lines I need, and it seems that CeateInk should be able to do that.
Please be aware that iText not merely has separate functions for those different forms, these different functions also create different types of PDF annotations.
In particular the Ink annotation -- which you would like to use for all forms -- is specified as
An ink annotation (PDF 1.3) represents a freehand “scribble” composed of one or more disjoint paths.
(Section 12.5.6.13 - Ink Annotations - ISO 32000-1)
As a freehand “scribble” commonly is not considered to be a sequence of straight lines and sharp corners but instead more soft and rounded; thus, it is only natural that PDF viewers will display an ink annotation given by coordinates of the corners of a rectangle with curves rather than corners.
Of course you can use an appearance stream to provide a visualization of the appearance but that would be a small misuse of this PDF feature.
Instead I would propose you use a different kind of annotation to draw the various kinds of markup lines you need: Polyline annotations. They are specified as:
Polygon annotations (PDF 1.5) display closed polygons on the page. Such polygons may have any number of vertices connected by straight lines. Polyline annotations (PDF 1.5) are similar to polygons, except that the first and last vertex are not implicitly connected.
(Section 12.5.6.9 - Polygon and Polyline Annotations - ISO 32000-1)
iText(Sharp) provides a method for this kind of annotations, too:
/**
* Creates a polygon or -line annotation
* #param writer the PdfWriter
* #param rect the annotation position
* #param contents the textual content of the annotation
* #param polygon if true, the we're creating a polygon annotation, if false, a polyline
* #param vertices an array with the vertices of the polygon or -line
* #since 5.0.2
*/
public static PdfAnnotation CreatePolygonPolyline(
PdfWriter writer, Rectangle rect, String contents, bool polygon, PdfArray vertices)
You might eventually still have to create annotations as not all PDF viewers, in particular so called "pre-viewers", generate appearances but instead count on appearances being provided in PDFs they pre-display...
Examples
Without own appearance
using (PdfReader pdfReader = new PdfReader(inputPath))
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream))
{
PdfArray vertices = new PdfArray(new int[]{ 100, 100, 300, 300, 100, 300, 300, 100 });
PdfAnnotation polyLine = PdfAnnotation.CreatePolygonPolyline(pdfStamper.Writer, pdfReader.GetPageSize(1),
"", false, vertices);
polyLine.Color = BaseColor.GREEN;
pdfStamper.AddAnnotation(polyLine, 1);
}
adds this:
in PDF viewers supporting annotations including appearance generation according to the specification.
With own appearance
using (PdfReader pdfReader = new PdfReader(inputPath))
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream))
{
Rectangle pageSize = pdfReader.GetPageSize(1);
PdfArray vertices = new PdfArray(new int[] { 100, 100, 300, 300, 100, 300, 300, 100 });
PdfAnnotation polyLine = PdfAnnotation.CreatePolygonPolyline(pdfStamper.Writer, pageSize,
"", false, vertices);
polyLine.Color = BaseColor.GREEN;
PdfAppearance appearance = PdfAppearance.CreateAppearance(pdfStamper.Writer, pageSize.Width, pageSize.Height);
appearance.SetColorStroke(BaseColor.RED);
appearance.MoveTo(100, 100);
appearance.LineTo(300, 300);
appearance.LineTo(100, 300);
appearance.LineTo(300, 100);
appearance.Stroke();
polyLine.SetAppearance(PdfName.N, appearance);
pdfStamper.AddAnnotation(polyLine, 1);
}
adds this
in PDF viewers supporting annotations which bring along their annotation according to the specification.
(I explicitly used a different color in my appearance to make sure the PDF viewer shows my appearance and does not create one itself.)

How to show digital signature VALUE in signature appearance of PDF file with iTextSharp

Is it possible to append Digital signature VALUE in signature appearance while signing document, because I am using this part of code
PdfFilename = txtFile.Text + "\\" + (string)chkLista.Items[i];
DestPdfFilename = txtFile.Text + "\\" + (string)chkLista.Items[i] + "-signed.pdf";
Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { cp.ReadCertificate(cert.RawData) };
IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-256");
PdfReader pdfReader = new PdfReader(PdfFilename);
FileStream signedPdf = new FileStream(DestPdfFilename, FileMode.Create); //the output pdf file
PdfStamper pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0');
PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance;
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
signatureAppearance.SetVisibleSignature(new iTextSharp.text.Rectangle(436, 700, 564, 750), 1, "sig");
MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CMS);
but in PDF it shows only the rectangle filled only with data like: Digitally signed by:... and Date:...
Except this I want to be showed digital signature Value in Base64 too!
If I correctly understand the OP, the task is to display a base64 representation of the actual signature value bytes as the signature field appearance.
This is not possible.
The reason is that the appearance of the signature field is part of the signed byte range:
(The appearance is defined somewhere in the first or third section in the example.)
Therefore, the appearance must be known before the signature value is created. Thus, the value cannot completely be represented in the field appearance.
For more backgrounds read this answer.
That been said, you might try to cheat a bit by adding JavaScript to the PDF which at display time changes the appearance of the signature field. This approach has two drawbacks, though:
Not all PDF viewers support JavaScript.
Adobe Reader and Acrobat, the main PDF viewers also supporting JavaScript, would recognize this change of the appearance and indicate that the signature is broken.

Write text on existing table/Image using itextsharp

There is an existing table/image. When I write text using pdfcontentbyte, it is written behind this table/image.
I also want to write the text from the right side of this table/column.
The code I'm currently using to produce the image above:
// open the reader
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();
PdfContentByte cb = writer.DirectContent;
BaseFont bf = BaseFont.CreateFont(BaseFont.COURIER_BOLD,BaseFont.CP1252, BaseFont.EMBEDDED);
string text = "WV0501";
cb.BeginText();
// put the alignment and coordinates here
cb.ShowTextAligned(2, text, 155, 655, 0);
cb.EndText();
// create the new page and add it to the pdf
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
document.Close();
fs.Close();
writer.Close();
You don't show us your code, so we have to guess what you are doing wrong.
The content isn't showing:
You probably have this line in your code:
PdfContentByte canvas = pdfStamper.GetUnderContent(page);
If so, you should replace it with this line:
PdfContentByte canvas = pdfStamper.GetOverContent(page);
Update after you showed us your code:
You want to add content to an existing document, yet you are using a combination of Document and PdfWriter. Why are you doing this? Please read chapter 6 of my book where you'll learn about PdfStamper.
Right now, you are adding the text first and then you are covering it with a page from an existing document. This means that the existing page will cover the text.
You can switch this around like this:
// create the new page and add it to the pdf
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
BaseFont bf = BaseFont.CreateFont(BaseFont.COURIER_BOLD,BaseFont.CP1252, BaseFont.EMBEDDED);
string text = "WV0501";
cb.BeginText();
// put the alignment and coordinates here
cb.ShowTextAligned(2, text, 155, 655, 0);
cb.EndText();
Now the text will cover the page, but that doesn't mean your code is better. You should really use PdfStamper instead of PdfWriter:
PdfReader reader = new PdfReader(oldFile);
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write);
PdfStamper stamper = new PdfStamper(reader, fs);
PdfContentByte canvas = stamper.GetOverContent(1);
BaseFont bf = BaseFont.CreateFont(BaseFont.COURIER_BOLD,BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
ColumnText.ShowTextAligned(
canvas,
Element.ALIGN_RIGHT,
new Phrase("WV0501", new Font(bf, 9)),
155, 655, 0
);
stamper.Close();
Don't you agree that this is more elegant?
IMPORTANT:
In your code you use:
BaseFont bf = BaseFont.CreateFont(BaseFont.COURIER_BOLD,BaseFont.CP1252, BaseFont.EMBEDDED);
However, that doesn't make much sense: COURIER_BOLD is one of the Standard Type 1 fonts and because of that the embedded parameter is ignored. I changed this into NOT_EMBEDDED because if you use EMBEDDED developers who read your code and who don't know anything about PDF and iText may get confused. They might ask: Why is the font not getting embedded when the parameter says it should be embedded?
BaseFont bf = BaseFont.CreateFont(BaseFont.COURIER_BOLD,BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
Writing from the right side:
You are defining the alignment using a number: 2. I suggest that you don't use a number in your code, but a constant: ALIGN_RIGHT. This way, we see that you want to right align the text.
The text is right aligned with respect to the coordinates you've defined:
x = 155
y = 655
If you are not happy with the position of your text, you should change these hard-coded coordinates. For instance: increase x and decrease y.
You probably want the text to be relative to the border of a table cell or an image. If that is the case, you should not hard-code the coordinates.
Retrieving the coordinates of an image is discussed in another question on SO. Retrieving the coordinates of a table might very well be impossible. It all depends on the nature of the original PDF.

Variable data on pdf

I want to add variable text and thumbnail images on specific position.
Text with formatting like fontstyles,rotation etc.
iTextSharp.text.pdf.PdfReader reader = null;
Document document = new Document();
PdfWriter writer;
writer = PdfWriter.GetInstance(document,
new FileStream(temp,
FileMode.Create, FileAccess.Write));
reader = new iTextSharp.text.pdf.PdfReader(file);
size = reader.GetCropBox(1);
PdfContentByte cb = writer.DirectContent;
document.NewPage();
PdfImportedPage page = writer.GetImportedPage(reader,
pageNumber);
cb.AddTemplate(page, 0, 0);
document.Close();
This will copy first page to new document. I want to add text and images on new document. how to do that?
Many people will stop reading your question after your first sentence:
I want to Edit existing PDF
If you read the intro of chapter 6 of my book, you'll understand that the word Edit is not the right word to use.
I did read on, and that I saw that you were using Document and PdfWriter to stamp new content on an existing PDF. If you do the effort of reading chapter 6 of my book, you'll understand that this is wrong. You should use PdfStamper instead.
This is one of the examples provided online:
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();
}
You can find these examples on the following URLs:
http://itextpdf.com/sandbox/stamper
http://itextpdf.com/book/chapter.php?id=6
If you need the examples from chapter 6 ported to C#, please visit this URL: http://tinyurl.com/itextsharpIIA2C06
Update
Does PdfStamper support:
font embedding: yes, when done correctly, fonts are embedded,
font size: yes, that's obvious,
font family: you provide the font program, the font program knows the font family,
alignments: for single lines: use showTextAligned(); for text blocks use ColumnText (caveat: read about the difference between text mode and composite mode)
rotation: for single lines, this is only a matter of providing a rotation angle; for text blocks, create a Form XObject and add this object using a rotation,
...

Categories

Resources