iTextSharp creates PDF with blank pages - c#

I've just added the iTextSharp XMLWorker nuget package (and its dependencies) to my project and I'm trying to convert the HTML from a string into a PDF file, even though no exceptions are being thrown, the PDF file is being generated with two blank pages. Why?
The previous version of the code was using just iTextSharp 5.5.8.0 with HTMLWorker and ParseList method, then I switched to
Here is the code I'm using:
public void ExportToPdf() {
string htmlString = "";
Document document = new Document(PageSize.A4, 40, 40, 40, 40);
var memoryStream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(document, memoryStream);
document.Open();
htmlString = sbBodyMail.ToString();
XMLWorkerHelper.GetInstance().ParseXHtml(writer, document, new StringReader(htmlString));
document.Close();
DownloadFile(memoryStream);
}
public void DownloadFile(MemoryStream memoryStream) {
//Clears all content output from Buffer Stream
Response.ClearContent();
//Clears all headers from Buffer Stream
Response.ClearHeaders();
//Adds an HTTP header to the output stream
Response.AddHeader("Content-Disposition", "attachment;filename=Report_Diagnosis.pdf");
//Gets or Sets the HTTP MIME type of the output stream
Response.ContentType = "application/pdf";
//Writes the content of the specified file directory to an HTTP response output stream as a file block
Response.BinaryWrite(memoryStream.ToArray());
//Response.Write(doc);
//sends all currently buffered output to the client
Response.Flush();
//Clears all content output from Buffer Stream
Response.Clear();
}
If I place document.Add(new Paragraph("Just a test")); right before document.Close(); the paragraph is rendered in the second page, but the rest of the document still is blank.
UPDATE
I've changed the HTML in the htmlString variable to just a DIV and a TABLE and it worked. So, now the question becomes: how do I know what part of the HTML is causing some error in the XMLWorker?

I've figured out that XMLWorkerHelper was having trouble with DIV width attribute (even set on style attribute) and unfortunately it doesn't throw any exception to help you on this.
I found this answer from iTextSharp's developer that says that centering a table isn't supported yet, so I'm assuming this is not supported too.

Related

Send PDF to the browser rather than saving to the server - ASP.NET iText 7 C# Web Forms

this is my first time posting on SO
I have been using iText 7 so users of my web app can generate a pdf of a document.
I would like the document sent to the browser so either it gets saved to the user Downloads folder or the user can choose where to save it with the browser save dialog box.
However, all the C# examples I have found require a hard-coded path & file name, so it gets saved on the server rather than client machines.
I have been researching this for a few days now and floundering around with solutions, this is what I have:
public void mtdCreatePDF()
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=print.pdf");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
var stream = new MemoryStream();
var writer = new PdfWriter(stream);
var pdf = new PdfDocument(writer);
var document = new Document(pdf);
document.Add(new Paragraph("Hello world!"));
document.Close();
Response.Write(document);
Response.End();
}
This creates print.pdf in browser Downloads folder, but the file is corrupt.
I would be grateful if someone could point out where I am going wrong, the majority of articles in this regard relate to the older itextsharp, and the iText 7 examples have hard-coded file paths and file names.
I have found one possible solution that looks good, but unfortunately it is in Java. I've been floundering around for ages trying to convert it to C#, but I don't know any Java so it's turned into a pig's breakfast. This is the Java solution:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(baos));
Document doc = new Document(pdfDoc);
doc.add(new Paragraph("Hello world!"));
doc.close();
// setting some response headers
response.setHeader("Expires", "0");
response.setHeader("Cache-Control",
"must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
// setting the content type
response.setContentType("application/pdf");
// the contentlength
response.setContentLength(baos.size());
// write ByteArrayOutputStream to the ServletOutputStream
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
os.close();
Any help would be greatly appreciated.
Thank you
This solution seems to be working perfectly.
public void mtdCreatePDF()
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=print.pdf");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
var stream = new MemoryStream();
var writer = new PdfWriter(stream);
var pdf = new PdfDocument(writer);
var document = new Document(pdf);
document.Add(new Paragraph("Hello world!"));
document.Close();
Response.BinaryWrite(stream.ToArray());
Response.End();
}

MVC - Generating multiple PDFs

I am using the following code for generating a PDF file.
It is working good, but now i want to generate 4 PDF's at the same time.
I tried by again initiating Document & repeating the whole code for generating 2nd PDF report, But it generates only 1 PDF.
var document = new Document(PageSize.A4, 50, 50, 25, 25);
// Create a new PdfWrite object, writing the output to a MemoryStream
var output = new MemoryStream();
var writer = PdfWriter.GetInstance(document, output);
// Open the Document for writing
document.Open();
string contents = System.IO.File.ReadAllText(Server.MapPath("~/Reports/Original.html"));
var parsedHtmlElements = HTMLWorker.ParseToList(new StringReader(contents), null);
foreach (var htmlElement in parsedHtmlElements)
document.Add(htmlElement as IElement);
document.Close();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename=Receipt-{0}.pdf", "Report"));
Response.BinaryWrite(output.ToArray());
return View();
How to generate multiple PDF's?
You are outputting the bytes as a response, so you would never be able of generating 2 different files in one response. Only one response per request.
If you want the user to download 2 different PDFs at the same time you could call the controller using javascript from the view.

iTextSharp not preserving PDF styling after adding js

