I've been attempting to create a pdf using iTextSharp and have run into an issue. Upon closing the pdf, Acrobat Reader prompts the user "Do you want to save changes..."
This seems to be a common issue, and there are probably a dozen questions on stack overflow about it, and just as many different solutions. I've tried as many solutions I can find, to no avail.
My code is below. I create a simple pdf with one paragraph, using MemoryStream and the PdfWriter. I then return the MemoryStream as an array, and I then use the response.outputstream to download the file to the client.
protected void lnkbtnDownloadPdf_Click(object sender, EventArgs e)
{
var Pdf = DownloadPdf();
Response.ContentType = "application/pdf;";
Response.AddHeader("Content-Disposition", "attachment; filename=" + "test.pdf");
Response.OutputStream.Write(Pdf, 0, Pdf.Length);
Response.OutputStream.Close();
}
public static byte[] DownloadPdf()
{
using (MemoryStream ms = new MemoryStream())
{
Document doc = new Document(PageSize.LETTER.Rotate());
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
doc.Open();
doc.Add(new Paragraph("testtesttesttesttesttestesttest"));
doc.Close();
writer.Close();
return ms.ToArray();
}
}
I've tried this - iTextSharp-generated PDFs now cause Save dialog in Adobe Reader X - and I still get the save dialog.
I've also tried to implement this - Using iTextSharp to write data to PDF works great, but Acrobat Reader asks 'Do you want to save changes' when closing file - but my program doesn't use the stamper. Bruno has an answer on that link as well mentioning the acroform dictionary, but I'm not sure how to remove entries from that dictionary, and the user who asked the question was unable to fix their issue doing that anyways.
I need to use the PdfWriter. I've also looked into using the filestream instead of the outputstream like mentioned here - iTextSharp-generated PDFs cause save dialog when closing - but I need to download the pdf to the client and not save it on disk.
After some time I figured out it wasn't an Itext problem at all (to my knowledge).
I added -
Response.End();
-at the end of the lnkbtnDownloadPdf_Click function and it worked. Acrobat no longer asks the user to save, when they close my PDFs.
Related
I have a PDF document that has a number of fill-in fields (text and checkboxes). How do you go about referencing these objects so I can manipulate its value, then push that updated PDF to the user where they can save it to their desired location. I'm not finding any good documentation on how to do this.
Any information you could give me would be greatly appreciated.
Right now I am using the following code, but when I go to open it my PDF reader tells me that it is damaged or corrupt.
String srcPath = Server.MapPath("~/App_Data/w9.pdf");
String dstPath = Server.MapPath("~/App_Data/w9_" + Session.SessionID + "_updated.pdf");
if (File.Exists(dstPath)) {
File.Delete(dstPath);
}
File.Copy(srcPath, dstPath);
PdfReader reader = new PdfReader(dstPath);
try
{
PdfStamper stamper = new PdfStamper(reader, Response.OutputStream);
stamper.FormFlattening = true;
stamper.AcroFields.SetField("topmostSubform[0].Page1[0].f1_01_0_[0]", "Homer J Simpson");
Response.ContentType = "application/pdf";
Response.BufferOutput = true;
Response.AppendHeader("Content-Disposition", "attachment; filename=W9_" +Session.SessionID + "_Complete.pdf");
Response.TransmitFile(dstPath);
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
I'm the author of the iText documentation. If you have a static form, then you can use the methods described in this chapter to fill out your form: http://www.manning.com/lowagie2/samplechapter6.pdf
Read section 6.3.5 to find out how to fill out a form created with Open Office. However, it looks as if you are using a form created with Adobe LiveCycle (fieldnames like topmostSubform[0].Page1[0].f1_01_0_[0] are typical for XFA forms).
Section 6.3.5 concludes with the following remark:
"There’s much more to say about forms, but we can’t go into further
detail until we’ve talked about annotations. Also, I haven’t said
anything about the different types of PDF forms yet: there are forms
based on AcroForm technology (like the form you created using Open
Office), and there are XFA forms (created with Adobe Designer). This
will have to wait until chapter 8, because we have one more group of
PDF manipulation classes left to cover."
If your form is a dynamic XFA form without any AcroForm technology inside, you need XFA Worker to flatten it. You can download a trial version of XFA Worker here: http://itextsupport.com/download/xfaworker.html
The first question you have to answer before you continue is: do I have an AcroForm or an XFA form? If you have an XFA form, you'll need either Adobe LiveCycle ES or XFA Worker to fill and flatten such a form. Both are closed source products. I don't know of any free / open source library that supports XFA flattening.
PS: if by "damaged" you mean that you get a message saying This document enabled extended features... then you are breaking the Reader enabling. You should read chapter 8 of "iText in Action - Second Edition" to find out how to avoid this message.
I'm using iTextSharp 5.3.2.0 to add information to an existing PDF file that contains a W-2 form. Everything is working perfectly and the PDF file looks great when written into the browser's response stream; however, when the user is done looking at the PDF, he is asked "Do you want to save changes to 'W2.pdf' before closing?" every time he views the document from the web page.
In trying to narrow the problem down, I've actually stripped out all of my modifications but the problem continues. Here's the simple version of my code, with my data-writing call commented out:
PdfReader pdfReader = new PdfReader(dataSource.ReportTemplate);
using(MemoryStream outputStream = new MemoryStream())
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream))
{
//dataSource.DrawDataFields(pdfStamper);
pdfStamper.FormFlattening = true;
return outputStream;
}
In this case, the "empty" PDF is written to the browser and looks good, but I still get asked, "Do you want to save" when I close the Acrobat window.
At this point I was thinking that there was something wrong with the source PDF file. However, when I send back the PDF file's raw bytes to the browser, I am NOT asked the "Do you want to save" question when using the code below.
byte[] bytes = File.ReadAllBytes(dataSource.ReportTemplate);
using (MemoryStream outputStream = new MemoryStream())
{
outputStream.Write(bytes, 0, bytes.Length);
return outputStream;
}
My conclusion is that iTextSharp is doing something "bad" to the PDF in the process of opening it and writing the bytes to the stream, but I'm new to iTextSharp and could easily be missing something.
FWIW, this is Acobat Reader 10.1.4 that we're talking about.
EDIT: The original PDF used as a template is approximately 80K in size. If I look at the temporary file that's been streamed down through my browser, the PDF file written by iTextSharp is approximately 150K. However, when I answer "Yes" to the "Save Changes" question asked by Acrobat Reader, the resulting file is approximately 80K again. iTextSharp is definitely doing something unexpected to this file.
Non-working:
public byte[] MergeDataByDrawing(int copies)
{
PdfReader pdfReader = new PdfReader(reportTemplate);
using (MemoryStream outputStream = new MemoryStream())
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream))
{
pdfStamper.FormFlattening = true;
return outputStream.GetBuffer();
}
}
Working:
public byte[] MergeDataByDrawing(int copies)
{
PdfReader pdfReader = new PdfReader(reportTemplate);
using (MemoryStream outputStream = new MemoryStream())
using (PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream))
{
pdfStamper.FormFlattening = true;
return outputStream.ToArray();
}
}
Seems the GetBuffer method is a problem. I don't understand why, but I'll take the result!
Props to MKL for giving me an idea and Fredrik for the right example at the right time.
See http://itextpdf.com/history/?branch=52&node=521
Bugfix AcroForms: In some cases, Adobe Reader X asks if you want to
"save changes" after closing a flattened PDF form. This was due to the
presence of some unnecessary entries in the /AcroForm dictionary (for
instance added when the form was created with OOo).
I'm the Bruno who fixed this bug. I remember that it occurred in Adobe Reader 10, but not in Adobe Reader 9. I was able to fix the bug because the person reporting it was a customer who sent me a PDF that showed this behavior.
If you would share your PDF, we could take a look and see what other entries should be removed from the /AcroForm dictionary. I only removed those that were added when the form is created using Open Office. If you don't want to share the PDF, the cause will always remain a mystery.
I have generated a pdf using iTextSharp, when its created it saves automatically in the location provided in my code on the server not on the client side and of course without telling anything to the user.
I need to send it to the client and I need to prompt a dialogue box to ask the user where he wants to save his pdf..
how can i do this please?
this is my pdf code:
using (MemoryStream myMemoryStream = new MemoryStream())
{
Document document = new Document();
PdfWriter PDFWriter = PdfWriter.GetInstance(document, myMemoryStream);
document.AddHeader("header1", "HEADER1");
document.Open();
//..........
document.Close();
byte[] content = myMemoryStream.ToArray();
// Write out PDF from memory stream.
using (FileStream fs = File.Create(HttpContext.Current.Server.MapPath("~\\report.pdf")))
{
fs.Write(content, 0, (int)content.Length);
}
EDIT
this is an example of the result i want
http://examples.extjs.eu/?ex=download
thanks to your replies ,I modified my code to this:
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AppendHeader( "Content-Disposition", "attachment; filename=test.pdf");
using (MemoryStream myMemoryStream = new MemoryStream())
{
Document document = new Document();
PdfWriter PDFWriter = PdfWriter.GetInstance(document, myMemoryStream);
document.AddHeader("Content-Disposition", "attachment; filename=wissalReport.pdf");
document.Open();
//..........
document.Close();
byte[] content = myMemoryStream.ToArray();
HttpContext.Current.Response.Buffer = false;
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.AppendHeader("content-disposition","attachment;filename=" + "my_report.pdf");
HttpContext.Current.Response.ContentType = "Application/pdf";
//Write the file content directly to the HTTP content output stream.
HttpContext.Current.Response.BinaryWrite(content);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
but i get this error:
Uncaught Ext.Error: You're trying to decode an invalid JSON String:
%PDF-1.4 %���� 3 0 obj <</Type/XObject/Subtype/Image/Width 994/Height 185/Length 13339/ColorSpace/DeviceGray/BitsPerComponent 8/Filter/FlateDecode>>stream x���|E�
...........
im absolutely sure my itextsharp to create pdf is correct because i can save it on the server, but thats not what i need to do ,when i try to send it to the client i got the error above
thanks in advance
In case of a web application you probably want to stream the pdf as binary to user, that would either open the pdf or prompt user to save the file.
Remember pdf generation is happening at server, even if user provides the path it won't be of any use on server. See following links -
How To Write Binary Files to the Browser Using ASP.NET and Visual C# .NET
In your case you are generating the file and hence will already be having a binary stream instead of file, hence you can directly use Response.BinaryWrite instead of Response.WriteFile.
Modified sample:
Response.Buffer = false;
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
//Set the appropriate ContentType.
Response.ContentType = "Application/pdf";
//Write the file content directly to the HTTP content output stream.
Response.BinaryWrite(content);
Response.Flush();
Response.End();
You need to send a content disposition header to the users browser. From memory the code is something sort of like this:
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Disposition","attachment; filename=nameofthefile.pdf");
Currently you are saving your file on the file server, thereby overwriting the same pdf with every request. And probably causing errors if you get two requests for a PDF at the same time.
Use Response to return the PDF (from the memorystream) to the user, and skip the writing of the PDF to a file locally on your server.
The browser will ask the user where the file should be saved. Something like:
Response.ContentType = "Application/pdf";
myMemoryStream.CopyTo(Response.OutputStream);
Also look at the answer from Alun, using content-disposition you can propose a filename to the user.
SOLVED
The error is from the submit operation trying to interpret the response which it can not because it is not in a known format.
I just set window.location to download files and this works fine.
{
xtype:'button',
text: 'Generate PDF',
handler: function () {
window.location = '/AddData.ashx?action=pdf';
}
}
Instead of setting the location you can also do window.open().
Whether the file will be downloaded or opened depends on browser settings.
You do not need to use MemoryStream. Use Response.OutputStream instead. That's what it's there for. No need to use Response.BinaryWrite() or any other call to explicitly write the document either; iTextSharp takes care of writing to the stream when you use Response.OutputStream.
Here's a simple working example:
Response.ContentType = "application/pdf";
Response.AppendHeader(
"Content-Disposition",
"attachment; filename=test.pdf"
);
using (Document document = new Document()) {
PdfWriter.GetInstance(document, Response.OutputStream);
document.Open();
document.Add(new Paragraph("This is a paragraph"));
}
Here's how to add the proper HTTP headers. (getting the prompt to save the file) And if your code is in a web form, (button click handler), add Response.End() to the code example above after the using statement so that the web form's HTML output is not appended the PDF document.
I have a website that has a bunch of PDFs that are pre-created and sitting on the webserver.
I don't want to allow a user to just type in a URL and get the PDF file (ie http://MySite/MyPDFFolder/MyPDF.pdf)
I want to only allow them to be viewed when I load them and display them.
I have done something similar before. I used PDFSharp to create a PDF in memory and then load it to a page like this:
protected void Page_Load(object sender, EventArgs e)
{
try
{
MemoryStream streamDoc = BarcodeReport.GetPDFReport(ID, false);
// Set the ContentType to pdf, add a header for the length
// and write the contents of the memorystream to the response
Response.ContentType = "application/pdf";
Response.AddHeader("content-length", Convert.ToString(streamDoc.Length));
Response.BinaryWrite(streamDoc.ToArray());
//End the response
Response.End();
streamDoc.Close();
}
catch (NullReferenceException)
{
Communication.Logout();
}
}
I tried to use this code to read from a file, but could not figure out how to get a MemoryStream to read in a file.
I also need a way to say that the "/MyPDFFolder" path is non-browsable.
Thanks for any suggestions
To load a PDF file from the disk into a buffer:
byte [] buffer;
using(FileStream fileStream = new FileStream(Filename, FileMode.Open))
{
using (BinaryReader reader = new BinaryReader(fileStream))
{
buffer = reader.ReadBytes((int)reader.BaseStream.Length);
}
}
Then you can create your MemoryStream like this:
using (MemoryStream msReader = new MemoryStream(buffer, false))
{
// your code here.
}
But if you already have your data in memory, you don't need the MemoryStream. Instead do this:
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Length", buffer.Length.ToString());
Response.BinaryWrite(buffer);
//End the response
Response.End();
streamDoc.Close();
Anything that is displayed on the user's screen can be captured. You might protect your source files by using a browser-based PDF viewer, but you can't prevent the user from taking snapshots of the data.
As far as keeping the source files safe...if you simply store them in a directory that is not under your web root...that should do the trick. Or you can use an .htaccess file to restrict access to the directory.
Keltex's code works for limiting who can get to the file. If the user isn't authorized for a particular file, give them a page with an error message, otherwise use that code to relay them the PDF. The URL then won't be directly to a PDF, but rather a script, so that will give you 100% control over who is permitted to access it.
Rather than putting the PDFs in question in an accessible location and messing with the configuration to hide them, you could put them someplace in the server that isn't directly web accessible. Since you'll have code reading the file into a buffer and relaying it to the user anyway, it doesn't matter where on the server the file is located, so long as it is accessible to your code.
I am trying to export the HTML page contents to Word.
My Html display page is:
What is your favourite color?
NA
List the top three school ?
one National
two Devs
three PS
And a button for click event. The button click event will open MS word and paste the page contents in word.
The word page contains the table property of html design page. It occurs only in Word 2003. But in word 2007 the word document contains the text with out table property. How can I remove this table property in word 2003.
I am not able to add the snapshots. Else i will make you clear.
I am designing the web page by aspx. I am exporting the web page content by the following code.
protected void Button1_Click(object sender, EventArgs e)
{
Response.ContentEncoding = System.Text.Encoding.UTF7;
System.Text.StringBuilder SB = new System.Text.StringBuilder();
System.IO.StringWriter SW = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter htmlTW = new System.Web.UI.HtmlTextWriter(SW);
tbl.RenderControl(htmlTW);
string strBody = "<html>" +
"<body>" + "<div><b>" + htmlTW.InnerWriter.ToString() + "</b></div>" +
"</body>" +
"</html>";
Response.AppendHeader("Content-Type", "application/msword");
Response.AppendHeader("Content-disposition", "attachment; filename=" + fileName);
Response.ContentEncoding = System.Text.Encoding.UTF7;
string fileName1 = "C://Temp/Excel" + DateTime.Now.Millisecond.ToString();
BinaryWriter writer = new BinaryWriter(File.Open(fileName1, FileMode.Create));
writer.Write(strBody);
writer.Close();
FileStream fs = new FileStream(fileName1, FileMode.Open, FileAccess.Read);
byte[] renderedBytes;
// Create a byte array of file stream length
renderedBytes = new byte[fs.Length];
//Read block of bytes from stream into the byte array
fs.Read(renderedBytes, 0, System.Convert.ToInt32(fs.Length));
//Close the File Stream
fs.Close();
FileInfo TheFile = new FileInfo(fileName1);
if (TheFile.Exists)
{
File.Delete(fileName1);
}
Response.BinaryWrite(renderedBytes);
Response.Flush();
Response.End();
}
You are writing HTML, claiming it is of content type "application/msword", then hoping for the best..
There are more "correct" ways to achieve your objective.
There are a few projects around for converting (X)HTML to WordML content, of which docx4j-ImportXHTML.NET is one. Disclosure: I maintain that; you can find links to others elsewhere here on StackOverflow.
Alternatively, you can use Word's altChunk mechanism, though note:
you have less control over how the import is performed;
AltChunk isn't supported by Word 2003 (even with the compatibility pack).
Question not clear.
Well, these links may help you in understanding MSWord-C# automation:
http://www.codeproject.com/KB/cs/Simple_Ms_Word_Automation.aspx
http://www.c-sharpcorner.com/UploadFile/amrish_deep/WordAutomation05102007223934PM/WordAutomation.aspx
You can also try to create an Open XML document that is now recognized by MS office.
Here is some more info with code samples:
http://msdn.microsoft.com/en-us/library/bb656295.aspx
From what I understand, you are trying to create a ms word document on the fly and are having difficulty when the output is viewed in Word 2003 vs. 2007.
In your code above, you are simply spitting out html and forcing it to be a ms word document. I'm surprised it even works.
Instead, you might want to use Office Interop (Microsoft.Office.Interop.Word) or install DocX using nuget. Look at some examples online, search for "C# create word doc".