Append created PDF page with existing PDF file with iTextSharp - asp.net

I'm currently in the process of creating (what I thought would have been) a really simple method to append two PDF files.
Firstly, my method creates a page that has all of the clients details on it as a digital signature. I had this working fine and saving to a single page PDF file.
However, I now want to append the terms & conditions that they're signing to the bottom of the PDF. The solution I'm coding in uses VB.NET, but you can provide the answer in C# if you prefer because I'm familiar with both. I just seriously cannot get my head around iTextSharps process.
Here is my code currently:
Public Sub CreateDocument() Handles btnCreate.ServerClick
Dim path As [String] = Server.MapPath("PDFs")
Dim document As New Document()
Dim writer As PdfWriter = PdfWriter.GetInstance(document, New FileStream(path + "/" + _AccountNo + "-RegAgreement.pdf", FileMode.Create))
'Removed chunk of code here, just defining content chunks and paragraphs
for the dynamically created page, left in the construction
part which you can see below'
'Construct digitally signed agreement page'
document.Open()
document.NewPage()
document.Add(pHeader)
table.SpacingBefore = 30.0F
table.SpacingAfter = 60.0F
document.Add(table)
pAgreement.SpacingAfter = 20.0F
document.Add(pAgreement)
document.Add(pSignedBy)
document.Add(imgSig)
document.Add(pFooter1)
document.Add(pFooter2)
document.Add(pFooter3)
writer.Close()
document.Close()
Now this is the bit I've added to the end of the above sub to append the PDF. As far as I'm aware, you need to use the PdfCopy to transfer the information from the PDF to a new Document object (In this case, doc). But then, I can't find a way to add these to the dynamically created PDF.
Is there perhaps a way to open it within the copier and then start copying from page 2?
Dim terms As New PdfReader(path + "/termsconditions.pdf")
Dim doc As New Document()
Dim copier As New PdfCopy(doc, New FileStream(path + "/" + _accountNo + "-RegAgreement2.pdf", FileMode.Create))
'Append Ts & Cs'
For i As Integer = 1 To terms.NumberOfPages
Dim importedPage As PdfImportedPage = copier.GetImportedPage(terms, i)
copier.AddPage(importedPage)
Next
terms.Close()
terms.Close()
End Sub
Every solution I've seen so far has used different methods like page stamps or memory streams, but none of them have worked or given me the result I need.
Any help is greatly appreciated!
UPDATE
Okay so after #mkl's suggestion, I have now brought the dynamically generated document back with a reader, however it's returning a null value suggesting that the .PDF is blank, but it isn't. (I have the file in my directory with all the content filled)
Dim copier As New PdfCopy(document, New FileStream(path + "/" + _distNo + "-RegAgreement2.pdf", FileMode.OpenOrCreate))
Dim reader As New PdfReader(path + "/" + _distNo + "-RegAgreement.pdf")
'retrieve dynamic document
Dim dynamicPage As PdfImportedPage = copier.GetImportedPage(reader, 1)
copier.AddPage(dynamicPage)
'Append Ts & Cs
For i As Integer = 1 To terms.NumberOfPages
Dim importedPage As PdfImportedPage = copier.GetImportedPage(terms, i)
copier.AddPage(importedPage)
Next
Is this because it's being done within the same subroutine?

Solved, big thanks to #mkl on this one.
The issues I was facing were because I wasn't creating a Document object for the copier to write to.
Dim doc As New Document()
Dim copier As New PdfCopy(doc, New FileStream(path + "/" + _distNo + "-RegAgreement.pdf", FileMode.Create))
'Open PDF created earlier in subroutine'
Dim reader As New PdfReader(path + "/" + _distNo + "-Signed.pdf")
doc.Open()
'Copy first (And only) page of dynamic PDF'
Dim dynamicPage As PdfImportedPage = copier.GetImportedPage(reader, 1)
copier.AddPage(dynamicPage)
'Append Ts & Cs'
For i As Integer = 1 To terms.NumberOfPages
Dim importedPage As PdfImportedPage = copier.GetImportedPage(terms, i)
copier.AddPage(importedPage)
Next
doc.Close()
terms.Close()
reader.Close()
copier.Close()
'For temporary purposes, delete local file'
'This will be done in output stream in end release'
File.Delete(path + "/" + _distNo + "-Signed.pdf")
Thanks for the help guys. Think I've got the basic procedures of this iTextSharp thing down now!

