I try to fill a PDF form with C#. But somehow it does not work. The problem: the fields object (in the line: fields.SetField("Name", "Peter");) seems to be null.
Here is my code:
public static void FillForm()
{
String pdfTemplate = #"c:\Users\Hagen\Desktop\formular.pdf";
String newFile = #"c:\Users\Hagen\Desktop\formular_fertig.pdf";
PdfReader pdfReader = new PdfReader(pdfTemplate);
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(newFile, FileMode.Create));
AcroFields fields = pdfStamper.AcroFields;
fields.SetField("Name", "Peter");
pdfStamper.Close();
}
I remember having a similar problem when I first tried to fill in form fields. The line you have that initializes the pdfStamper;
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(newFile, FileMode.Create));
Try adding ReadWrite permissions to the stamper object like so.
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(newFile, FileMode.Create, FileAccess.ReadWrite));
That MIGHT be your problem. I don't recall exactly how I fixed this problem myself, but that is what jumps out to me initially. It may very well be trying to write in the field value, but the stamper doesn't have the FileAccess it requires to accomplish this.
Hope this helps
Related
Here is my chunk of code. It compiles fine and when I fire off the event I get the email, but I then get this error
Email attachment ERROR on Adobe while opening(Acrobat could not open 'Att00002.pdf' because it is either not a supported file type or because the file has been damaged(for example, it was sent as an email attachment and wasnt correctly decoded.)
string agentName = "My Name";
MemoryStream _output = new MemoryStream();
PdfReader reader = new PdfReader("/pdf/Agent/Specialist_Certificate.pdf");
using (PdfStamper stamper = new PdfStamper(reader, _output))
{
AcroFields fields = stamper.AcroFields;
// set form fields
fields.SetField("FIELD_AGENT_NAME", agentName);
fields.SetField("FIELD_DATE", AvalonDate);
// flatten form fields and close document
stamper.FormFlattening = true;
SendEmail(_output);
DownloadAsPDF(_output);
stamper.Close();
}
private void SendEmail(MemoryStream ms)
{
Attachment attach = new Attachment(ms, new System.Net.Mime.ContentType("application/pdf"));
EmailHelper.SendEMail("myemail#myemail.com", "mjones#globusfamily.com", null, "", "Avalon Cert", "Hope this works", EmailHelper.EmailFormat.Html,attach);
}
EDITED *************************************
using (MemoryStream _output = new MemoryStream())
{
using (PdfStamper stamper = new PdfStamper(reader, _output))
{
AcroFields fields = stamper.AcroFields;
// set form fields
fields.SetField("FIELD_AGENT_NAME", agentName);
fields.SetField("FIELD_DATE", AvalonDate);
// flatten form fields and close document
stamper.FormFlattening = true;
}
SendEmail(_output);
}
You're calling stamper.close() inside the using (PdfStamper stamper = new PdfStamper(reader, _output)). The using will automatically close the stamper upon exiting it in addition to your manual close(), so technically the stamper is trying to be closed twice. Because of this it is also trying to close the MemoryStream more than once. That's where the exception is coming from.
I would use the technique located in the answer here for your MemoryStream and PdfStamper (modified and taken from: Getting PdfStamper to work with MemoryStreams (c#, itextsharp)):
using (MemoryStream _output = new MemoryStream()) {
using (PdfStamper stamper = new PdfStamper(reader, _output)) {
// do stuff
}
}
Using itextsharp v5.5.5.0 in VS2010
Setting the stamper FormFlattening = true no filed data is written to the output pdf. If set false the data is all present & correct but still editable (which I don't want)
PdfReader pdfTemplate = new PdfReader("..\\..\\pdf\\BFC-Template.pdf");
FileStream fileOutputStream = new FileStream("..\\..\\pdf\\BFC.pdf", FileMode.Create);
PdfStamper stamper = new PdfStamper(pdfTemplate, fileOutputStream);
stamper.AcroFields.SetField("FitID", "1234");
stamper.AcroFields.SetField("FitBy", "Fred Flintstone");
stamper.AcroFields.SetField("FitDate", "03/11/2015");
stamper.AcroFields.SetField("FitLocation", "Bedrock");
stamper.FormFlattening = true;
stamper.Close();
pdfTemplate.Close();
fileOutputStream.Close();
Try adding :
stamper.AcroFields.GenerateAppearances = true;
EDIT:
If your form is a Dynamic Form. you might need to change
stamper.AcroFields.SetField("FitID", "1234");
to:
stamper.AcroFields.Xfa.DatasetsSom.Name2Node["FitID"].InnerText = "1234"
It shouldn't matter, but you could try instantiating a AcroFields object from the pdfStamper field.
PdfStamper stamper = new PdfStamper(pdfTemplate, fileOutputStream);
AcroFields pdfFields = pdfStamper.AcroFields;
Then you can just set each field using pdfFields:
pdfFields.SetField("FitID", "1234");
pdfFields.SetField("FitBy", "Fred Flintstone");
pdfFields.SetField("FitDate", "03/11/2015");
pdfFields.SetField("FitLocation", "Bedrock");
stamper.FormFlattening = true;
stamper.Close();
I have this exact setup and it works for me.
I need to set the zoom level 75% to pdf file using iTextSharp. I am using following code to set the zoom level.
PdfReader reader = new PdfReader("input.pdf".ToString());
iTextSharp.text.Document doc = new iTextSharp.text.Document(reader.GetPageSize(1));
doc.OpenDocument();
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream("Zoom.pdf", FileMode.Create));
PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 0.75f);
doc.Open();
PdfAction action = PdfAction.GotoLocalPage(1, pdfDest, writer);
writer.SetOpenAction(action);
doc.Close();
But I am getting the error "the page 1 was request but the document has only 0 pages" in the doc.Close();
You need to use PdfStamper (as indicated by mkl) instead of PdfWriter (as made clear by Chris Haas). Please take a look at the AddOpenAction example:
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, reader.getPageSize(1).getHeight(), 0.75f);
PdfAction action = PdfAction.gotoLocalPage(1, pdfDest, stamper.getWriter());
stamper.getWriter().setOpenAction(action);
stamper.close();
reader.close();
}
The result is a PDF that opens with a zoom factor of 75%.
I'm struggling to insert images on a multi-page PDF.
To create several pages I'm using PdfConcatenate, and it works. I get to add pages of my template perfectly. The problem starts when I try to add images. It just doesn't load them.
Here's the code that works to add images:
string pdfTemplate = #"Tools\template.pdf";
string targetPdfPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), fileName + ".pdf");
FileStream output = new FileStream(targetPdfPath, FileMode.Create);
PdfConcatenate pdfConcatenate = new PdfConcatenate(output);
PdfReader pdfReader = new PdfReader(pdfTemplate);
MemoryStream memoryStream = getMemoryStream(output);
PdfStamper pdfStamper = new PdfStamper(pdfReader, output);
int cardIndex = 1;
foreach (Registry reg in registries)
{
setFields(reg, pdfStamper, cardIndex);
if (cardIndex == 4)
{
pdfConcatenate.AddPages(pdfReader);
pdfReader = new PdfReader(pdfTemplate);
pdfStamper = new PdfStamper(pdfReader, output);
cardIndex = 1;
}
else
{
cardIndex++;
}
}
//if (cardIndex != 1)
// pdfConcatenate.AddPages(pdfReader);
//make the form no longer editable
pdfStamper.FormFlattening = true;
pdfStamper.Close();
pdfReader.Close();
//pdfConcatenate.Close();
If use MemoryStream for PdfStamper and uncomment these lines:
//if (cardIndex != 1)
// pdfConcatenate.AddPages(pdfReader);
//pdfConcatenate.Close();
I get it to add pages, but without images.
Any idea of what is wrong?
SOLUTION: (Thanks to #mkl)
string pdfTemplate = #"Tools\template.pdf";
string targetPdfPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), fileName + ".pdf");
FileStream output = new FileStream(targetPdfPath, FileMode.Create);
PdfConcatenate pdfConcatenate = new PdfConcatenate(output);
PdfReader pdfReader = new PdfReader(pdfTemplate);
MemoryStream memoryStream = new MemoryStream();
PdfStamper pdfStamper = new PdfStamper(pdfReader, memoryStream);
int cardIndex = 1;
foreach (Registry reg in registries)
{
setFields(reg, pdfStamper, cardIndex);
if (cardIndex == 4)
{
pdfStamper.FormFlattening = true;
pdfStamper.Close();
PdfReader tempReader = new PdfReader(memoryStream.ToArray());
pdfConcatenate.AddPages(tempReader);
memoryStream = new MemoryStream();
pdfReader = new PdfReader(pdfTemplate);
pdfStamper = new PdfStamper(pdfReader, memoryStream);
cardIndex = 1;
}
else
{
cardIndex++;
}
}
if (cardIndex != 1)
{
pdfStamper.FormFlattening = true;
pdfStamper.Close();
PdfReader tempReader = new PdfReader(memoryStream.ToArray());
pdfConcatenate.AddPages(tempReader);
tempReader.Close();
}
pdfStamper.Close();
pdfReader.Close();
pdfConcatenate.Close();
The problem most likely is some misconception on how PdfStamperworks. You seem to think it somehow manipulates the data in the PdfReader it stamps, and also pages exported from that reader beforehand. This is not the case, a PdfStamper generates a new PDF file (in its output stream) based on the data in the reader but the contents of the reader itself are not updated to also reflect all the changes (the PdfReader object may be touched in the process, though, and not be reusable afterwards). So...
As already mentioned in the comment, you have the PdfConcatenate and an unknown number of PdfStamper instances all writing the same `FileStream' output. As each of these objects creates an independant PDF, you are lucky if one of then wins because then you'll get at least a proper PDF as output. Otherwise you either get some exception or garbage consisting of multiple intermingled PDFs. Thus, make only PdfConcatenate target your output file.
If your actual intent is to repeatedly fill the template fields with the content of 4 cards each time and combine the results, you should not add the pages from the PdfReader of the template to the PdfConcatenate --- the pages in that reader are not filled in! --- but instead have the PdfStamper output to a MemoryStream, fill its fields, flatten its form, close it, open its output in a new PdfReader, and add all the pages in that reader to the PdfConcatenate.
I don't dare to put that into code as I'm predominantly using Java and writing down untested C# code most likely would include multiple errors... ;)
PS: Currently you count on all the PdfReader instances you open to be implicitly closed somewhere. While that is true currently, recent check-ins in the iText SVN repository seem to indicate that these implicit close calls are removed from the code. Thus, please also start explicitly closing PdfReader instances you dont't use anymore. Otherwise you will soon have to deal with memory leaks due to readers closing much too late..
I want to clone a pdf, and make slight changes to the document at some point during or after copying.
I managed to do that with the pages but I am trying to copy also all metadata, form fields, acrofields etc.
How will I be able to do that using iTextSharp ?
Document document = new Document();
FileStream fs = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None)
PdfCopy copy = new PdfCopy(document, fs);
document.Open();
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfImportedPage importedPage = copy.GetImportedPage(reader, i);
copy.AddPage(importedPage);
}
copy.Outlines = SimpleBookmark.GetBookmark(reader);
fs.Flush();
PdfCopyFields copyf = new PdfCopyFields(fs);
You cannot make identical-byte copies with iTextSharp. You can make identical copies with System.IO.File.Copy.
You are then free to open it with iTextSharp to make further adjustments to the copy.
You use a PdfCopy based solution.
For your task, though, i.e. to take a single PDF and apply some changes to it, the appropriate solution is PdfStamper based. That would look like this:
PdfReader reader = ...;
[...apply changes using PdfReader methods...]
FileStream fs = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None)
PdfStamper stamper = new PdfStamper(reader, fs);
[...apply changes using PdfStamper methods...]
stamper.Close();