iTextSharp Form Field Not Displaying ampersands, &, with SetField - pdf

I'm having an issue with iTextSharp and a PDF form (form fields specifically) that I've spend nearly two days on that I am direly hoping someone has the answer to.
I have a PDF form that when I open it as a user I can enter ampersands, &, into form fields just fine. However, when I use iTextSharp to fill in a form field value using .SetField the ampersands disappear. I have tried using & (which actually causes all the text in the field to appear as blank), the unicode representation of &, not flattening the form, flattening the form, etc. all to no avail. I am not sure what the issue could be as I mentioned the form field can certainly accept commas and ampersands with it's default encoding.
Is there something i'm missing?
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'Using iText 4.1.2.0
GeneratePDF2()
End Sub
Private Sub GeneratePDF2()
''//The directory to output files to
Dim WorkingFolder = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim FormFileName = Path.Combine(WorkingFolder, "testfile.pdf")
Dim FinalFileName = Path.Combine(WorkingFolder, "Final.pdf")
''//The name of the form field that we are going to create
Dim TextFieldName = "form1[0].#subform[0].Table3[0].Row2[0].Line2_FullName_and_AddressofEmployer[0]"
Dim FieldValue As String = "Jonathan & Chris & Mark" ' Does Not Work
'Dim FieldValue As String = "Jonathan and Chris and Mark" ' Works
Dim Letter As RandomAccessFileOrArray
'Create a PDF reader object based on the PDF template
Dim PDFReader As PdfReader
'Dim BAOS1 As MemoryStream
Dim Stamper As PdfStamper
Dim BAOS As MemoryStream = New MemoryStream()
Dim Copy As PdfCopyFields = New PdfCopyFields(BAOS)
Dim FormFilePath As String = FormFileName
Letter = New RandomAccessFileOrArray(FormFilePath)
'Create a PDF reader object based on the PDF template
PDFReader = New PdfReader(Letter, Nothing)
Dim BAOS1 As MemoryStream = New MemoryStream()
Stamper = New PdfStamper(PDFReader, BAOS1)
Dim FormFields As AcroFields = Stamper.AcroFields
'Set field value
FormFields.SetField(TextFieldName, FieldValue)
'Rename field after setting value
Dim RenamedFormFieldName As String
RenamedFormFieldName = String.Concat(Guid.NewGuid().ToString, "_", Guid.NewGuid().ToString)
FormFields.RenameField(TextFieldName, RenamedFormFieldName)
' flatten the form to remove editting options, set it to false
' to leave the form open to subsequent manual edits
Stamper.FormFlattening = True
' close the pdf
Stamper.Close()
'This could be the correct location
Copy.AddDocument(New PdfReader(BAOS1.ToArray))
Copy.Writer.CloseStream = False
Copy.Close()
PDFReader = New PdfReader(BAOS.ToArray())
Stamper = New PdfStamper(PDFReader, New FileStream(FinalFileName, FileMode.Create))
Stamper.FormFlattening = True
Stamper.Close()
End Sub

