iTextSharp Html Arabic Mixed Content to PDF - pdf

We are in project for educational domain, where we are looking for importing Arabic content, Images (uri/base64 crypted texts), html tables.
We are facing issue while executing using HtmlWorker with Stream data. It throws error as "the document has no pages"
string str="html content contains arabic font texts/images";
using (MemoryStream ms = new MemoryStream())
{
using (iTextSharp.text.Document document = new iTextSharp.text.Document(iTextSharp.text.PageSize.A4, 25, 25, 30, 30))
{
using (iTextSharp.text.pdf.PdfWriter writer = iTextSharp.text.pdf.PdfWriter.GetInstance(document,ms))
{
using (var htmlWorker = new iTextSharp.text.html.simpleparser.HTMLWorker(document))
{
//HTMLWorker doesn't read a string directly but instead needs a TextReader (which StringReader subclasses)
using (var sr = new StreamReader(str)) /// We are facing issue at this juncture where it throws error.
{
//Parse the HTML
htmlWorker.Parse(sr);
}
}
document.Close();
writer.Close();
ms.Close();
Response.ContentType = "pdf/application";
Response.AddHeader("content-disposition", "attachment;filename=First_PDF_document.pdf");
Response.OutputStream.Write(ms.ToArray(), 0, ms.ToArray().Length);
}
}
}
Could you please help us regarding this?
Now,
I have tried with other approach:
using (var htmlWorker = new iTextSharp.text.html.simpleparser.HTMLWorker(document))
{
using (Stream s = GenerateStreamFromString(str))
{
using (var srt = new StreamReader(s))
{
//Parse the HTML
htmlWorker.Parse(srt); //this line throws error now.
}
}
}
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
Error message:
"The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters."

Related

Fill XFA without breaking usage rights

