Problem when filling out a PDF and printing the PDF - vb.net

I use my application to fill and print out forms.
When the form is printed out all the text except the name of the customer is stretch black...
I have tried to print the saved PDF and the same result is happening.
When i open the filled out pdf and change the text, the file is printed out correctly..
The code i'm using to fill out the PDF and printing it is under... Is there something that i can change in my code so this dont happens?
Private Sub btnPrint_Click(sender As Object, e As EventArgs) Handles btnPrint.Click
Me.xmltopdf()
Me.Print()
End Sub
Private Sub xmltopdf()
Dim pdfTemp As String = My.Settings.SavePDFT ' ---> It's the original pdf form you want to fill
Dim newFile As String = My.Settings.SavePDFS & Me.TextBox1.Text & ".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("Field_1", TextBox1.Text)
pdfFormFields.SetField("Field_2", TextBox2.Text)
' There is more fields.. just removed them this.
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
' Print PDF
Private Sub Print()
' Wait a bit so the PDF file is created before printing.
Threading.Thread.Sleep(2500)
Dim psi As New ProcessStartInfo
psi.UseShellExecute = True
psi.Verb = "print"
psi.WindowStyle = ProcessWindowStyle.Hidden
'psi.Arguments = PrintDialog1.PrinterSettings.PrinterName.ToString()
psi.FileName = My.Settings.SavePDFS & Me.Ordre_NummerTextBox.Text & ".PDF" ' Here specify a document to be printed
Process.Start(psi)
End Sub
This is the printet out PDF.

I made a new PDF File and have had no problems with it sinse.
The old PDF file was 25.8 MB large and the new one is only 140 kB.
Also i remember that the Old file is copied and change several times in the past.

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.

How to create .key file with specific text

I've been trying to make a program that is able to create a file with a .key extension, which contains a 5 line text.
It is fundamental to have 5 lines, otherwise it won't work.
I use
Dim filepath As String = TextBox1.Text + "\\rarreg.key"
Dim rarreg As New IO.StreamWriter(filepath, True)
rarreg.Write(String.Join(Environment.NewLine, hiddenTxt))
The hiddenTxt contains all the text needed and it's multilined.
However, when I click on the button to call this functions, it succesfully creates the file, but it comes empty.
Try this
' Add any initialization after the InitializeComponent() call.
Dim filepath As String = ""
Dim dialog As New SaveFileDialog
dialog.DefaultExt = "key"
dialog.FileName = "rarreg.key"
dialog.InitialDirectory = "c:\temp"
Dim results As DialogResult = dialog.ShowDialog()
If results <> Windows.Forms.DialogResult.Cancel Then
filepath = dialog.FileName
End If​

Printing an external PDF document in VB.net

