Acrofields Autofilled with iTextSharp in vb.net Not Visible Until Clicked - vb.net

I'm working on a vb.net app to fill preexisting pdf forms and I've run in to a frustrating problem. The code below puts the values into the given fields on the pdf form, but in order to see those values in Adobe Reader, the fields themselves have to be selected. I can't share the pdf itself, but from opening it in Acrobat, it seems like security/protection isn't the issue, though I do get a permissions error when I set FormFlattening to True.
Is there a step in the code below which I'm missing?
Imports System
Imports System.IO
Imports System.Xml
Imports iTextSharp
Imports iTextSharp.text
Imports iTextSharp.text.pdf
Imports iTextSharp.text.xml
Imports iTextSharp.pdfa
Imports System.Security
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim pdfTemp As String = "C:\ExampleTemplate.pdf"
Dim newFile As String = "C:\NewFile.Pdf"
Dim pdfReader As New PdfReader(pdfTemp)
Dim pdfStamper As New PdfStamper(pdfReader, New FileStream(newFile,_ FileMode.Create), "\6c", True)
Dim pdfFormFields As AcroFields = pdfStamper.AcroFields
pdfFormFields.SetField("Date", "03092014", "03092014")
pdfFormFields.SetField("Contract_No", "1234456", "1234456")
pdfFormFields.SetField("Buyer", "bar, foo", "bar, foo")
pdfFormFields.GenerateAppearances = True
pdfStamper.FormFlattening = True
pdfStamper.Close()
pdfReader.Close()
End Sub
End Class