I'm unable to reproduce your problem, I'm using version 5.1.1.0. Below is sample code that creates a PDF, adds a field to it and then sets the field's value to This & that. (Its in three steps because I don't know how to add a field during the initial PDF creation.) I also tried manually creating a PDF in Acrobat and I was able to set the field to an ampersand just fine, too. Are you creating the form field in iTextSharp or another program? Can you post that PDF somewhere so we can look at it?
Option Explicit On
Option Strict On
Imports iTextSharp.text
Imports iTextSharp.text.pdf
Imports System.IO
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
''//The directory to output files to
Dim WorkingFolder = My.Computer.FileSystem.SpecialDirectories.Desktop
''//This sample code creates a base PDF, then adds a text field to it and finally sets the field value.
''//These filenames represent those three actions
Dim BaseFileName = Path.Combine(WorkingFolder, "Base.pdf")
Dim FormFileName = Path.Combine(WorkingFolder, "Form.pdf")
Dim FinalFileName = Path.Combine(WorkingFolder, "Final.pdf")
''//The name of the form field that we are going to create
Dim TextFieldName = "Text1"
''//Create our base PDF
Using FS As New FileStream(BaseFileName, FileMode.Create, FileAccess.Write, FileShare.Read)
Using Doc As New Document(PageSize.LETTER)
Using W = PdfWriter.GetInstance(Doc, FS)
Doc.Open()
Doc.NewPage()
Doc.Add(New Paragraph("This is my form"))
Doc.Close()
End Using
End Using
End Using
''//Add our form field
Using FS As New FileStream(FormFileName, FileMode.Create, FileAccess.Write, FileShare.Read)
Dim R1 = New PdfReader(BaseFileName)
Using S As New PdfStamper(R1, FS)
Dim F As New TextField(S.Writer, New Rectangle(50, 50, 500, 100), TextFieldName)
S.AddAnnotation(F.GetTextField(), 1)
S.Close()
End Using
End Using
''//Set the field value to text with an ampersand
Using FS As New FileStream(FinalFileName, FileMode.Create, FileAccess.Write, FileShare.Read)
Dim R2 = New PdfReader(FormFileName)
Using S As New PdfStamper(R2, FS)
S.AcroFields.SetField(TextFieldName, "This & that")
S.Close()
End Using
End Using
Me.Close()
End Sub
End Class
EDIT
I just tried it with the PDF you sent and its working just fine for me. Below is the full code that I ran. Here's the PDF it made. Are you sure you're not doing something else to the PDF (I don't know what.) If you create a brand new Windows Applications and use the below code against 5.1.1.0 does it work for you?
Option Explicit On
Option Strict On
Imports iTextSharp.text
Imports iTextSharp.text.pdf
Imports System.IO
Imports System.Text
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
''//The directory to output files to
Dim WorkingFolder = My.Computer.FileSystem.SpecialDirectories.Desktop
Dim FormFileName = Path.Combine(WorkingFolder, "testfile.pdf")
Dim FinalFileName = Path.Combine(WorkingFolder, "Final.pdf")
''//The name of the form field that we are going to create
Dim TextFieldName = "form1[0].#subform[0].Table3[0].Row2[0].Line2_FullName_and_AddressofEmployer[0]"
''//Set the field value to text with an ampersand
Using FS As New FileStream(FinalFileName, FileMode.Create, FileAccess.Write, FileShare.Read)
Dim R2 = New PdfReader(FormFileName)
Using S As New PdfStamper(R2, FS)
S.AcroFields.SetField(TextFieldName, "Chris & Mark")
S.FormFlattening = True
S.Close()
End Using
End Using
Me.Close()
End Sub
End Class

Had a similar case where German umlauts entered by the user in the application were not showing in the PDF. Turned out to be a font issue.
Had to ship our own fonts with the application (Liberation package to get cross-platform Arial-style) and doing this (it's Java):
BaseFont baseFont = BaseFont.createFont(FONT_FILE, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
acroFields.setFieldProperty(fieldName, "textfont", baseFont, null);

Related

Export the entire interface to PDF

I created a simple program that contains Labels and TextBoxes. I added a Button to export the entire interface with Labels and Textboxes to PDF but I get this error message:
Unable to cast object of type 'System.Windows.Forms.Panel' to type
'iTextSharp.text.IElement'.,
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim pdfDoc As New Document()
Dim pdfWrite As PdfWriter = PdfWriter.GetInstance(pdfDoc, New FileStream("C:\Users\Win 10\Desktop\simple.pdf", FileMode.Create))
pdfDoc.open()
pdfDoc.Add(Panel1)
pdfDoc.Add(Panel2)
pdfDoc.Add(TextBox1)
pdfDoc.Add(TextBox2)
pdfDoc.Close()
End Sub
You will need to convert the controls to Bitmap images, then drop them into the PDF.
I wrote this function that will take WinForms controls, convert them to Bitmap and then into iTextSharp.text.Image formats that can then be placed inside of a PDF.
Function ControlToPDFImage(ControlToConvert As Windows.Forms.Control)
Dim Bmp As Bitmap = New Bitmap(ControlToConvert.Width, ControlToConvert.Height)
ControlToConvert.DrawToBitmap(Bmp, New Drawing.Rectangle(0, 0, Panel1.Width, Panel1.Height))
Dim PDFImg As Image = iTextSharp.text.Image.GetInstance(Bmp, System.Drawing.Imaging.ImageFormat.Png)
Return PDFImg
End Function
So if you change your code to this, it should work:
pdfDoc.Add(ControlToPDFImage(Panel1))
pdfDoc.Add(ControlToPDFImage(Panel2))
pdfDoc.Add(ControlToPDFImage(TextBox1))
pdfDoc.Add(ControlToPDFImage(TextBox2))

Import CSV file to database using VB

I need to import the information from a CSV txt file to a database using the DataGridView in my form. The application should allow the user to open a .txt file and then update the DataGridView table in my form. I am able to get the file, but am unable to update the grid using the file. I can update textboxes, but cannot figure out how to update the grid. Can anyone help me out with this?
Imports Microsoft.VisualBasic.FileIO
Imports System.IO
Public Class Form1
Private fileToOpen As String 'the file to be opened and read
Private responseFileDialog As DialogResult 'response from OpenFileDialog
Private myStreamReader As StreamReader 'the reader object to get contents of file
Private myStreamWriter As StreamWriter 'the writer object to save contents of textbox
Private myTextFieldParser As TextFieldParser ' To parse text to searched.
Dim myDataAdapter As OleDb.OleDbDataAdapter
Dim myString() As String
Dim myRow As DataRow
Private Sub PeopleBindingNavigatorSaveItem_Click(sender As Object, e As EventArgs) Handles PeopleBindingNavigatorSaveItem.Click
Me.Validate()
Me.PeopleBindingSource.EndEdit()
Me.TableAdapterManager.UpdateAll(Me.MyContactsDataSet)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'MyContactsDataSet.People' table. You can move, or remove it, as needed.
Me.PeopleTableAdapter.Fill(Me.MyContactsDataSet.People)
End Sub
Private Sub OpenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OpenToolStripMenuItem.Click
Dim fileContentString As String 'contents of the file
Dim update As New OleDb.OleDbCommandBuilder(myDataAdapter)
'Dim myRow As DataRow
'set the properties of the OpenFileDialog object
OpenFileDialog1.InitialDirectory = My.Computer.FileSystem.CurrentDirectory
OpenFileDialog1.Title = "Select File to View..."
OpenFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"
'responseFileDialog contains holds the response of the user (which button they selected)
responseFileDialog = OpenFileDialog1.ShowDialog()
'check to see if the user select OKAY, if not they selected CANCEL so don't open anything
If (responseFileDialog <> System.Windows.Forms.DialogResult.Cancel) Then
'make sure there isn't a file already open, if there is then close it
If (myStreamReader IsNot Nothing) Then
myStreamReader.Close()
'TextBoxFileOutput.Clear()
End If
'open the file and read its text and display in the textbox
fileToOpen = OpenFileDialog1.FileName
myStreamReader = New StreamReader(OpenFileDialog1.FileName)
initTextFieldParser()
'loop through the file reading its text and adding it to the textbox on the form
Do Until myStreamReader.Peek = -1
fileContentString = myStreamReader.ReadLine()
'Try
' myTextFieldParser = New TextFieldParser(fileToOpen)
' myTextFieldParser.TextFieldType = FieldType.Delimited
' myTextFieldParser.SetDelimiters(",")
'Catch ex As Exception
' MessageBox.Show("Cannot Open File to Be Read!")
'End Try
myTextFieldParser.TextFieldType = FieldType.Delimited
myString = TextFieldParser.NewLine()
myRow.Item("FirstName") = myString(1)
MyContactsDataSet.Tables("People").Rows.Add(myRow)
PeopleTableAdapter.Update(MyContactsDataSet)
'TextBoxFileOutput.AppendText(fileContentString)
'TextBoxFileOutput.AppendText(Environment.NewLine)
Loop
'close the StreamReader now that we are done with it
myStreamReader.Close()
'SaveToolStripMenuItem.Enabled = True
End If
End Sub
Private Sub initTextFieldParser()
'Close myTextFieldParser in case the user is surfing through the records and then
'decides to search for a particular last name --> Basically start searching from beginning of the file
If (myTextFieldParser IsNot Nothing) Then
myTextFieldParser.Close()
End If
Try
myTextFieldParser = New TextFieldParser(fileToOpen)
myTextFieldParser.TextFieldType = FieldType.Delimited
myTextFieldParser.SetDelimiters(",")
Catch ex As Exception
MessageBox.Show("Cannot Open File to Be Read!")
End Try
End Sub
End Class
updating gridview with your file content
Import System.IO as we gonna need StreamReader
Using reader As New StreamReader("filepath")
DataGridView1.Columns.Add("col1",reader.ReadToEnd())
End Using
check this out!

Update one form based on selections from another form

I apologise if the title is a bit vague, i've only been on here a day.
So my problem is I have a menu form in which I input the options from the comboboxes. And then I go to the next form which shows the relevant imported text file info.
However when I click the 'back' button to return to the menu and input different information in the comboboxes, it doesn't take me to the correct text file info, it just shows the info from the previous selection.
here is the student menu pic
here is the text file form
below is the code for the student menu next button:
If OptionBox.Text = "Introduction" Then
Introduction.Show()
Else
If OptionBox.Text = "Explanation" Then
Explanation.Show()
End If
End If
End Sub
below is the code for the text file form load page and the back button
Private Sub Introduction_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Student_Menu.Hide()
Dim font As New System.Drawing.Font("Calibri", 11)
If Student_Menu.TopicSelect.Text = "Computer Systems" Then
Dim strFile As String = "C:\Users\Sales\Documents\Visual Studio 2010\Projects\gcsecomputingtask\textfiles\Introduction\ComputerSystems.txt"
Dim sr As New IO.StreamReader(strFile)
IntroductionLabel.Text = sr.ReadToEnd()
sr.Close()
Else
If Student_Menu.TopicSelect.Text = "Hardware" Then
Dim strFile As String = "C:\Users\Sales\Documents\Visual Studio 2010\Projects\gcsecomputingtask\textfiles\Introduction\Hardware.txt"
Dim sr As New IO.StreamReader(strFile)
IntroductionLabel.Text = sr.ReadToEnd()
sr.Close()
Else
If Student_Menu.TopicSelect.Text = "Software" Then
Dim strFile As String = "C:\Users\Sales\Documents\Visual Studio 2010\Projects\gcsecomputingtask\textfiles\Introduction\Software.txt"
Dim sr As New IO.StreamReader(strFile)
IntroductionLabel.Text = sr.ReadToEnd()
Else
If Student_Menu.TopicSelect.Text = "Representation of Data" Then
Dim strFile As String = "C:\Users\Sales\Documents\Visual Studio 2010\Projects\gcsecomputingtask\textfiles\Introduction\RepresentationOfData.txt"
Dim sr As New IO.StreamReader(strFile)
IntroductionLabel.Text = sr.ReadToEnd()
Else
If Student_Menu.TopicSelect.Text = "Databases" Then
Dim strFile As String = "C:\Users\Sales\Documents\Visual Studio 2010\Projects\gcsecomputingtask\textfiles\Introduction\Databases.txt"
Dim sr As New IO.StreamReader(strFile)
IntroductionLabel.Text = sr.ReadToEnd()
Else
If Student_Menu.TopicSelect.Text = "Communications & Networks" Then
Dim strFile As String = "C:\Users\Sales\Documents\Visual Studio 2010\Projects\gcsecomputingtask\textfiles\Introduction\Hardware.txt"
Dim sr As New IO.StreamReader(strFile)
IntroductionLabel.Text = sr.ReadToEnd()
End If
End If
End If
End If
End If
End If
IntroductionLabel.Font = font
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBack.Click
Me.Hide()
Student_Menu.Show()
Student_Menu.TopicSelect.ResetText()
Student_Menu.OptionBox.ResetText()
End Sub
what do i need to do in order to update this information so that the program doesn't skip going through the form again.
There is a lot of repeated code there. Here is a way to reduce it (see DRY) and expose a method to change the topic. In a Module:
Public Enum Topics
ComputerSystems
Hardware
Software
Data
Database
Networks
End Enum
Then in the form that shows the text:
Friend Sub DisplayTopic(topic As Topics)
Dim text As String
Dim filname As String = ""
Select Case topic
Case Topics.ComputerSystems
filname = "ComputerSystems.txt"
Case Topics.Database
filname = "Databases.txt"
'... etc
End Select
' attach path
filname = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"gcsecomputingtask", filname)
text = File.ReadAllText(filname)
IntroductionLabel.Text = text
End Sub
By the way, VB does has an ElseIf which can avoid the "arrow" anti pattern you can see in your code. At the very least, the excessive indentation is annoying.
If topic = Topics.ComputerSystems Then
'...
ElseIf topic = Topics.Software Then
'...
End If
Show that form normally using an instance of the form class:
Public Class MenuForm ' a form is just a class
' declare an object variable to use
Private info As Form2 ' whatever its name is (Explanation???)
....
Private Sub MenuForm_Load(...)
' create an instance to be used later:
info = New Form2
Then invoke the method to tell it which topic to display. Displaying topic info is a separate method from loading a form first because the form load event happens only once. A specialized method to do what we want makes more sense since they really have nothing to do with one another, and makes it easier to see how the code works:
info.DisplayTopic(Topics.ComputerSystems)
info.Show
This way, you dont have one form fiddling with the controls on another, but still have a clear way of communicating which topic to display.
Note that the location of the topics file(s) is a bit different. You'd want a "gcsecomputingtask" folder in MyDocuments for the files. The VS project folder is not a good place for it, the folder location could change depending on which machine you are running on (yours or computer lab etc). They could also be stored as a resource to skip that part too.

NullReferenceException was caught

Please I'm using vb.net 2008 and Sql 2008 and I have to save a picture in to the database. When I run the code initially it was saving and later i realized it was giving me NullReferenceException was caught. Object reference not set to an instance of an object. I' just confused!
The code below
Imports System.Data.SqlClient
Imports System.IO
Private Sub btnImage1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImage1.Click
'Code to load picture
Dim OpenFileDialog1 As New OpenFileDialog
OpenFileDialog1.Filter = "JPG|*.jpg|BITMAP|*.bmp|GIF|*.gif"
OpenFileDialog1.ShowDialog()
If OpenFileDialog1.FileName <> "" AndAlso IO.File.Exists(OpenFileDialog1.FileName) Then
Dim Extention As String = New IO.FileInfo(OpenFileDialog1.FileName).Extension
Select Case Extention.ToLower
Case Is = ".jpg", Is = ".bmp", Is = ".gif"
Case Else
MsgBox("Only JPG, BMP and GIF files are allowed. Thank you")
Exit Sub
End Select
Me.Pic1.Image = Image.FromFile(OpenFileDialog1.FileName)
End If
End Sub
'Code to save picture (I stepped into the code and the frmAllottee.Pic1 is there)
Public Sub Save_Picture()
Dim sql_command As SqlCommand
Dim mStream As MemoryStream = New MemoryStream()
'Dim mstream As New MemoryStream()
frmAllottee.Pic1.BackgroundImage.Save(mstream, frmAllottee.Pic1.BackgroundImage.RawFormat) - This line gives the error
Dim arrImage() As Byte = mstream.GetBuffer()
mstream.Close()
Dim Sql As String = "Insert into Alloc(Pic) VALUES(#Pic)"
sql_command = New SqlClient.SqlCommand(Sql, Con)
sql_command.Connection.Open()
sql_command.Parameters.AddWithValue("#Pic1", arrImage)
sql_command.ExecuteNonQuery()
sql_command.Connection.Close()
End Sub
This would happen if frmAllottee.Pic1.BackgroundImage is null.
Image and BackgroundImage are not the same.
Me.Pic1.Image = Image.FromFile(OpenFileDialog1.FileName)
This line of code here doesnt correspond to this code :
frmAllottee.Pic1.BackgroundImage.Save(mstream, frmAllottee.Pic1.BackgroundImage.RawFormat)
You have inserted an Image in your Pic1 in the Image while you are saving it and you chose BackgroundImage instead of Image
Also
Dim Sql As String = "Insert into Alloc(Pic) VALUES(#Pic)"
sql_command = New SqlClient.SqlCommand(Sql, Con)
sql_command.Connection.Open()
sql_command.Parameters.AddWithValue("#Pic1", arrImage)
sql_command.ExecuteNonQuery()
sql_command.Connection.Close()
#Pic from inserting to database should be the same as your #Pic1 when addingwithvalue i.e. (both should be #Pic or whichever you like)
Ive tried it and it works

Printing an RTF file using Printdialog in VB.NET

I have this code:
Private printDocument1 As New PrintDocument()
Private stringToPrint As String
Private Sub ReadFile()
Dim docName As String = "print_doc.rtf"
Dim docPath As String = fsPathPrintDoc
printDocument1.DocumentName = docName
Dim stream As New FileStream(docPath + docName, FileMode.Open)
Try
Dim reader As New StreamReader(stream)
Try
stringToPrint = reader.ReadToEnd()
Finally
reader.Dispose()
End Try
Finally
stream.Dispose()
End Try
End Sub
and I do the printing using:
ReadFile()
printDocument1.Print()
I want to print a rtf file using a VB.NET printdialog.show(), because in want to choose specific printers for printing, but my above code i dont have any idea, how i can embed printdialog here.
This is required because i want to print that file using printers available on different systems using network. Now all these available printers are available for me in print dialog, what i want is to simply print a particular file in my drive using printdialog()
Also, I tried to find a possibility to print a file using printdialog and printdocument but unfortunately failed.
Edit:
I found http://msdn.microsoft.com/en-us/library/system.drawing.printing.printdocument.aspx but it does not includes printdialog
You assign your PrintDocument to the PrintDialogs Document Property, it will then add the selected printer to your Document. You then print the Document as normal.
PrintDialog1.AllowSomePages = True
PrintDialog1.ShowHelp = True
PrintDialog1.Document = printDocument1 'Assign your Document here
Dim result As DialogResult = PrintDialog1.ShowDialog()
If (result = DialogResult.OK) Then
printDocument1.Print()
End If