I know this question has been asked before, but my situation is a bit wonky.
Basically, I'm trying to print a PDF file that I've generated using a previous Windows Form. I can find the file no problem, and I used the following code which I found off MSDN's help forums:
Dim p As New System.Diagnostics.ProcessStartInfo()
p.Verb = "print"
p.WindowStyle = ProcessWindowStyle.Hidden
p.FileName = "C:\534679.pdf" 'This is the file name
p.UseShellExecute = True
System.Diagnostics.Process.Start(p)
So far so good, but everytime I press the button to run this code, it keeps asking me to save it as a PDF file instead, as shown below:
I've also tried adding a PrintDialog to the Windows Form, getting it to pop up, and I can select the printer I want to use from there, but even after selecting the printer it still asks me to print to PDF Document instead.
What am I doing wrong?
To print massive PDF documents with VB.Net you can use LVBPrint and run it via command line:
http://www.lvbprint.de/html/gsbatchprint1.html
For Example:
C:\temp\gsbatchprint64\gsbatchprintc.exe -P \\server\printer -N A3 -O Port -F C:\temp\gsbatchprint64\Test*.pdf -I Tray3
I use the following function in my application:
' print a pdf with lvbrint
Private Function UseLvbPrint(ByVal oPrinter As tb_Printer, fileName As String, portrait As Boolean, sTray As String) As String
Dim lvbArguments As String
Dim lvbProcessInfo As ProcessStartInfo
Dim lvbProcess As Process
Try
Dim sPrinterName As String
If portrait Then
lvbArguments = String.Format(" -P ""{0}"" -O Port -N A4 -F ""{1}"" -I ""{2}"" ", sPrinterName, fileName, sTray)
Else
lvbArguments = String.Format(" -P ""{0}"" -O Land -N A4 -F ""{1}"" -I ""{2}"" ", sPrinterName, fileName, sTray)
End If
lvbProcessInfo = New ProcessStartInfo()
lvbProcessInfo.WindowStyle = ProcessWindowStyle.Hidden
' location of gsbatchprintc.exe
lvbProcessInfo.FileName = LvbLocation
lvbProcessInfo.Arguments = lvbArguments
lvbProcessInfo.UseShellExecute = False
lvbProcessInfo.RedirectStandardOutput = True
lvbProcessInfo.RedirectStandardError = True
lvbProcessInfo.CreateNoWindow = False
lvbProcess = Process.Start(lvbProcessInfo)
'
' Read in all the text from the process with the StreamReader.
'
Using reader As StreamReader = lvbProcess.StandardOutput
Dim result As String = reader.ReadToEnd()
WriteLog(result)
End Using
Using readerErr As StreamReader = lvbProcess.StandardError
Dim resultErr As String = readerErr.ReadToEnd()
If resultErr.Trim() > "" Then
WriteLog(resultErr)
lvbProcess.Close()
Return resultErr
End If
End Using
If lvbProcess.HasExited = False Then
lvbProcess.WaitForExit(3000)
End If
lvbProcess.Close()
Return ""
Catch ex As Exception
Return ex.Message
End Try
End Function
I discourage on using AcrRd32.exe as it doesn't work with massive printings.
First, to be able to select a Printer, you'll have to use a PrintDialog and PrintDocument to send graphics to print to the selected printer.
Imports System.Drawing.Printing
Private WithEvents p_Document As PrintDocument = Nothing
Private Sub SelectPrinterThenPrint()
Dim PrintersDialog As New PrintDialog()
If PrintersDialog.ShowDialog(Me) = System.Windows.Forms.DialogResult.OK Then
Try
p_Document = New PrintDocument()
PrintersDialog.Document = p_Document
AddHandler p_Document.PrintPage, AddressOf HandleOnPrintPage
Catch CurrentException As Exception
End Try
End If
End Sub
Private Sub HandleOnPrintPage(ByVal sender As Object, ByVal e As PrintPageEventArgs) Handles p_Document.PrintPage
Dim MorePagesPending As Boolean = False
'e.Graphics.Draw...(....)
'e.Graphics.DrawString(....)
' Draw everything...
If MorePagesPending Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
End Sub
That's what I'm doing since I usually have custom objects to print.
But to print PDF Files, you must understand that PDF means absolutely nothing to dotNet. Unlike common images like Bitmaps (.bmp) or Ping images (.png) the dotNet doesn't seem to have any inbuilt parser/decoder for reading, displaying and printing PDF files.
So you must use a third party application, thrid party library or your own custom PDF parser/layout generator in order to be able to send pages to print to your printer.
That's why you can't launch a hidden (not visible) process of Acrobat Reader with the command "print". You won't be able to select a printer but will direct to the default one instead !
You can however launch the Acrobat Reader process just to open the file, and do the printing manipulations (select a printer) inside Acrobat Reader (you're outside dotNet coding now)
A workaround for your may aslo to select another default printer by opening Acrobat Reader, and print one blank page on an actual working printer. This should deselect your FoxIt thing in favour of an actual printer..
This code will help you to print in a specific printer.
The sample print a file using a ProcessStartInfo and a specific printer you can change the printer to use in the process.
If the print process is not finished after 10 seconds we kill the print process.
'Declare a printerSettings
Dim defaultPrinterSetting As System.Drawing.Printing.PrinterSettings = Nothing
Private Sub cmdPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPrint.Click
Try
dim fileName As String = "C:\534679.pdf"
'Get de the default printer in the system
defaultPrinterSetting = DocumentPrinter.GetDefaultPrinterSetting
'uncomment if you want to change the default printer before print
'DocumentPrinter.ChangePrinterSettings(defaultPrinterSetting)
'print your file
If PrintFile(fileName, defaultPrinterSetting) then
msgbox ("your print file success message")
else
msgbox ("your print file failed message")
end if
Catch ex As Exception
mssbox(ex.Message.toString)
End Try
End Sub
Public NotInheritable Class DocumentPrinter
Shared Sub New()
End Sub
Public Shared Function PrintFile(ByVal fileName As String, printerSetting As System.Drawing.Printing.PrinterSettings) As Boolean
Dim printProcess As System.Diagnostics.Process = Nothing
Dim printed As Boolean = False
Try
If PrinterSetting IsNot Nothing Then
Dim startInfo As New ProcessStartInfo()
startInfo.Verb = "Print"
startInfo.Arguments = defaultPrinterSetting.PrinterName ' <----printer to use----
startInfo.FileName = fileName
startInfo.UseShellExecute = True
startInfo.CreateNoWindow = True
startInfo.WindowStyle = ProcessWindowStyle.Hidden
Using print As System.Diagnostics.Process = Process.Start(startInfo)
'Close the application after X milliseconds with WaitForExit(X)
print.WaitForExit(10000)
If print.HasExited = False Then
If print.CloseMainWindow() Then
printed = True
Else
printed = True
End If
Else
printed = True
End If
print.Close()
End Using
Else
Throw New Exception("Printers not found in the system...")
End If
Catch ex As Exception
Throw
End Try
Return printed
End Function
''' <summary>
''' Change the default printer using a print dialog Box
''' </summary>
''' <param name="defaultPrinterSetting"></param>
''' <remarks></remarks>
Public Shared Sub ChangePrinterSettings(ByRef defaultPrinterSetting As System.Drawing.Printing.PrinterSettings)
Dim printDialogBox As New PrintDialog
If printDialogBox.ShowDialog = Windows.Forms.DialogResult.OK Then
If printDialogBox.PrinterSettings.IsValid Then
defaultPrinterSetting = printDialogBox.PrinterSettings
End If
End If
End Sub
''' <summary>
''' Get the default printer settings in the system
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function GetDefaultPrinterSetting() As System.Drawing.Printing.PrinterSettings
Dim defaultPrinterSetting As System.Drawing.Printing.PrinterSettings = Nothing
For Each printer As String In System.Drawing.Printing.PrinterSettings.InstalledPrinters
defaultPrinterSetting = New System.Drawing.Printing.PrinterSettings
defaultPrinterSetting.PrinterName = printer
If defaultPrinterSetting.IsDefaultPrinter Then
Return defaultPrinterSetting
End If
Next
Return defaultPrinterSetting
End Function
End Class
I used this code to print my PDF files on VB NET:
Dim PrintPDF As New ProcessStartInfo
PrintPDF.UseShellExecute = True
PrintPDF.Verb = "print"
PrintPDF.WindowStyle = ProcessWindowStyle.Hidden
PrintPDF.FileName = dirName & fileName 'fileName is a string parameter
Process.Start(PrintPDF)
When you do this, process remains open with a adobe reader window that users have to close manually. I wanted to avoid user's interaction, just want them to get their documents. So, I added a few code lines to kill process:
Private Sub killProcess(ByVal processName As String)
Dim procesos As Process()
procesos = Process.GetProcessesByName(processName) 'I used "AcroRd32" as parameter
If procesos.Length > 0 Then
For i = procesos.Length - 1 To 0 Step -1
procesos(i).Kill()
Next
End If
End Sub
If you put the kill process method right after the print method you won't get your document printed (I guess this is because process is killed before it is sent to printer). So, between these 2 methods, I added this line:
Threading.Thread.Sleep(10000) ' 10000 is the milisecs after the next code line is executed
And with this my code worked as I wanted. Hope it helps you!

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