I have a piece of code which exports the Datatable to pdf. When I try to download the pdf, it downloads successfully but it get will not open. I am using the iTextSharp library. Here is my code:
var document = new Document(PageSize.A4, 10, 10, 10, 10);
var output = new MemoryStream();
PdfWriter writer= PdfWriter.GetInstance(document, output);
document.Open();
iTextSharp.text.Font font5 = iTextSharp.text.FontFactory.GetFont(FontFactory.HELVETICA, 5);
Paragraph p = new Paragraph();
p.Alignment = Element.ALIGN_CENTER;
document.Add(p);
if (dt != null)
{
//Craete instance of the pdf table and set the number of column in that table
PdfPTable PdfTable = new PdfPTable(dt.Columns.Count);
PdfPCell PdfPCell = null;
for (int rows = 0; rows < dt.Rows.Count; rows++)
{
for (int column = 0; column < dt.Columns.Count; column++)
{
PdfPCell = new PdfPCell(new Phrase(new Chunk(dt.Rows[rows][column].ToString())));
PdfTable.AddCell(PdfPCell);
}
}
document.Add(PdfTable);
document.Close();
}
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}", reportname + "_Report_" + DateTime.Now.Date.ToString("yyyy_MMM_dd") + ".pdf"));
HttpContext.Current.Response.Write(document);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
Can anybody please tell me what the problem is?
The OP writes an iTextSharp Document instance to the HTTP response:
var document = new Document(PageSize.A4, 10, 10, 10, 10);
var output = new MemoryStream();
PdfWriter writer= PdfWriter.GetInstance(document, output);
document.Open();
...
HttpContext.Current.Response.Write(document);
This is wrong, that Document instance only is an object to forward material to which is to be arranged and drawn to the PDF. The actual PDF is output to the MemoryStream instance for which the PdfWriter is instantiated. Thus, this stream's content has to be returned.
In reaction to a comment to that effect, the OP fixed the problem using
HttpContext.Current.Response.BinaryWrite(output.ToArray());
instead.
Related
while generating pdf on localhost using below code is fine,however it generates a pdf of 0KB size while on server . What I am doing wrong here ?
I am using iTextsharp nuget and the code runs fine on local server.
public byte[] GetPDF(string pHTML, List<int> ideaidlist)
{
byte[] bPDF = null;
MemoryStream ms = new MemoryStream();
TextReader txtReader = new StringReader(pHTML);
// Document doc = new Document(PageSize.LETTER, 0, 0, 0, 0);
Document doc = new Document(new Rectangle(864f, 870f), 0, 0, 0, 0);
string Certpath = ConfigurationManager.AppSettings["MailImagePath"]+"Certificates.pdf";//System.Configuration.
string ImgTopPath =ConfigurationManager.AppSettings["CertificateImagePath"];
string ImgMidPath =ConfigurationManager.AppSettings["CertificateImagePath"];
string ImgBotPath =ConfigurationManager.AppSettings["CertificateImagePath"];
FileInfo newExistFile = new FileInfo(Certpath);
if (newExistFile.Exists)
{
newExistFile.Delete();
}
PdfWriter oPdfWriter = PdfWriter.GetInstance(doc,new FileStream(Certpath , FileMode.CreateNew));
HTMLWorker htmlWorker = new HTMLWorker(doc);
doc.Open();
GeneratePdfVM data = new GeneratePdfVM();
foreach (var item in ideaidlist)
{
data = new CommonBL().GetIdeaidListForGenerateCertificates(item);
doc.NewPage();
PdfPTable table = new PdfPTable(1);
table.TotalWidth = 1000;
table.WidthPercentage = 100;
table.LockedWidth = true;
table.HorizontalAlignment = 0;
table.DefaultCell.Border = Rectangle.NO_BORDER;
iTextSharp.text.Image imageTopURL = iTextSharp.text.Image.GetInstance(ImgTopPath + "CertiTop.PNG");
PdfPCell imgTopCell = new PdfPCell(imageTopURL);
imgTopCell.Border = Rectangle.NO_BORDER;
table.AddCell(imgTopCell);
imageTopURL.SpacingAfter = 20;
PdfPCell FirstTxtCell = new PdfPCell();
Paragraph p = new Paragraph(data.EmpName);
p.Font = new Font(Font.FontFamily.HELVETICA, 35f, Font.UNDERLINE);
p.Alignment = Element.ALIGN_CENTER;
FirstTxtCell.AddElement(p);
FirstTxtCell.PaddingRight = 190f;
FirstTxtCell.Border = 0;
table.AddCell(FirstTxtCell);
iTextSharp.text.Image imageMidURL = iTextSharp.text.Image.GetInstance(ImgMidPath + "CertiMid.PNG");
PdfPCell imgMidCell = new PdfPCell(imageMidURL);
imgMidCell.Border = Rectangle.NO_BORDER;
imgMidCell.Border = 0;
imageMidURL.SpacingBefore = 15f;
imageMidURL.Alignment = Element.ALIGN_CENTER;
imgMidCell.PaddingRight = 244f;
table.AddCell(imgMidCell);
PdfPCell SecTextCell = new PdfPCell();
Paragraph para = new Paragraph(data.Title);
para.Font = new Font(Font.FontFamily.HELVETICA, 32f, Font.ITALIC);
para.Alignment = Element.ALIGN_CENTER;
SecTextCell.AddElement(para);
SecTextCell.Border = 0;
SecTextCell.PaddingRight = 200f;
table.AddCell(SecTextCell);
iTextSharp.text.Image imageBotURL = iTextSharp.text.Image.GetInstance(ImgBotPath + "CertiBottom.PNG");
PdfPCell imgBotCell = new PdfPCell(imageBotURL);
imgBotCell.Border = 0;
table.AddCell(imgBotCell);
imageBotURL.SpacingBefore=20;
imageTopURL.ScaleAbsolute(860f, 230f);
imageMidURL.ScaleAbsolute(930f, 100f);
imageBotURL.ScaleAbsolute(864f, 230f);
doc.Open();
doc.Add(table);
htmlWorker.StartDocument();
htmlWorker.Parse(txtReader);
htmlWorker.EndDocument();
}
htmlWorker.Close();
doc.Close();
bPDF = ms.ToArray();
ms.Close();
return bPDF;
}
Here I am calling the above function :
public void GenerateCertificatePDF(List<int> ideaidlist)
{
string HTMLContent = "";
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=" + "Certificates.pdf");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.BinaryWrite(GetPDF(HTMLContent, ideaidlist));
}
When you run your code locally, a file is created:
new FileStream(Certpath , FileMode.CreateNew)
That same file is created on the server when you run the code on the server.
However, you also want to send the bytes of the PDF document to the browser. To achieve this by creating a MemoryStream:
MemoryStream ms = new MemoryStream();
When I search your code for the ms variable, I don't find it anywhere except at the very end:
bPDF = ms.ToArray();
ms.Close();
return bPDF;
In other words: you don't write any bytes to ms; the MemoryStream is empty. This is proven by the fact that you get 0 bytes.
Your code works in the sense that a PDF is written on the disk of the server, but that's not what you want, is it? You want this method to create a PDF in memory and then send its bytes to a server.
To achieve this, you need to remove all references to certPath, the part where you exist if the file exists and the FileStream. Instead, you need to write the PDF to the MemoryStream:
PdfWriter oPdfWriter = PdfWriter.GetInstance(doc, ms);
This is explained by Chris Haas in his answer to this question: iTextSharp - Create new document as Byte[]
When generating a tagged pdf that reuses a PdfTemplate you are presented with this exception:
Template with tagged content could not be used more than once.
Is it not possible in a tagged pdf to produce reusable content or is this just a limitation in iText right now?
void Main()
{
using (var ms = new MemoryStream())
{
var doc = new Document(PageSize.LETTER, 72, 72, 72, 72);
var writer = PdfWriter.GetInstance(doc, ms);
writer.SetTagged();
doc.Open();
var canvas = writer.DirectContent;
PdfTemplate t = canvas.CreateTemplate(6, 6);
var disc = Image.GetInstance(t);
var ol = new iTextSharp.text.List(false);
var li = new iTextSharp.text.ListItem("List Item 1");
var symbol = new Chunk(disc, 0, 0);
li.ListSymbol = symbol;
ol.Add(li);
li = new iTextSharp.text.ListItem("List Item 2");
symbol = new Chunk(disc, 0, 0);
li.ListSymbol = symbol;
ol.Add(li);
doc.Add(ol);
doc.Close();
ms.Flush();
File.WriteAllBytes("d:\\list.pdf", ms.ToArray());
}
}
I have a source PDF with some Free Text Annotations.
I would like to perform a mail merge like function on PDF. I would like to make a copy of the PDF and replace the Free Text Annotation based on some text replacement method.
For simplicity, I have a program that takes the annotations and add "LHC" behind it. Alas, the copy works, but the annotations remains unchanged.
I would have tried to use PdfAnnotation however, I am unsure how to convert from the PdfDictionary to PdfAnnotation
See my code below
string oldFile = "C:\\Temp\\oldFile.pdf";
string newFile = "C:\\Temp\\newFile.pdf";
// open the reader
PdfReader reader = new PdfReader(oldFile);
Rectangle size = reader.GetPageSizeWithRotation(1);
Document document = new Document(size);
// open the writer
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write);
PdfCopy writer = new PdfCopy(document,fs);
document.Open();
// the pdf content
PdfContentByte cb = writer.DirectContent;
// adding Free Text Annotation
for (int pg = 1; pg < reader.NumberOfPages; pg++)
{
PdfDictionary pageDict = reader.GetPageN(pg);
PdfArray annotArray = pageDict.GetAsArray(PdfName.ANNOTS);
for (int i = 0; i < annotArray.Size; ++i)
{
PdfDictionary curAnnot = annotArray.GetAsDict(i);
PdfName contents = new PdfName("Contents");
PdfString str = curAnnot.GetAsString(contents);
String newString = str.ToString() + "LHC";
curAnnot.Remove(contents);
curAnnot.Put(contents, new PdfString(newString));
}
PdfImportedPage page = writer.GetImportedPage(reader, pg);
// PdfImportedPage pageOut = writer.destinationPdfReader(reader, pg);
//cb.AddTemplate(page, 0, 0);
writer.AddPage(page);
PdfAnnotation annot = new PdfAnnotation(writer, new Rectangle(0, 0));
writer.AddAnnotation(annot);
}
document.Close();
fs.Close();
writer.Close();
reader.Close();
References:
http://itextsharp.10939.n7.nabble.com/How-to-edit-annotations-td3352.html
(There is another link in stackoverflow, that I can't find, when I find it I will add it here)
The steps:
Step 1. Create a stamper from a reader.
Step 2. Read all the annotations
Step 3. Delete a set of keys and as a fallback any dictionary items
You now have performed an edit/copy of the annotation and changed the values.
The following is the code:
// Step 1. Create the stamper
string oldFile = "C:\\Temp\\oldFile.pdf";
string newFile = "C:\\Temp\\newFile.pdf";
// open the reader
PdfReader reader = new PdfReader(oldFile);
Rectangle size = reader.GetPageSizeWithRotation(1);
Document document = new Document(size);
// open the writer
// remember to set the page size before opening document
// otherwise the page is already set.
/* chapter02/HelloWorldMetadata.java */
document.Open();
// the pdf content
// cb does not work with stamper
// create the new pagez and add it to the pdf
// this segment of code is meant for writer
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.ReadWrite);
PdfStamper writer = new PdfStamper(reader, fs, reader.PdfVersion, false);
for (int pg = 1; pg < reader.NumberOfPages; pg++)
{
// taken from http://itextsharp.10939.n7.nabble.com/How-to-edit-annotations-td3352.html
PdfDictionary pagedic = reader.GetPageN(pg);
PdfArray annotarray = (PdfArray)PdfReader.GetPdfObject(pagedic.Get(PdfName.ANNOTS));
if (annotarray == null || annotarray.Size == 0)
continue;
// step 2. read all the annotations
foreach (PdfIndirectReference annot in annotarray.ArrayList)
{
PdfDictionary annotationDic = (PdfDictionary)PdfReader.GetPdfObject(annot);
PdfName subType = (PdfName)annotationDic.Get(PdfName.SUBTYPE);
if (subType.Equals(PdfName.TEXT) || subType.Equals(PdfName.FREETEXT))
{
// 3. Change values of different properties of a certain annotation and delete a few keys & dictionaries
annotationDic.Put(PdfName.CONTENTS, new PdfString("These are changed contents", PdfObject.TEXT_UNICODE));
}
PdfString contents = annotationDic.GetAsString(PdfName.CONTENTS);
if (contents != null)
{
String value = contents.ToString();
annotationDic.Put(PdfName.CONTENTS, new PdfString(value));
annotationDic.Remove(PdfName.AP);
List<PdfName> tobeDel = new List<PdfName>();
foreach (PdfName key in annotationDic.Keys)
{
if (key.CompareTo(PdfName.AP) == 0 ||
key.CompareTo(PdfName.RC) == 0 ||
annotationDic.Get(key).IsDictionary())
{
tobeDel.Add(key);
}
}
foreach (PdfName key in tobeDel)
{
annotationDic.Remove(key);
}
}
writer.MarkUsed(annotationDic);
}
if ((pg + 1) < reader.NumberOfPages)
{
document.NewPage();
}
}
// close the streams and voilá the file should be changed :)
writer.Close();
reader.Close();
I have 3 pdfs templates that i Fill out and save to a memorystream them merge them together into 1 pdf into a memorystream. The resulting merged pdf is non flattenned. I tried reading the merged pdf and flattening it but it say "pdf header signature not found". Is there a way to flattened merged pdf from a memorystream.
this is what I tried so far without success.
var mergedPdf = MergePDFs(AllPdfs);
MemoryStream flattenedMergedPdf = new MemoryStream();
PdfReader Finalpdf = new PdfReader(mergedPdf);
PdfStamper StampFinalMerged = new PdfStamper(Finalpdf,flattenedMergedPdf);
StampFinalMerged.FormFlattening=true;
return flattenedMergedPdf;
the method i use to merge the pdfs(found on SO) is below:
public MemoryStream MergePDFs(List<byte[]> pdfFiles)
{
if (pdfFiles.Count > 1)
{
PdfReader finalPdf;
Document pdfContainer;
PdfCopy pdfCopy;
MemoryStream msFinalPdf = new MemoryStream();
finalPdf = new PdfReader(pdfFiles[0]);
pdfContainer = new Document();
pdfCopy = new PdfSmartCopy(pdfContainer, msFinalPdf);
pdfContainer.Open();
for (int k = 0; k < pdfFiles.Count; k++)
{
finalPdf = new PdfReader(pdfFiles[k]);
for (int i = 1; i < finalPdf.NumberOfPages + 1; i++)
{
((PdfSmartCopy)pdfCopy).AddPage(pdfCopy.GetImportedPage(finalPdf, i));
}
pdfCopy.FreeReader(finalPdf);
}
//tried this here but no success
// PdfReader FinalRead = new PdfReader(finalPdf);
//MemoryStream FinalMS = new MemoryStream();
//var finalStamper = new PdfStamper(FinalRead, FinalMS);
//finalStamper.FormFlattening = true;
pdfCopy.CloseStream = false;
pdfCopy.Close();
finalPdf.Close();
//return FinalMS
return msFinalPdf;
}
Any help will be much appreciated. Thanks
You can try another approach to flatten PDF templates first then merge them into a final PDF file:
string newFile = "... path to the merged pdf file ...";
string[] pdfTemplates = new string[3];
string pdfTemplates[0] = "... path to the 1st pdf template ...";
string pdfTemplates[1] = "... path to the 2nd pdf template ...";
string pdfTemplates[2] = "... path to the 3rd pdf template ...";
string[] pdfFiles = new string[3];
string pdfFiles[0] = "... path to the 1st temp pdf file ...";
string pdfFiles[1] = "... path to the 2nd temp pdf file ...";
string pdfFiles[2] = "... path to the 3rd temp pdf file ...";
for (int i = 0; i < 3; i++)
{
PdfReader pdfReader = new PdfReader(pdfTemplates[i]);
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(pdfFiles[i], FileMode.Create));
pdfStamper.FormFlattening = true;
pdfStamper.Close();
}
MergeFiles(newFile, pdfFiles);
for (int i = 0; i < 3; i++)
{
FileInfo fi = new FileInfo(pdfFiles[i]);
fi.Delete();
}
private void MergeFiles(string destinationFile, string[] sourceFiles)
{
try
{
int f = 0;
PdfReader reader = new PdfReader(sourceFiles[f]);
int n = reader.NumberOfPages;
Document document = new Document(reader.GetPageSizeWithRotation(1));
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(destinationFile, FileMode.Create));
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
int rotation;
while (f < sourceFiles.Length)
{
int i = 0;
while (i < n)
{
i++;
document.SetPageSize(reader.GetPageSizeWithRotation(i));
document.NewPage();
page = writer.GetImportedPage(reader, i);
rotation = reader.GetPageRotation(i);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
}
else
{
cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
}
f++;
if (f < sourceFiles.Length)
{
reader = new PdfReader(sourceFiles[f]);
n = reader.NumberOfPages;
}
}
document.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
I have a PDF that has a plugin control on one page. I need to merge it with another pdf but when I do, the plugin is redendered as a blank rectangle. Is there a way to merge and preserve the plugin control? If important, the plugin is a Dessault Systemes 3D Via Composer Player control as installed from http://www.3ds.com/products/3dvia/3dvia-composer/resource-center/
The code I'm using is simple writer getinstance, contentbyte directcontent, getimportedpage, addtemplate. Nothing fancy.
FileStream docStream = new FileStream(#"C:\Temp\Merged.pdf", FileMode.Create);
Document newDocument = new Document(PageSize.A4.Rotate());
PdfWriter pdfWriter = PdfWriter.GetInstance(newDocument, docStream);
try
{
newDocument.Open();
PdfContentByte pdfContentByte = pdfWriter.DirectContent;
newDocument.NewPage();
PdfReader mainPage = new PdfReader(#"C:\Temp\PageWithPlugin.pdf");
PdfImportedPage importedPage1 = pdfWriter.GetImportedPage(mainPage, 1);
pdfContentByte.AddTemplate(importedPage1, 0, 0);
mainPage.Close();
PdfReader smgPages = new PdfReader(#"C:\Temp\MorePages.pdf");
for (int page = 1; page <= smgPage.NumberOfPages; page++)
{
newDocument.NewPage();
PdfImportedPage importedPage = pdfWriter.GetImportedPage(smgPages, page);
pdfContentByte.AddTemplate(importedPage, 0, 0);
}
smgPages.Close();
}
finally
{
docStream.Flush();
if (newDocument != null)
newDocument.Close();
docStream.Close();
}
Give this a try.
List<byte[]> fileList = new List<byte[]>();
using (FileStream fileSteam = File.OpenRead((#"C:\Temp\PageWithPlugin.pdf")))
{
Byte[] byteArray = new byte[fileSteam.Length];
fileSteam.Read(byteArray, 0, byteArray.Length);
fileList.Add(byteArray);
}
using (FileStream fileSteam = File.OpenRead((#"C:\Temp\MorePages.pdf")))
{
Byte[] byteArray = new byte[fileSteam.Length];
fileSteam.Read(byteArray, 0, byteArray.Length);
fileList.Add(byteArray);
}
using(MemoryStream msOutput = new MemoryStream())
{
PdfReader pdfFile = new PdfReader(fileList[0]);
Document doc = new Document();
PdfWriter pCopy = new PdfSmartCopy(doc, msOutput);
doc.Open();
for (int k = 0; k < fileList.Count; k++)
{
for (int i = 1; i < pdfFile.NumberOfPages + 1; i++)
{
pdfFile = new PdfReader(fileList[k]);
((PdfSmartCopy)pCopy).AddPage(pCopy.GetImportedPage(pdfFile, i));
pCopy.FreeReader(pdfFile);
}
}
pdfFile.Close();
pCopy.Close();
doc.Close();
fileList.Clear();
byte[] form = msOutput.ToArray();
using (FileStream fileSteam = new FileStream(#"C:\Temp\Merged.pdf", FileMode.Create))
{
fileStream.Write(form, 0, form.Length);
}
}
Not to look a gift horse in the mouth but... In case anyone else uses the solution, there is a small problem with the k loop. The numberofpages would be off by one document after the zeroth one and the pdfReader keeps getting freed and reread for every page, which isn't necessary. I think this is an improvement for that part of the code:
using (MemoryStream msOutput = new MemoryStream())
{
Document doc = new Document();
PdfWriter pCopy = new PdfCopy(doc, msOutput);
doc.Open();
for (int k = 0; k < fileList.Count; k++)
{
PdfReader pdfFile = new PdfReader(fileList[k]);
for (int i = 1; i < pdfFile.NumberOfPages + 1; i++)
{
((PdfCopy)pCopy).AddPage(pCopy.GetImportedPage(pdfFile, i));
}
pCopy.FreeReader(pdfFile);
pdfFile.Close();
}
pCopy.Close();
doc.Close();
fileList.Clear();