I'm trying to create a PDF from HTML, and am using iTextSharp for that. From my reading, the license that covers the newer versions of iTextSharp would require me to make the source code available. We can't do that, so we're using version 4, which is under the LGPL.
I'm trying to get a footer to appear along with the HTML, but it's not working for some reason. I've tried removing the HTML and just using text. Just putting a chunk in the footer. Multiple pages vs single pages. Hopefully I'm just missing something easy, but from the examples I've seen it should be super easy.
using (MemoryStream ms = new MemoryStream())
{
Document doc = new Document(PageSize.LETTER, 35,35,35,70);
var font = FontFactory.GetFont("arial", 8f);
font.Color = Color.BLACK;
var chunk = new Chunk("Footer", font);
var phrase = new Phrase(chunk);
var footer = new HeaderFooter(phrase, true);
footer.Alignment = 1;
footer.Border = Rectangle.NO_BORDER;
doc.Footer = footer;
//doc.Footer = new HeaderFooter(new Phrase("Footer"),false);
var writer = PdfWriter.GetInstance(doc, ms);
var htmlWorker = new HTMLWorker(doc);
using (var sr = new StringReader(html))
{
doc.Open();
doc.Add(new Chunk("Text"));
//htmlWorker.Parse(sr);
doc.Close();
}
return ms.ToArray();
}
Watch your HeaderFooter ctor. The signature your are using might lead to setting the header text only.
Anyway maybe use the PdfWriter.PageEvent and some class deriving from PdfPageEventHelper to implement header and footer (instead of HeaderFooter())
Related
I have to convert this Html tempelate written in notepad into PDF using itextsharp
<Body>
<h3>Hello</h3><img src="https://i.stack.imgur.com/nMwn1.png">
</Body>
Install a package called iTextSharp through Nuget Package.
using iTextSharp.text;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
public class PdfController : Controller
{
[Route("/htmlpdf")]
public FileStreamResult DownloadPDF()
{
string HTMLContent = "Hello <b>World</b>";// Put your html tempelate here
MemoryStream ms = new MemoryStream();
TextReader txtReader = new StringReader(HTMLContent);
// 1: create object of a itextsharp document class
Document doc = new Document(PageSize.A4, 25, 25, 25, 25);
// 2: we create a itextsharp pdfwriter that listens to the document and directs a XML-stream to a file
PdfWriter PdfWriter = PdfWriter.GetInstance(doc, ms);
PdfWriter.CloseStream = false;
// 3: we create a worker parse the document
HTMLWorker htmlWorker = new HTMLWorker(doc);
// 4: we open document and start the worker on the document
doc.Open();
htmlWorker.StartDocument();
// 5: parse the html into the document
htmlWorker.Parse(txtReader);
// 6: close the document and the worker
htmlWorker.EndDocument();
htmlWorker.Close();
doc.Close();
ms.Flush(); //Always catches me out
ms.Position = 0; //Not sure if this is required
return File(ms, "application/pdf", "HelloWorld.pdf");
}
}
Test of result
//You can also use this free "SelectPdf" library for basic use
SelectPdf.HtmlToPdf converter = new SelectPdf.HtmlToPdf();
//SelectPdf.PdfDocument doc = converter.ConvertUrl("https://google.com");
SelectPdf.PdfDocument doc = converter.ConvertHtmlString(HTMLContent.ToString());
doc.Save("test.pdf");
I am trying to create a pdf using iTextSharp and it did it. But it is also printing html tags in the pdf instead of making it as a design around text
Document pdfDoc = new Document(PageSize.A4, 25, 10, 25, 10);
PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDoc, Response.OutputStream);
pdfDoc.Open();
Paragraph Text = new Paragraph("<b>Hiii</b>");
pdfDoc.Add(Text);
pdfWriter.CloseStream = false;
pdfDoc.Close();
Response.Buffer = true;
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=Example.pdf");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Write(pdfDoc);
Response.End();
}
Output of this is Hiii with bold tags the way it is looking in the code , but I want Hiii
You expect iText to parse HTML tags in the text of its layout elements (Paragraph, ...) but iText does not do so. To get "Hiii" instead of "<b>Hiii</b>" in iText you essentially have two options:
Explicitly use a bold font for bold text and a normal font for regular text.
var phrase = new Phrase();
phrase.Add(new Chunk("REASON(S) FOR CANCELLATION:", boldFont));
phrase.Add(new Chunk(" See Statutoryreason(s) designated by Code No(s) 1 on the reverse side hereof", normalFont));
This is explained in detail in the answers to the question #Ratheesh pointed to in a comment. In particular you can get a bold font either by explicitly naming a bold font, e.g.
var normalFont = FontFactory.GetFont(FontFactory.HELVETICA, 12);
var boldFont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 12);
Or you can ask iText to find a bold font of a font family; if iText cannot find it, it will use create a poor-man's-bold version of the regular font by drawing a line along the outlines of the font glyphs:
Font verdanaBold = FontFactory.GetFont("Verdana", 7f, Font.BOLD);
Use the XMLWorker to parse XHTML and generate accordingly styled layout elements from it.
This also has been explained in many answers on stack overflow, see for example the CreateSimpleHtmlParagraph method in this answer:
private static Phrase CreateSimpleHtmlParagraph(String text)
{
var p = new Phrase();
var mh = new MyElementHandler();
using (TextReader sr = new StringReader("<html><body><p>" + text + "</p></body></html>"))
{
XMLWorkerHelper.GetInstance().ParseXHtml(mh, sr);
}
foreach (var element in mh.elements)
{
foreach (var chunk in element.Chunks)
{
p.Add(chunk);
}
}
return p;
}
(The helper class MyElementHandler is shown in the referenced answer.)
I have to add (register, embed) font to a PDF programmatically.
I tried with a lot of utilities like ghostscript or itextsharp but i did not manage to solve the problem.
For example in a situation like this one:
I would like to add Courier-Bold and get this situation:
I just created a project using iTextSharp v5.5.9 via NuGet and used the following code:
const string PdfLocation = #"C:\fakepath\output.pdf";
static void Main(string[] args)
{
using (var pdfDoc = new Document())
using (var fs = new FileStream(PdfLocation, FileMode.OpenOrCreate))
using (var writer = PdfWriter.GetInstance(pdfDoc, fs))
{
pdfDoc.Open();
var font = FontFactory.GetFont(FontFactory.COURIER_BOLD);
// Doesn't use font
var paragraph = new Paragraph("LINE 1");
paragraph.Font = font;
pdfDoc.Add(paragraph);
// Doesn't use font
var paragraph2 = new Paragraph();
paragraph2.Add("LINE 2");
paragraph2.Font = font;
pdfDoc.Add(paragraph2);
// Does use font
var paragraph3 = new Paragraph();
paragraph3.Font = font;
paragraph3.Add("LINE 3"); // This must be done after setting the font
pdfDoc.Add(paragraph3);
var cb = writer.DirectContent;
pdfDoc.Close();
}
}
I discovered that you need to set the font first before you write the text. The following code outputs the PDF with the following properties. I didn't get the TrueType requirement out of this, but perhaps this will set you in the right direction.
Where I'm using paragraph and paragraph2 will use the default font which was Helvetica for me because I'm setting the font after I'm setting the text. Order does matter!
The documentation for this certainly needs to be expanded upon...
When I export ARABIC data into pdf.Microsoft adobereader showing error.Adobe reader could not open file because it is either not a supported file.My code is following asp.net c#.Guide me
protected void btnExport_Click(object sender, EventArgs e)
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=TestPage.pdf");
Document doc = new Document(PageSize.LETTER);
doc.Open();
//Sample HTML
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(#"<p>This is a test: <strong>مسندم</strong></p>");
//Path to our font
string arialuniTff = Server.MapPath("~/tradbdo.TTF");
//Register the font with iTextSharp
iTextSharp.text.FontFactory.Register(arialuniTff);
//Create a new stylesheet
iTextSharp.text.html.simpleparser.StyleSheet ST = new iTextSharp.text.html.simpleparser.StyleSheet();
//Set the default body font to our registered font's internal name
ST.LoadTagStyle(HtmlTags.BODY, HtmlTags.FACE, "Traditional Arabic Bold");
//Set the default encoding to support Unicode characters
ST.LoadTagStyle(HtmlTags.BODY, HtmlTags.ENCODING, BaseFont.IDENTITY_H);
//Parse our HTML using the stylesheet created above
List<IElement> list = HTMLWorker.ParseToList(new StringReader(stringBuilder.ToString()), ST);
//Loop through each element, don't bother wrapping in P tags
foreach (var element in list)
{
doc.Add(element);
}
doc.Close();
Response.Write(doc);
Response.End();
}
I found the following article which shows how to correctly export and display Arabic content via the iTextSharp library: http://geekswithblogs.net/JaydPage/archive/2011/11/02/using-itextsharp-to-correctly-display-hebrew--arabic-text-right.aspx.
Here is the code sample that you can try:
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
public void WriteDocument()
{
//Declare a itextSharp document
Document document = new Document(PageSize.A4);
//Create our file stream and bind the writer to the document and the stream
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(#"C:\Test.Pdf", FileMode.Create));
//Open the document for writing
document.Open();
//Add a new page
document.NewPage();
//Reference a Unicode font to be sure that the symbols are present.
BaseFont bfArialUniCode = BaseFont.CreateFont(#"C:\ARIALUNI.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
//Create a font from the base font
Font font = new Font(bfArialUniCode, 12);
//Use a table so that we can set the text direction
PdfPTable table = new PdfPTable(1);
//Ensure that wrapping is on, otherwise Right to Left text will not display
table.DefaultCell.NoWrap = false;
//Create a regex expression to detect hebrew or arabic code points
const string regex_match_arabic_hebrew = #"[\u0600-\u06FF,\u0590-\u05FF]+";
if (Regex.IsMatch("مسندم", regex_match_arabic_hebrew, RegexOptions.IgnoreCase))
{
table.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
}
//Create a cell and add text to it
PdfPCell text = new PdfPCell(new Phrase("مسندم", font));
//Ensure that wrapping is on, otherwise Right to Left text will not display
text.NoWrap = false;
//Add the cell to the table
table.AddCell(text);
//Add the table to the document
document.Add(table);
//Close the document
document.Close();
//Launch the document if you have a file association set for PDF's
Process AcrobatReader = new Process();
AcrobatReader.StartInfo.FileName = #"C:\Test.Pdf";
AcrobatReader.Start();
}
The iTextSharp.text.Document is a class used to help bridge human concepts like Paragraph and Margin into PDF concepts. The bridge part is important. It is not a PDF file in any way so it should never be treated as a PDF. Doing so would be like treating System.Drawing.Graphics as if it were an image. This leads to one of your problems on the second to last line of code that tries to treat the Document as if it were a PDF by sending it directly to the output stream:
//This won't work
Response.Write(doc);
You will find many, many tutorials out there that do this and they are all wrong. Fortunately (or unfortunately), PDF is forgiving and allows junk data at the end so only a handful of PDF fail and people assume there was some other problem.
Your other problem is that you are missing a PdfWriter. If Document is the bridge, PdfWriter is the actual construction worker that puts that PDF together. It, however, is also not a PDF. Instead, it needs to be bound to a stream like a file, in-memory or the HttpResponse.OutputStream.
Below is some code that shows this off. I very strongly recommend separating your PDF logic from your ASPX logic. Do all of you PDF stuff first and get an actual "something" that represents a PDF, then do something with it.
At the beginning we declare a byte array that we'll fill in later. Next we create a System.IO.MemoryStream that will be used to write the PDF to. After creating the Document we then create a PdfWriter that's bound to the Document and our stream. Your internal code is the same and although I didn't test it it appears correct. Right before we're done with our MemoryStream we grab the active bytes into our byte array. Lastly we use the BinaryWrite() method to send our raw binary PDF to the requesting client.
//At the end of this bytes will hold a byte array representing an actual PDF file
Byte[] bytes;
//Create a simple in-memory stream
using (var ms = new MemoryStream()){
using (var doc = new Document()) {
//Create a new PdfWriter bound to our document and the stream
using (var writer = PdfWriter.GetInstance(doc, ms)) {
doc.Open();
//This is unchanged from the OP's code
//Sample HTML
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(#"<p>This is a test: <strong>مسندم</strong></p>");
//Path to our font
string arialuniTff = Server.MapPath("~/tradbdo.TTF");
//Register the font with iTextSharp
iTextSharp.text.FontFactory.Register(arialuniTff);
//Create a new stylesheet
iTextSharp.text.html.simpleparser.StyleSheet ST = new iTextSharp.text.html.simpleparser.StyleSheet();
//Set the default body font to our registered font's internal name
ST.LoadTagStyle(HtmlTags.BODY, HtmlTags.FACE, "Traditional Arabic Bold");
//Set the default encoding to support Unicode characters
ST.LoadTagStyle(HtmlTags.BODY, HtmlTags.ENCODING, BaseFont.IDENTITY_H);
//Parse our HTML using the stylesheet created above
List<IElement> list = HTMLWorker.ParseToList(new StringReader(stringBuilder.ToString()), ST);
//Loop through each element, don't bother wrapping in P tags
foreach (var element in list) {
doc.Add(element);
}
doc.Close();
}
}
//Right before closing the MemoryStream grab all of the active bytes
bytes = ms.ToArray();
}
//We now have a valid PDF and can do whatever we want with it
//In this case, use BinaryWrite to send it directly to the requesting client
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=TestPage.pdf");
Response.BinaryWrite(bytes);
Response.End();
I have an xml and mapping to pdf form field using iTextsharp. It works well for single record. But when multiple records are there, it does not add 2nd record in the output pdf. Here is a code
public static void GeneratePdf(string sin, List<XElement> elements)
{
var pdfTemplate = HttpContext.Current.Server.MapPath("~/input.pdf");
var newFile = HttpContext.Current.Server.MapPath("~/output.pdf");
var pdfReader = new PdfReader(pdfTemplate);
var pdfStamper = new PdfStamper(pdfReader, new FileStream(
newFile, FileMode.Create));
foreach (var element in elements)
{
foreach (var elem in elements.Elements())
{
pdfStamper.AcroFields.SetField(elem.Name.ToString(), (string)elem);
}
}
pdfStamper.FormFlattening = false;
pdfStamper.Close();
}
Your question is unclear because you're telling us nothing about the nature of your form.
IF YOU'RE FORM IS BASED ON ACROFORM TECHNOLOGY
Please take a look at this video tutorial: http://itextpdf.com/codenvy_webapp
You can find the examples used in this tutorial here: https://github.com/blowagie/itextsamples
You can also find the standalone examples here: http://itextpdf.com/sandbox/acroforms/reporting
Note that there's an example "HOW NOT TO DO IT". Make sure you use the correct example: FillFlattenMerge2
Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
document.open();
ByteArrayOutputStream baos;
PdfReader reader;
PdfStamper stamper;
AcroFields fields;
while (myApp.hasMoreRecords()) {
baos = new ByteArrayOutputStream();
reader = new PdfReader(SRC);
stamper = new PdfStamper(reader, baos);
fields = stamper.getAcroFields();
myApp.processNextRecord(fields);
stamper.setFormFlattening(true);
stamper.close();
reader.close();
// add the PDF to PdfCopy
reader = new PdfReader(baos.toByteArray());
copy.addDocument(reader);
reader.close();
}
document.close();
Note that myApp is an instance of a custom class you could write to loop over a record set. You'd implement a method hasMoreRecords() and processNextRecord() to loop over the records and process them one by one.
IF YOUR FORM IS BASED ON THE XML FORMS ARCHITECTURE
In this case, you're using the wrong methods. You can't fill out a dynamic form using the setField() method. The fact that it works for one record is a sign that your form is either an AcroForm or a hybrid XFA form. In both cases you can NOT achieve what you want without changing your form into a pure, dynamic XFA form.
As soon as you have a pure, dynamic XFA form, you need to use this code:
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader,
new FileOutputStream(dest));
AcroFields form = stamper.getAcroFields();
XfaForm xfa = form.getXfa();
xfa.fillXfaForm(new FileInputStream(xml));
stamper.close();
reader.close();
I repeat: this code snippet will only work if you have a correct form. Elements in your question indicate that this is not the case. If your form isn't a dynamic XFA form, you won't find any software that can achieve what you want!!!
Watch these movies for more info: http://itextpdf.com/product/xfa_worker