So it's not 100% clear to me why this worked and my previous efforts didn't, but copying and pasting this code to initialize the PdfStamper
Dim pdfTemplate As String = "Path to fillable pdf"
Dim strFolder As String = "Path to destination Folder"
Dim newFile As String = strFolder & "Name of Completed Form"
Dim pdfReader As New PdfReader(pdfTemplate)
Dim pdfStamper As New PdfStamper(pdfReader, New FileStream(newFile, FileMode.Create))
Dim pdfFormFields As AcroFields = pdfStamper.AcroFields
`fields and values as in original question'
pdfStamper.FormFlattening = True
pdfStamper.Close()
from the tutorial here made the project work.
On a side note, it became clear to me that not all .pdf files with fillable fields are "forms", and that itextsharp requires that the file be a form. I realized this when, after applying the above code to two files successfully, the third failed, despite me knowing the names of the fields. To make it into a form, and thus recognizable to itextsharp, I opened it in acrobat and created a form. All the fields and their names were preserved so I saved it and it worked like a charm.

Related

What is the proper way to save an existing file to a user's computer using a SaveFileDialog?

I have a vb.net windows app that creates a PDF. After creation, I want to prompt the user where they want to save the file. The default save folder is different than the folder of the created PDF. I get the SaveDialog box to come up with the default folder and file name that I want. If I choose "Save", I get a message saying that the file does not exist and none of the code below the ShowDialog is executed (I'm sure that I'm doing that part wrong as well).
Dim saveFileDialog1 As New SaveFileDialog
saveFileDialog1.InitialDirectory = MyDocsFolder
saveFileDialog1.FileName = "Report.pdf"
saveFileDialog1.Title = "Save Report"
saveFileDialog1.CheckFileExists = True
saveFileDialog1.CheckPathExists = True
saveFileDialog1.DefaultExt = "pdf"
saveFileDialog1.Filter = "All files (*.*)|*.*|All files (*.*)|*.*"
saveFileDialog1.FilterIndex = 2
saveFileDialog1.RestoreDirectory = True
saveFileDialog1.ShowDialog()
If saveFileDialog1.ShowDialog = DialogResult.OK Then
If saveFileDialog1.FileName() <> "" Then
Dim newStream As FileStream = File.Open(newFile, FileMode.Open)
Dim pdfStream As New FileStream(saveFileDialog1.FileName, FileMode.Create)
newStream.CopyTo(fs, FileMode.Append)
newStream.Close()
fs.Close()
End If
End If
you can do it like this:
Imports Microsoft.WindowsAPICodePack.Dialogs
Public NotInheritable Class Form1
Private Sub ButtonSave_Click(sender As Object, e As EventArgs) Handles ButtonSave.Click
Dim Path As String
Using SFD1 As New CommonSaveFileDialog
SFD1.Title = "Where should the file be saved?"
SFD1.Filters.Add(New CommonFileDialogFilter("PDF", ".pdf"))
SFD1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
If SFD1.ShowDialog() = CommonFileDialogResult.Ok Then
Path = SFD1.FileName
Else
Return
End If
End Using
Dim dest As IO.FileInfo
Using fs As IO.FileStream = IO.File.Create(Path & ".pdf")
dest = My.Computer.FileSystem.GetFileInfo(fs.Name)
End Using
End Sub
End Class
Please note that I am using a FileDialog that I downloaded from Visual Studios' own Nuget Package Manager. See image. You don't have to do that, but I prefer this FileDialog because it offers more options than the one that is already included.
So the user enters the file name; thus the path results. In my code example, this creates a blank PDF. It cannot be opened like this yet.
So that something is written in the PDF, you can download itext7 (also via NuGet).
Then, you write Imports iText.Kernel.Pdf,
Imports iText.Kernel.Utils and in your sub Dim pdfwriter As New PdfWriter(dest) with ‘dest’ from above.
I am so blind and stupid...
saveFileDialog1.CheckFileExists = True
Sorry for wasting anyone's time.

PDF fill in not merging correctly

We are using an asp.net website with iTextSharp.dll version 5.5.13
We can merge multiple PDF files into one using a stream and it works perfectly. However, when we use a PDF that was created in a "fill-in" function the new PDF file does not correctly merge into the other documents. It merges without the filled in values. However, if I open the filled in PDF that it creates the filled in data displays and prints fine.
I have tried merging the new "filled in" PDF at a later time but it still displays the template file as though the filled in data was missing.
Below code fills in the data
Dim strFileName As String = Path.GetFileNameWithoutExtension(strSourceFile)
Dim strOutPath As String = HttpContext.Current.Server.MapPath("~/Apps/Lifetime/OfficeDocs/Export/")
newFile = strOutPath & strFileName & " " & strRONumber & ".pdf"
If Not File.Exists(newFile) Then
Dim pdfReader As PdfReader = New PdfReader(strSourceFile)
Using pdfStamper As PdfStamper = New PdfStamper(pdfReader, New FileStream(newFile, FileMode.Create))
Dim pdfFormFields As AcroFields = pdfStamper.AcroFields
pdfFormFields.SetField("CUSTOMER NAME", strCustomer)
pdfFormFields.SetField("YR MK MODEL", strVehicle)
pdfFormFields.SetField("RO#", strRONumber)
pdfStamper.FormFlattening = False
pdfStamper.Dispose()
End Using
End If
Then code below here merges multiple PDF files/paths sent to it
Public Shared Sub MergePDFs(ByVal files As List(Of String), ByVal filename As String)
'Gets a list of full path files and merges into one memory stream
'and outputs it to a browser response.
Dim MemStream As New System.IO.MemoryStream
Dim doc As New iTextSharp.text.Document
Dim reader As iTextSharp.text.pdf.PdfReader
Dim numberOfPages As Integer
Dim currentPageNumber As Integer
Dim writer As iTextSharp.text.pdf.PdfWriter = iTextSharp.text.pdf.PdfWriter.GetInstance(doc, MemStream)
doc.Open()
Dim cb As iTextSharp.text.pdf.PdfContentByte = writer.DirectContent
Dim page As iTextSharp.text.pdf.PdfImportedPage
Dim strError As String = ""
For Each strfile As String In files
reader = New iTextSharp.text.pdf.PdfReader(strfile)
numberOfPages = reader.NumberOfPages
currentPageNumber = 0
Do While (currentPageNumber < numberOfPages)
currentPageNumber += 1
doc.SetPageSize(reader.GetPageSizeWithRotation(currentPageNumber))
doc.NewPage()
page = writer.GetImportedPage(reader, currentPageNumber)
cb.AddTemplate(page, 0, 0)
Loop
Next
doc.Close()
doc.Dispose()
If MemStream Is Nothing Then
HttpContext.Current.Response.Write("No Data is available for output")
Else
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.ContentType = "application/pdf"
HttpContext.Current.Response.AppendHeader("Content-Disposition", "inline; filename=" + filename)
HttpContext.Current.Response.BinaryWrite(MemStream.ToArray)
HttpContext.Current.Response.OutputStream.Flush()
HttpContext.Current.Response.OutputStream.Close()
HttpContext.Current.Response.OutputStream.Dispose()
MemStream.Close()
MemStream.Dispose()
End If
End Sub
I expect the "filled in" PDF in the list of files to retain the filled in data but it does not. Even if I try to merge the filled in file later it still comes up missing the filled in data. If I print the filled in file it looks perfect.
PdfWriter.GetImportedPage only returns you a copy of the page contents. This does not include any annotations, in particular not the widget annotations of form fields on the page at hand.
To also copy the annotations of the source pages, use the iText PdfCopy class instead. This class is designed to copy pages including all annotations. Furthermore, it includes methods to copy all pages of a source document in one step.
You have to tell the PdfCopy object to merge fields, otherwise the document-wide form structure won't be built.
As an aside, your code creates many PdfReader objects but does not close them. That may increase your memory requirements substantially.
Thus:
Public Shared Sub MergePDFsImproved(ByVal files As List(Of String), ByVal filename As String)
Using mem As New MemoryStream()
Dim readers As New List(Of PdfReader)
Using doc As New Document
Dim copy As New PdfCopy(doc, mem)
copy.SetMergeFields()
doc.Open()
For Each strfile As String In files
Dim reader As New PdfReader(strfile)
copy.AddDocument(reader)
readers.Add(reader)
Next
End Using
For Each reader As PdfReader In readers
reader.Close()
Next
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.ContentType = "application/pdf"
HttpContext.Current.Response.AppendHeader("Content-Disposition", "inline; filename=" + filename)
HttpContext.Current.Response.BinaryWrite(mem.ToArray)
HttpContext.Current.Response.OutputStream.Flush()
HttpContext.Current.Response.OutputStream.Close()
HttpContext.Current.Response.OutputStream.Dispose()
End Using
End Sub
Actually I'm not sure whether it is a good idea to Close and Dispose the response output stream here, that shouldn't be the responsibility of a PDF merging method.
This is a related answer for the Java version of iText; you may want to read it for additional information. Unfortunately many links in that answer meanwhile are dead.

Filling out a PDF form with values from textbox.text and printing the PDF after the PDF is filled

I have search the web and have not found a solution to do this.
I have a VB.net form with a Dataset of costumers, and i want to take the contact information in the textbox.text and fill out a PDF form, and print it.
Itextsharp is mention every where to create a pdf, not to fill out one and print it, and i found a promising code, im not really familiar with vb.net at all, this is my first program.
This is the code i found that i think would work...
Imports System
Imports System.IO
Imports System.Xml
Imports iTextSharp
Imports iTextSharp.text
Imports iTextSharp.text.pdf
Imports iTextSharp.text.xml
Imports System.Security
Private Sub xmltopdf()
Dim pdfTemp As String = "C:\ExampleTemplate.pdf" ' ---> It's the original pdf form you want to fill
Dim newFile As String = "C:\NewFile.Pdf" ' ---> It will generate new pdf that you have filled from your program
' ------ READING -------
Dim pdfReader As New PdfReader(pdfTemp)
' ------ WRITING -------
' If you don’t specify version and append flag (last 2 params) in below line then you may receive “Extended Features” error when you open generated PDF
Dim pdfStamper As New PdfStamper(pdfReader, New FileStream(newFile, FileMode.Create), "\6c", True)
Dim pdfFormFields As AcroFields = pdfStamper.AcroFields
' ------ SET YOUR FORM FIELDS ------
pdfFormFields.SetField("Company", "Parth Dave & Co.")
pdfFormFields.SetField("SalesOrder", "1234456")
pdfFormFields.SetField("InstallAddress", "Lorimer Street")
pdfFormFields.SetField("Suburb", "Port Melbourne")
pdfFormFields.SetField("Post_Code", "3207")
pdfFormFields.SetField("ClientContact", "Parth")
pdfFormFields.SetField("ClientPhone", "0402020202")
pdfStamper.FormFlattening = False
' close the pdf
pdfStamper.Close()
' pdfReader.close() ---> DON"T EVER CLOSE READER IF YOU'RE GENERATING LOTS OF PDF FILES IN LOOP
End Sub
I get errors on the Imports and dont know what the import are..
I have added the itextsharp.dll so that should be ok..
If anyone could help me out or send me in the right direction it would be much appreciated.
Put the Imports outside of the class.

Cannot close PDFStamper after Setfield

The VB.Net code below works under v 5.3.4 but the .Close statement fails under v5.4.1 and v5.4.1. I can use the same code and switch .dlls to reproduce the problem.
Me.Text in the second line is a textbox containing the path to the file. The file was created with AcroBat 9.5 and it has two form fields named 'NAME' and 'PHONE'.
The itextsharp.dll from the core.zip is added as a reference to the project. At the form level: IMPORTS itextsharp.text and .text.pdf. Thanks!
Could someone verify this and report the bug? Or let me know what I'm doing wrong (besides using WinForms and VB.Net:)?
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
Dim newFile As String = Me.Text.Replace(".pdf", "_Out.pdf")
''//create w/overwrite copy of the template
Dim pdfReader As New PdfReader(pdfTemplate)
Dim pdfStamper As New PdfStamper(pdfReader, New FileStream(newFile, FileMode.Create))
pdfFormFields = pdfStamper.AcroFields
''//set form pdfFormFields ' field names are case sensitive
pdfFormFields.SetField("NAME", "Firstname Lastname")
pdfFormFields.SetField("PHONE", "805.555.1212")
''//report by reading values from completed PDF
Dim sTmp As String = "Completed: " + pdfFormFields.GetField("NAME") + " " + _
pdfFormFields.GetField("PHONE")
MessageBox.Show(sTmp, "Finished")
''//flatten the form to remove editting options, set it to false
''//to leave the form open to subsequent manual edits
pdfStamper.FormFlattening = False
''//close the pdf
pdfStamper.Close()
End Sub

Adding headers with iTextSharp in VB.NET

I'm wondering how can I put a header into my PDF file, cause I've tried the tutorials from here:
http://itextsharp.sourceforge.net/tutorial/ch04.html
And it has not worked.
I've done this:
Dim head As New HeaderFooter(New Phrase("This is page: "), False)
head.Border = Rectangle.NO_BORDER
document.Header = head
But VS2008 says that HeaderFooter is not defined (line 1), and Footer it's not a member of "iTextSharp.text.document" (line 3).
I've already included the imports at the beginning of my code and iIdon't have any other problems with the iTextsharps (I mean that it is working apart of the header problem):
Imports iTextSharp.text
Imports iTextSharp.text.pdf
Imports System.Data.SQLite
Imports System.IO
So please, can anyone explain to me how can i set a header for my pages?
Regards
The answer to this question depends on which version of the iTextSharp dll you are using.
If you are using a version lower than 5, this should work
Imports iTextSharp.text.pdf
Imports iTextSharp.text
Module Module1
Sub Main()
Dim pdfWrite As PdfWriter
Dim pdfDoc As New Document()
Dim pdfMemoryStream As New IO.FileStream("tryme.pdf", IO.FileMode.Create)
pdfWrite = PdfWriter.GetInstance(pdfDoc, pdfMemoryStream)
Dim pdfHeader As New HeaderFooter(New Phrase("Im at the head: "), False)
pdfHeader.Border = Rectangle.NO_BORDER
pdfDoc.Header = pdfHeader
pdfDoc.Open()
pdfDoc.Add(New Paragraph("Hello World"))
pdfDoc.NewPage()
pdfDoc.Add(New Paragraph("Hello World Again"))
pdfDoc.Close()
End Sub
End Module
Update
For version 5+ of iTextSharp the HeaderFooter property has been removed from iTextSharp. To add Headers/Footers now you must use PageEvents. The following code demonstrates how to do this (very simply!)
Imports iTextSharp.text.pdf
Imports iTextSharp.text
Imports System.IO
Module Module1
Sub Main()
Dim pdfDoc As New Document()
Dim pdfWrite As PdfWriter = PdfWriter.GetInstance(pdfDoc, New FileStream("tryme2.pdf", FileMode.Create))
Dim ev As New itsEvents
pdfWrite.PageEvent = ev
pdfDoc.Open()
pdfDoc.Add(New Paragraph("Hello World"))
pdfDoc.NewPage()
pdfDoc.Add(New Paragraph("Hello World Again"))
pdfDoc.Close()
End Sub
End Module
Public Class itsEvents
Inherits PdfPageEventHelper
Public Overrides Sub OnStartPage(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document)
Dim ch As New Chunk("This is my Stack Overflow Header on page " & writer.PageNumber)
document.Add(ch)
End Sub
End Class