I have an set of PDF files created before using different system.
Those are styled correctly, (using Arial font, bold and normal) - PDF contains Swedish characters, and everything works when I print it.
However, I've been working on an solution to not show the pdf file itself to the user, just start the print dialogue. I have used iTextSharp to include JS code what will automatically print the PDF once started.
Method that adds the JS to the provided file and sends it to the user:
protected void StreamPdf(string pdfSource)
{
var outputStream = new MemoryStream();
var pdfReader = new PdfReader(pdfSource);
var pdfStamper = new PdfStamper(pdfReader, outputStream);
//Add the auto-print javascript
var writer = pdfStamper.Writer;
writer.AddJavaScript(GetAutoPrintJs());
pdfStamper.Close();
var content = outputStream.ToArray();
outputStream.Close();
Response.ContentType = "application/pdf";
Response.BinaryWrite(content);
Response.End();
outputStream.Close();
outputStream.Dispose();
}
Now the thing is - after writing the file back using response, I am loosing the formatting - text that was bold before now is normal, and regional characters are lost (displaying empty squares instead).
Is there any possibility to preserve the formatting?

asp.net open word document

I try to open a word document with c#.
When I open the document, the page is blocked after.
Here is the code :
HttpContext.Current.Response.Write(temp);
//HttpContext.Current.Response.End();
//HttpContext.Current.Response.Flush();
//HttpContext.Current.Response.Write(sw.ToString());
//HttpContext.Current.Response.clear();
//HttpContext.Current.Response.End();
//HttpContext.Current.Response.SuppressContent = true;
//HttpContext.Current.Response.Close();
//Response.Redirect(Page.Request.Url.AbsolutePath.Substring(0, Page.Request.Url.AbsolutePath.LastIndexOf("/")) + "/PIEditor.aspx?PostID=" + Request.Params["PostID"], true);`
//HttpContext.Current.Response.End();
As you see, I tried different options but without result, the window for opening or saving the document is displayed but I can't click on any buttons the page after. It looks like it is deactivated or stopped.
you can try GemBox.Document component to export Word document from ASP.NET application, if that is what you are trying to do.
Here is a sample C# code that should go in ASPX page code behind:
// Create a new empty document.
DocumentModel document = new DocumentModel();
// Add document content.
document.Sections.Add(new Section(document, new Paragraph(document, "Hello World!")));
// Microsoft Packaging API cannot write directly to Response.OutputStream.
// Therefore we use temporary MemoryStream.
using (MemoryStream documentStream = new MemoryStream())
{
document.Save(documentStream, SaveOptions.DocxDefault);
// Stream file to browser.
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats";
Response.AddHeader("Content-Disposition", "attachment; filename=Document.docx");
documentStream.WriteTo(Response.OutputStream);
Response.End();
}
Try the below code:
//create new MemoryStream object and add PDF file’s content to outStream.
MemoryStream outStream = new MemoryStream();
//specify the duration of time before a page cached on a browser expires
Response.Expires = 0;
//specify the property to buffer the output page
Response.Buffer = true;
//erase any buffered HTML output
Response.ClearContent();
//add a new HTML header and value to the Response sent to the client
Response.AddHeader(“content-disposition”, “inline; filename=” + “output.doc”);
//specify the HTTP content type for Response as Pdf
Response.ContentType = “application/msword”;
//write specified information of current HTTP output to Byte array
Response.BinaryWrite(outStream.ToArray());
//close the output stream
outStream.Close();
//end the processing of the current page to ensure that no other HTML content is sent
Response.End();

Save the generated pdf directly to the server directory folder without user prompt

A friend of mine gave me this task so I can learn advance programming a little bit easier. I am currently doing convertion of an html page to pdf using itext sharp and email the pdf as an attachement. My idea is to save the pdf first to the server machine in the folder name ToBeEmailedPDF folder before using it as an email attachment. The thing that bothers me is that this dialog as what you can see in the picture shows up using the code that I have below.
StringBuilder sb = new StringBuilder();
StringWriter tw = new StringWriter(sb);
HtmlTextWriter hw = new HtmlTextWriter(tw);
pnlPDF.RenderControl(hw); // pnlPDF contains the html contents to be converted to pdf
string htmlDisplayText = sb.ToString();
Document document = new Document();
MemoryStream ms = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(document, ms);
StringReader se = new StringReader(htmlDisplayText);
HTMLWorker obj = new HTMLWorker(document);
document.Open();
obj.Parse(se);
// step 5: we close the document
document.Close();
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=report.pdf");
Response.ContentType = "application/pdf";
Response.Buffer = true;
Response.OutputStream.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
Response.OutputStream.Flush();
Response.End();
I know many of you out there knows a better way or know how to solve my problem. Please help me. Thank you!
There is big difference between client-side and server-side.
Response class can output contents to client machine, if you need to save file on server use something like File.WriteAllBytes (msdn) method
What you are trying to achieve is impossible for security reasons. Only the user can decide where he wants the attachment to be saved. Imagine if this was possible: you would then be able to save any kind of viruses into any kind of folders on the user's computer. As an alternative to showing the Save dialog you could open the PDF inline:
Response.AddHeader("Content-Disposition", "inline; filename=report.pdf");
You can save it using the following code:
PdfWriter.GetInstance(pdfDoc, new FileStream(context.Server.MapPath("~") + "/PDF/" + reportName + ".pdf", FileMode.Create));

Categories