Related

Print SSRS Report from Code (asp.net)

I have found good information on how to automatically download a file to the client advertised as a solution of how to print using code
(https://forums.asp.net/t/1233841.aspx?How+do+I+print+from+Reporting+Services+AUTOMATICALLY+in+VB+Net+web+app+)
but what I need to do is have the code print the document without the user interacting.
From what I have found it appears this can not be done as one might casually think. ReportViewer for example does not have a 'print' method.
The only two solutions appears to be to use ProcessStart (which then means saving the file to the file system before printing which I dont want to do)
or maybe (will be researching this today) create a subscription using code and then delete it later.
You are not able to print a report directly from your asp.net page. The reason for this is security. If it allowed you to send a file through the network and onto the clients computer, and then search the computer for a printer, this could cause major security issues. The report viewer does have a print icon, but this disappears when you deploy the project and run the page remotely. I have faced the same issue in the past and found it best to just export the report to say PDF and allow the user to Download it. I have used the below code to accomplish this task in the past:
Private Sub CreatePDFMatrix(fileName As String)
' ReportViewer1.LocalReport.DataSources.Clear()
Dim adapter As New ReportDataSetTableAdapters.vwPrintTagsTableAdapter
Dim table As New ReportDataSet.vwPrintTagsDataTable
Dim month = MonthName(Date.Today.Month)
Dim year = Date.Today.Year
Dim p(1) As ReportParameter
Dim warnings() As Warning
Dim streamIds As String()
Dim mimeType As String = String.Empty
Dim encoding As String = String.Empty
Dim extension As String = String.Empty
Dim adpt2 As New ReportDataSetTableAdapters.vwPrintTagsTableAdapter
adapter.FillForMainReport(table, DropDownList1.SelectedValue, g_Company, g_Division)
Me.ReportViewer1.LocalReport.DataSources.Add(New ReportDataSource("DataSet1", CType(table, DataTable))) 'Add(New ReportDataSource("ReportingData", CType(table, DataTable)))
Me.ReportViewer1.DataBind()
Dim viewer = ReportViewer1
viewer.ProcessingMode = ProcessingMode.Local
viewer.LocalReport.ReportPath = "Report1.rdlc"
p(0) = New ReportParameter("MonthYear", month & "-" & year)
Dim check = DropDownList1.SelectedValue
ReportViewer1.LocalReport.SetParameters(p(0))
p(1) = New ReportParameter("Location", DropDownList1.SelectedValue)
ReportViewer1.LocalReport.SetParameters(p(1))
Try
Dim bytes As Byte() = viewer.LocalReport.Render("PDF", Nothing, mimeType, encoding, ".pdf", streamIds, warnings)
Response.Buffer = True
Response.Clear()
Response.ContentType = mimeType
Response.AddHeader("content-disposition", Convert.ToString((Convert.ToString("attachment; filename=") & fileName) + ".") & extension)
Response.BinaryWrite(bytes)
' create the file
Response.Flush()
Catch ex As Exception
Debug.Print(ex.ToString)
End Try
End Sub

VB.NET FTP Picture Upload Error [duplicate]

This question already has answers here:
Zip file is getting corrupted after downloading from server in C#
(3 answers)
Closed 4 years ago.
I am trying to allow authenticated users to upload pictures to the server through FTP. The code works for the most part. The part that doesn't is that there is an issue in uploading the file. I have tried to upload a few different pictures and all of them are larger on the server and therefore, not properly constructed.
One picture I tried is 4.56MB on my computer and 8.24MB on the server. When I load the picture in Photo, it states "We can't open this file." The page location is at http://troop7bhac.com/pages/slideshowedit.aspx. The following is the VB.NET code behind the upload:
Sub uploadFile_Click(sender As Object, e As EventArgs)
lblUploadErrors.InnerHtml = ""
If (lstSlideshowChoose.SelectedValue = "") Then
lblUploadErrors.InnerHtml = "<p>A slideshow must be selected.</p>"
Else
If (FileUpload1.HasFile) Then
Dim nameList() As String
Dim successList() As String
Dim i As Integer = 0
For Each file As HttpPostedFile In FileUpload1.PostedFiles
Dim fileBytes() As Byte = Nothing
Dim fileName As String = Path.GetFileName(file.FileName)
Dim photoRE As New Regex("^[A-z0-9 _]{1,}\.jpg|JPG|jpeg|JPEG|png|PNG+$")
Dim photoSuccess As Boolean = photoRE.Match(fileName).Success
ReDim Preserve nameList(i)
ReDim Preserve successList(i)
If (photoSuccess = True) Then
Using fileStream As New StreamReader(file.InputStream)
fileBytes = Encoding.UTF8.GetBytes(fileStream.ReadToEnd())
fileStream.Close()
End Using
Try
Dim request As FtpWebRequest = DirectCast(WebRequest.Create(ftpPath & lstSlideshowChoose.SelectedValue & "/" & fileName), FtpWebRequest)
request.Method = WebRequestMethods.Ftp.UploadFile
request.Credentials = New NetworkCredential(ftpUser, ftpPass)
Using uploadStream As Stream = request.GetRequestStream()
uploadStream.Write(fileBytes, 0, fileBytes.Length)
uploadStream.Close()
End Using
Dim response As FtpWebResponse = DirectCast(request.GetResponse(), FtpWebResponse)
response.Close()
successList(i) = "Success "
Catch ex As Exception
successList(i) = "Failed "
End Try
Else
successList(i) = "Failed "
End If
nameList(i) = fileName
i += 1
Next
For x As Integer = 0 To nameList.Count - 1
lblUploadErrors.InnerHtml += "<p>" & successList(x) & nameList(x) & "</p>"
Next
Else
lblUploadErrors.InnerHtml = "<p>You have not selected a picture to upload.</p>"
End If
End If
End Sub
The files are obtained through an ASP.NET FileUpload control. The control has been set to allow multiple files at once.
Any help to figure out why the pictures are not uploading properly would be greatly appreciated.
EDIT: I tried Martin Prikryl's possible duplicate solution. Had to change it from C# to VB.NET. It failed. I tried David Sdot's solution and it also failed. Both solutions returned the same errors.
If the page was ran on my local machine, it returned "C:\Program Files (x86)\IIS Express\PictureName.JPG." If the page was ran on the server, it returned "C:\Windows\SysWOW64\inetsrv\PictureName.JPG." Both errors are of the System.IO.FileNotFoundException class.
Your Problem is here:
Using fileStream As New StreamReader(file.InputStream)
fileBytes = Encoding.UTF8.GetBytes(fileStream.ReadToEnd())
fileStream.Close()
Using
Your image is read as text. From this text you get the bytes UTF8 byte values, thats why your image is nearly twice the size when uplaoded. You need the bytes from the image, without converting them to something else.
fileBytes = File.ReadAllBytes(file.FileName)

VB Saving img file with path adds folder name to file name

Hi I am having some problems with saving img files using Visual Basic, the files are being named wrongly with the folder name being added to the start of the file name.
I parse a web address and then use the split address values to rename my files however the the path value seems to be added to the file as well.
The files in the photo should be named for example "DCAT040iMBE Test13.jpg"
but this file is being name "Test1DCAT040iMBE Test13.jpg"
Protected Sub GeneratedCode()
Dim path As String = "C:\Users\Grey\Documents\visual studio 2010\Projects\QRCodeGenerator\QRCodeGenerator\Output\"
LogoUpload.SaveAs(path + LogoUpload.FileName)
TextFile.SaveAs(path + TextFile.FileName)
Dim lines() As String = IO.File.ReadAllLines(path + TextFile.FileName)
For Each line As String In lines
Dim count As Integer
Dim encoder As New QRCodeEncoder()
encoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H
encoder.QRCodeScale = 10
Dim img As Bitmap = encoder.Encode(line)
Dim logo As System.Drawing.Image = System.Drawing.Image.FromFile(path + LogoUpload.FileName)
Dim left As Integer = (img.Width / 2) - (logo.Width / 2)
Dim top As Integer = (img.Height / 2) - (logo.Height / 2)
Dim g As Graphics = Graphics.FromImage(img)
Dim parseLine = line
Dim replaceDelimiter As String
If Not String.IsNullOrWhiteSpace(line) Then
replaceDelimiter = Replace(line, "&", "=")
End If
Dim fileNameSplit() As String = replaceDelimiter.Split("=")
Dim newFileName As String
Dim partTwo = fileNameSplit(1)
Dim partSix = fileNameSplit(5)
Dim objFSO
Dim newFolder As String
newFolder = "C:\Users\Grey\Documents\visual studio 2010\Projects\QRCodeGenerator\QRCodeGenerator\Output\" + partSix
objFSO = CreateObject("Scripting.FileSystemObject")
If (Not System.IO.Directory.Exists(newFolder)) Then
System.IO.Directory.CreateDirectory(newFolder)
End If
count += 1
g.DrawImage(logo, New Point(left, top))
newFileName = partTwo & " " & partSix & count & ".jpg"
img.Save(newFolder + newFileName, ImageFormat.Jpeg)
amountCreatedLbl.Text = count & " QRCodes Created"
logo.Dispose()
Next
End Sub
Could it be that I am generating my newFolder Values wrongly?
edited to add an example of data from the parsed txt file.
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAT050&Logo=MyLogo&Companyloc=Test1
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT055iMB&Logo=MyLogo&Companyloc=Test1
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT040iMBE&Logo=MyLogo&Companyloc=Test1
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAB060&Logo=MyLogo&Companyloc=Test1
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAT050&Logo=MyLogo&Companyloc=Test2
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT055iMB&Logo=MyLogo&Companyloc=Test2
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT040iMBE&Logo=MyLogo&Companyloc=Test2
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAB060&Logo=MyLogo&Companyloc=Test2
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAT050&Logo=MyLogo&Companyloc=Test3
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT055iMB&Logo=MyLogo&Companyloc=Test3
https://mywebsite.com/QRCode/default.aspx?materialcode=DCAT040iMBE&Logo=MyLogo&Companyloc=Test3
https://mywebsite.com/QRCode/default.aspx?materialcode=DTAB060&Logo=MyLogo&Companyloc=Test
Looks like you are missing a slash on the line:
img.Save(newFolder + newFileName, ImageFormat.Jpeg)
It should be:
img.Save(newFolder + "\" + newFileName, ImageFormat.Jpeg)
The program doesn't realize that the newDirectory variable is supposed to be a directory, it's just being concatenated to the filename directly. A better option would be to use:
img.Save(System.IO.Path.Combine(newFolder, newFileName), ImageFormat.Jpeg)
The System.IO.Path.Combine() function automatically adds the missing slash between the directory and filename, as well as some additional checks to make sure the result is valid.
As a side note, I would also recommend using & instead of + when joining strings together. Hard to debug issues can come up when you do it that way. I would also recommend turning Option Strict On, you will see a couple of other warnings that come up with your code as is. But, to resolve your issue, the above will work.

Export Crystal Report to PDF in a Loop only works with first

i'm trying to generate a report and export it to pdf in a loop, the report will receive a new parameter in each loop and prompt the client to download a PDF, in other words, the client may need to download 2 or 3 (or more) PDFs at the same time, the problem is that the prompt to accept the download only appears for the first pdf, dont know why. I can export to disk (server side) without any problems.
Code:
Sub PrintReport(ByVal Cod As Integer)
Dim CTableLogInfo As TableLogOnInfo
Dim ConnInfo As CrystalDecisions.Shared.ConnectionInfo = New ConnectionInfo()
ConnInfo.Type = ConnectionInfoType.SQL
ConnInfo.ServerName = ConfigurationManager.AppSettings("SQLSERVERNAME")
ConnInfo.DatabaseName = ConfigurationManager.AppSettings("SQLDBNAME")
ConnInfo.UserID = ConfigurationManager.AppSettings("SQLSERVERUSER")
ConnInfo.Password = ConfigurationManager.AppSettings("SQLSERVERPASSWORD")
ConnInfo.AllowCustomConnection = False
ConnInfo.IntegratedSecurity = False
For Each CTable As Table In CrystalReportSource1.ReportDocument.Database.Tables
CTable.LogOnInfo.ConnectionInfo = ConnInfo
CTableLogInfo = CTable.LogOnInfo
CTableLogInfo.ReportName = CrystalReportSource1.ReportDocument.Name
CTableLogInfo.TableName = CTable.Name
CTable.ApplyLogOnInfo(CTableLogInfo)
Next
Dim pField As ParameterField = CrystalReportSource1.ReportDocument.ParameterFields(0)
Dim val1 As ParameterDiscreteValue = New ParameterDiscreteValue
val1.Value = Cod
pField.CurrentValues.Clear()
pField.CurrentValues.Add(val1)
Dim PDFName As String = "PDF Nº " & Cod
CrystalReportSource1.ReportDocument.ExportToHttpResponse(ExportFormatType.PortableDocFormat, Page.Response, True, PDFName)
End Sub
EDIT:
Tried to zip the reports with DotNetZip but i get an broken zip.
Can you tell me whats wrong? (Solved: code bellow is corrected now)
Response.ClearContent()
Response.ClearHeaders()
Response.ContentType = "application/zip"
Response.AppendHeader("content-disposition", "attachment; filename=AllPDFs.zip")
Using zipFile As New ZipFile()
For i = 0 To Cod.Length - 1
If Cod(i) > 0 Then
val1.Value = Cod(i)
pField.CurrentValues.Clear()
pField.CurrentValues.Add(val1)
val2.Value = Cod(i)
pField2.CurrentValues.Clear()
pField2.CurrentValues.Add(val2)
Dim PDFNameAs String = "PDF Nº " & Cod(i) & ".pdf"
Dim s As New System.IO.MemoryStream
s =CrystalReportSource1.ReportDocument.ExportToStream(ExportFormatType.PortableDocFormat)
zipFile.AddEntry(PDFName, s)
End If
Next
zipFile.Save(Response.OutputStream)
End Using
Response.Clear()
Probably the response ends after the first one, therefore there's no response to write to for the 2nd and 3rd attempts.
Instead, you can have the client download the reports via AJAX Request (move your report generation into an .ashx generic handler), or have the user click the button 3 times to initiate new requests.
Or zip the PDF's up until a single file and allow the client to download that.

How to fill a word document using Visual Basic / Visual C# in ASP.NET

I'm looking for options to fill a Word Document from either Visual Basic, or Visual C#. I'm currently using merge fields, and the code below to fill specific fields in a Word Document, but now I've run into a situation where I need tabular data pushed to MS Word. Is there anyway to take data from a grid view (number of rows is dynamic), and import it into a Word Document Table using a merge field or something of that sort? I have to maintain the format of my template doc, and would like to be able to control the layout of the page ..
Dim templateDoc As String = Server.MapPath("\Userfiles\docs\" & location)
Dim mergePath As String = Server.MapPath("\App_Data\Temp\")
Dim mergeFileName As String = location.Replace("/", "_") & ".docx"
Dim mergeDoc As String = mergePath & "\" & mergeFileName
File.Copy(templateDoc, mergeDoc, True)
Using pkg As Package = Package.Open(mergeDoc, FileMode.Open, FileAccess.ReadWrite)
Dim uri As Uri = New Uri("/word/document.xml", UriKind.Relative)
Dim part As PackagePart = pkg.GetPart(uri)
Dim xmlMainXMLDoc As XmlDocument = New XmlDocument()
xmlMainXMLDoc.Load(part.GetStream(FileMode.Open, FileAccess.Read))
Dim innerXml As String = xmlMainXMLDoc.InnerXml _
.Replace("«Corporate Legal Name»", businessName) _
.Replace("«Address 1»", mailingAddress1) _
.Replace("«Address 2»", mailingAddress2) _
.Replace("«City»", city)
xmlMainXMLDoc.InnerXml = innerXml
Using partWriter As New StreamWriter(part.GetStream(FileMode.Open, FileAccess.Write))
xmlMainXMLDoc.Save(partWriter)
End Using
pkg.Close()
End Using
You can write out in HTML and save it with a .doc extension and Word will handle it gracefully.
Just like my answer for your question regarding Excel, Office writer will work for you here too!

Resources