I have an XFA form that I can successfully fill in by extracting the XML modifying and writing back. Works great if you have the full Adobe Acrobat, but fails with Adobe Reader. I have seen various questions on the same thing with answers but they were some time ago so updating an XFA that is readable by Adobe Reader may no longer be doable?
I use this code below and I've utilised the StampingProperties of append as in the iText example but still failing. I'm using iText 7.1.15.
//open file and write to temp one
PdfDocument pdf = new(new PdfReader(FileToProcess), new PdfWriter(NewPDF), new StampingProperties().UseAppendMode());
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdf, true);
XfaForm xfa = form.GetXfaForm();
XElement node = xfa.GetDatasetsNode();
IEnumerable<XNode> list = node.Nodes();
foreach (XNode item in list)
{
if (item is XElement element && "data".Equals(element.Name.LocalName))
{
node = element;
break;
}
}
XmlWriterSettings settings = new() { Indent = true };
using XmlWriter writer = XmlWriter.Create(XMLOutput, settings);
{
node.WriteTo(writer);
writer.Flush();
writer.Close();
}
//We now how to strip an extra xfa line if updating
if(update)
{
string TempXML= CSTrackerHelper.MakePath($"{AppContext.BaseDirectory}Temp", $"{Guid.NewGuid()}.XML");
StreamReader fsin = new(XMLOutput);
StreamWriter fsout = new(TempXML);
string linedata = string.Empty;
int cnt = 0;
while (!fsin.EndOfStream)
{
if (cnt != 3 && linedata != string.Empty)
{
fsout.WriteLine(linedata);
}
linedata = fsin.ReadLine();
cnt++;
}
fsout.Close();
fsin.Close();
XMLOutput = TempXML;
}
xlogger.Info("Populating pdf fields");
//Now loop through our field data and update the XML
XmlDocument xmldoc = new();
xmldoc.Load(XMLOutput);
XmlNamespaceManager xmlnsManager = new(xmldoc.NameTable);
xmlnsManager.AddNamespace("xfa", #"http://www.xfa.org/schema/xfa-data/1.0/");
string[] FieldValues;
string[] MultiNodes;
foreach (KeyValuePair<string, DocumentFieldData> v in DocumentData.FieldData)
{
if (!string.IsNullOrEmpty(v.Value.Field))
{
FieldValues = v.Value.Field.Contains(";") ? v.Value.Field.Split(';') : (new string[] { v.Value.Field });
foreach (string FValue in FieldValues)
{
XmlNodeList aNodes;
if (FValue.Contains("{"))
{
aNodes = xmldoc.SelectNodes(FValue.Substring(0, FValue.LastIndexOf("{")), xmlnsManager);
if (aNodes.Count > 1)
{
//We have a multinode
MultiNodes = FValue.Split('{');
int NodeIndex = int.Parse(MultiNodes[1].Replace("}", ""));
aNodes[NodeIndex].InnerText = v.Value.Data;
}
}
else
{
aNodes = xmldoc.SelectNodes(FValue, xmlnsManager);
if (aNodes.Count >= 1)
{
aNodes[0].InnerText = v.Value.Data;
}
}
}
}
}
xmldoc.Save(XMLOutput);
//Now we've updated the XML apply it to the pdf
xfa.FillXfaForm(new FileStream(XMLOutput, FileMode.Open, FileAccess.Read));
xfa.Write(pdf);
pdf.Close();
FYI I've also tried to set a field directly also with the same results.
PdfReader preader = new PdfReader(source);
PdfDocument pdfDoc=new PdfDocument(preader, new PdfWriter(dest), new StampingProperties().UseAppendMode());
PdfAcroForm pdfForm = PdfAcroForm.GetAcroForm(pdfDoc, true);
XfaForm xform = pdfForm.GetXfaForm();
xform.SetXfaFieldValue("VRM[0].CoverPage[0].Wrap2[0].Table[0].CSID[0]", "Test");
xform.Write(pdfForm);
pdfDoc.Close();
If anyone has any ideas it would be appreciated.
Cheers
I ran into a very similar issue. I was attempting to auto fill an XFA that was password protected while not breaking the certificate or usage rights (it allowed filling). iText7 seems to have made this not possible for legal/practical reasons, however it is still very much possible with iText5. I wrote the following working codeusing iTextSharp (C# version if iText5):
using iTextSharp.text;
using iTextSharp.text.pdf;
string pathToRead = "/Users/home/Desktop/c#pdfParser/encrypted_empty.pdf";
string pathToSave = "/Users/home/Desktop/c#pdfParser/xfa_encrypted_filled.pdf";
string data = "/Users/home/Desktop/c#pdfParser/sample_data.xml";
FillByItextSharp5(pathToRead, pathToSave, data);
static void FillByItextSharp5(string pathToRead, string pathToSave, string data)
{
using (FileStream pdf = new FileStream(pathToRead, FileMode.Open))
using (FileStream xml = new FileStream(data, FileMode.Open))
using (FileStream filledPdf = new FileStream(pathToSave, FileMode.Create))
{
PdfReader.unethicalreading = true;
PdfReader pdfReader = new PdfReader(pdf);
PdfStamper stamper = new PdfStamper(pdfReader, filledPdf, '\0', true);
stamper.AcroFields.Xfa.FillXfaForm(xml, true);
stamper.Close();
pdfReader.Close();
}
}
PdfStamper stamper = new PdfStamper(pdfReader, filledPdf, '\0', true)
you have to use this line.

Converting dynamic cshtml to pdf using iTextSharp?

I was using Rotativa for the conversion of html to pdf. My whole aim was to send receipt as pdf to customers emailid. It was working well locally but when deployed in GoDaddy Server its not supported. So I am planning to generate the pdf using iTextSharp(Viewers Opinion is also invited).
Code written for the generation of pdf in Rotativa:
public ActionResult GetPdfReceipt(int RegId)
{
var actionPDF = new Rotativa.ActionAsPdf("GetPdfReceipt", new { RegId = regId })
{
FileName = "Receipt.pdf"
};
//Dynamic student receipt pdf
var byteArrayDynamic = actionPDF.BuildPdf(ControllerContext);
}
public ActionResult GetPdfReceipt(int RegId)
{
try
{
var _mdlReceiptPdf = new ReceiptPdfVM
{
...
...
};
return View("Receipts", _mdlReceiptPdf);
}
catch (Exception ex)
{
return View("");
}
}
I have gone through some of the codes for generating pdf using iTextSharp and it was as follows
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.Charset = "";
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=LoginReportPerDay.pdf");
StringWriter sWriter = new StringWriter();
HtmlTextWriter hTWriter = new HtmlTextWriter(sWriter);
GridView1.RenderControl(hTWriter);
StringReader sReader = new StringReader(sWriter.ToString());
Document pdf = new Document(PageSize.A4);
HTMLWorker worker = new HTMLWorker(pdf);
PdfWriter.GetInstance(pdf, HttpContext.Current.Response.OutputStream);
pdf.Open();
worker.Parse(sReader);
pdf.Close();
HttpContext.Current.Response.Write(pdf);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
How can I use the above code to render dynamically generated Receipt View pdf array bytes.

Corrupted pdf after some compression using iTextSharp

The following code creates a .pdf first which is okay and looks perfect, I have taken the rest of the code (which makes the compression) from another post on this site. The problem is that the compressed.pdf file is 1kb and acrobat says the file is damaged and cannot be repaired. I have never made a pdf compressor before. Please, take a look at my code and if it is possible offer some corrections to make it working.
private void btnEndScan_Click(object sender, EventArgs e)
{
Document doc1 = new Document(PageSize.A4, 0, 0, 0, 0);
string filename = "Prot_" + label.Text + ".pdf";
try
{
PdfWriter.GetInstance(doc1, new FileStream("C:/" + filename, FileMode.Create));
doc1.Open();
for (int i = 0; i < imageArray.Length; i++)
{
iTextSharp.text.Image pic = iTextSharp.text.Image.GetInstance(imageArray[i], System.Drawing.Imaging.ImageFormat.Bmp);
pic.ScalePercent(36f);
doc1.Add(pic);
}
}
catch (Exception ex)
{
MessageBox.Show("Error creating pdf file" + ex);
}
finally
{
doc1.Close();
PdfReader reader = new PdfReader("C:/" + filename);
string filepath = "C:/compressed/" + filename;
using (MemoryStream ms = new MemoryStream())
{
PdfStamper stamper = new PdfStamper(reader, ms, PdfWriter.VERSION_1_5);
PdfWriter writer = stamper.Writer;
writer.CompressionLevel = PdfStream.BEST_COMPRESSION;
reader.RemoveFields();
reader.RemoveUnusedObjects();
stamper.Reader.RemoveUnusedObjects();
stamper.SetFullCompression();
stamper.Writer.SetFullCompression();
byte[] compressed = ms.ToArray();
reader.Close();
stamper.Close();
using (FileStream fs = File.Create("C:/compressed/compressed.pdf"))
{
fs.Write(compressed, 0, (int)compressed.Length);
fs.Close();
}
}
}
}
You are cutting the file too short.
Take a look at these lines:
byte[] compressed = ms.ToArray();
reader.Close();
stamper.Close();
They should be ordered like this:
stamper.Close();
reader.Close();
byte[] compressed = ms.ToArray();
The order in your code is wrong because:
You should close the reader after the stamper, because the stamper may need access to the reader while closing.
The file is only complete when you close the stamper. At the moment you create the byte[] not all the PDF data has been written yet. The file is incomplete.
Because of the incomplete byte[], you are removing a substantial part of your file when you do this:
fs.Write(compressed, 0, (int)compressed.Length);
The value of compressed.Length is too short. Your actual file has a larger file size.

How to convert a file to bytes and bytes to a file in mvc4

I am using MVC4. My requirement is:
I have to convert the file into byte array and save to database varbinary column.
For this I written code like below:
public byte[] Doc { get; set; }
Document.Doc = GetFilesBytes(PostedFile);
public static byte[] GetFilesBytes(HttpPostedFileBase file)
{
MemoryStream target = new MemoryStream();
file.InputStream.CopyTo(target);
return target.ToArray();
}
I am downloading the file by using the following code:
public ActionResult Download(int id)
{
List<Document> Documents = new List<Document>();
using (SchedulingServiceInstanceManager facade = new SchedulingServiceInstanceManager("SchedulingServiceWsHttpEndPoint"))
{
Document Document = new Document();
Document.DMLType = Constant.DMLTYPE_SELECT;
Documents = facade.GetDocuments(Document);
}
var file = Documents.FirstOrDefault(f => f.DocumentID == id);
return File(file.Doc.ToArray(), "application/octet-stream", file.Name);
}
when I am downloading pdf file then it is showing message as "There was an error opening this document. The file is damaged and could not be repaired."
Any thing else I need to do?
I tried with the following code but no luck
return File(file.Doc.ToArray(), "application/pdf", file.Name);
Please help me to solve the issue.
Thanks in advance.
Please try as in below code in your controller
FileStream stream = File.OpenRead(#"c:\path\to\your\file\here.txt");
byte[] fileBytes= new byte[stream.Length];
stream.Read(fileBytes, 0, fileBytes.Length);
stream.Close();
//Begins the process of writing the byte array back to a file
using (Stream file = File.OpenWrite(#"c:\path\to\your\file\here.txt"))
{
file.Write(fileBytes, 0, fileBytes.Length);
}
It may helps you...

ă ş ţ chars aren't rendered by iTextSharp

I use iTextSharp in asp.net mvc to return pdf like this:
public class Pdf : IPdf
{
public FileStreamResult Make(string s)
{
using (var ms = new MemoryStream())
{
using (var document = new Document())
{
PdfWriter.GetInstance(document, ms);
document.Open();
using (var str = new StringReader(s))
{
var htmlWorker = new HTMLWorker(document);
htmlWorker.Parse(str);
}
document.Close();
}
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=MyPdfName.pdf");
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.OutputStream.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
HttpContext.Current.Response.OutputStream.Flush();
HttpContext.Current.Response.End();
return new FileStreamResult(HttpContext.Current.Response.OutputStream, "application/pdf");
}
}
}
the problem is that characters like: ă ţ ş are not rendered
yetanothercoder is correct. That would do the trick... but there's another very similar question which I answered in a bit more detail:
iText + HTMLWorker - How to change default font?
Please try the folowing:
var unicodeFont = iTextSharp.text.pdf.BaseFont.CreateFont(iTextSharp.text.FontFactory.TIMES_ROMAN, iTextSharp.text.pdf.BaseFont.CP1250, iTextSharp.text.pdf.BaseFont.EMBEDDED);
acroFields.SetFieldProperty("txtContractorBirthPlace", "textfont", unicodeFont, null);
And it should do it for you.
You have to add the field property to every field you wish to have diacritics.
Baftă!