I am working on creating a pdf from html template file where i defined placeholders. i am able to replace the place holders with some text like
content.Replace(["Product_ID"],TextBox1.text);
is there any way i can also replace a placeholder with a checkbox(with either checked or unchecked depending on a condition) ?
Create two images, one for the checkbox "checked" state, and "unchecked", and use an IF statement to get the right image: i.e:
string pdfpath = Server.MapPath("PDFs");
string imagepath = Server.MapPath("Images");
Document doc = new Document();
try
{
PdfWriter.GetInstance(doc, new FileStream(pdfpath + "/Images.pdf", FileMode.Create));
doc.Open();
doc.Add(new Paragraph("GIF"));
Image gif;
if (chkBoxExample.Checked)
{
gif = Image.GetInstance(imagepath + "/checked.gif");
}
else
{
gif = Image.GetInstance(imagepath + "/unchecked.gif");
}
doc.Add(gif);
}
finally
{
doc.Close();
}
Related
I am building a desktop application that generates a .docx document with data that I pull from an SQLite database. I am using Xceed's DocX Nuget package to build it, and I can write text without any complication.
However, my application needs to place an image ON THE HEADER. I pull the image with ease from the database, but I fail when I try to send it to the .docx file.
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "Documento Word (*.docx)|*.docx",
FileName = "Documento " + obj_eObra.ProcesoDeSeleccion + ".docx",
DefaultExt = ".docx"
};
if (saveFileDialog.ShowDialog() == true)
{
DocX document = DocX.Create(saveFileDialog.FileName);
Stream Logo = new MemoryStream(obj_eEmpresa.Logo);
Xceed.Document.NET.Image image = document.AddImage(Logo);
document.AddHeaders();
document.AddFooters();
// Force the first page to have a different Header and Footer.
document.DifferentFirstPage = true;
// Force odd & even pages to have different Headers and Footers.
document.DifferentOddAndEvenPages = true;
// Insert a Paragraph into the first Header.
document.Headers.First.Images.Add(image);
// Insert a Paragraph into this document.
var p = document.InsertParagraph();
// Append some text and add formatting.
p.Append("This is a simple formatted red bold paragraph")
.Font(new Font("Arial"))
.FontSize(25)
.Color(System.Drawing.Color.Red)
.Bold()
.Append(" containing a blue italic text.").Font(new Font("Times New Roman")).Color(System.Drawing.Color.Blue).Italic()
.SpacingAfter(40);
document.Save();
}
I expect to see a file that has an image in the header and the following paragraph in the body of the document:
"This is a simple formatted red bold paragraph containing a blue italic text.
But my file only has text, no image.
I did it! Here's the solution
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "Documento Word (*.docx)|*.docx",
FileName = "Documento " + obj_eObra.ProcesoDeSeleccion + ".docx",
DefaultExt = ".docx"
};
if (saveFileDialog.ShowDialog() == true)
{
DocX document = DocX.Create(saveFileDialog.FileName);
Stream Logo = new MemoryStream(obj_eEmpresa.Logo);
Xceed.Document.NET.Image image = document.AddImage(Logo);
document.AddHeaders();
document.AddFooters();
// Force the first page to have a different Header and Footer.
document.DifferentFirstPage = true;
// Force odd & even pages to have different Headers and Footers.
document.DifferentOddAndEvenPages = true;
// Insert a Paragraph & image into the first Header.
var picture = image.CreatePicture();
var p = document.Headers.First.InsertParagraph("");
p.AppendPicture(picture);
p.SpacingAfter(30);
// Insert a Paragraph into this document.
Paragraph CiudadYFecha = document.InsertParagraph();
// Append some text and add formatting.
CiudadYFecha.Append("\n\n\n" + obj_eObra.Ciudad + ", " + obj_eObra.FechaActual + ".\n\nSeñores: " + "\n" + obj_eObra.Cliente + "\n\nAtt.: Comité de Selección " + "\nRef.: " + "<Insertar adjudicacion> " + "N° " + obj_eObra.ProcesoDeSeleccion)
.Font(new Font("Times New Roman"))
.FontSize(12)
.SpacingAfter(40);
Paragraph Cuerpo = document.InsertParagraph("De nuestra consideración: \n\n" + "Es grato dirigirnos a ustedes en atención al proceso de selección de la referencia, para alcanzarles nuestra oferta técnico – económica.\n\n" + "Sin otro particular, nos suscribimos de ustedes,\n\n" + "Atentamente,\n");
Cuerpo.Font(new Font("Times New Roman"))
.FontSize(12)
.SpacingAfter(40);
document.Save();
}
I have a pdf document where I am filling all the values using the below code.
using(MemoryStream ms = new MemoryStream())
{
// Fill the PDF with the XFA
using(PdfStamper stamper = new PdfStamper(oInPDF, ms))
{
stamper.Writer.CloseStream = false;
XfaForm.SetXfa(oXFA, stamper.Reader, stamper.Writer);
}
// Code for Flatten the filled PDF.
}
I am trying to draw a box in red around the value displayed to highlight when the values are not in the expected range.
I would like to know, how do I locate the position of a control on a pdf page using iTextSharp and C#.
Any help or info on this, much appreciated.
Many Thanks.
Finally managed to draw borders around controls with below code.
XmlDocument newXMLDoc = new XmlDocument();
newXMLDoc.LoadXml(#"<border><edge thickness=""1.3mm""><color value=""0, 0, 255""/></edge></border>");
if (Rs.Rows.Count > 0)
{
foreach (DataRow query in Rs.Rows)
{
if(isRET)
{
if (oXFA.DomDocument.SelectSingleNode("//t:*[#name='" + Rs[0] + "']", oNameSpace) != null)
{
XmlNode newNode =
oXFA.DomDocument.ImportNode(newXMLDoc.SelectSingleNode("border"), true);
oXFA.DomDocument.SelectSingleNode("//t:*[#name='" + Rs[0] + "']", oNameSpace).AppendChild(newNode);
}
}
}
}
I have pdf files in the "C:\\pdfs\\" directory. I want to get these pdf files and insert metadatas from the meta_data.txt file. With my lock of iTextSharp knowledge, I coded like this:
var pdf_files = Directory.GetFiles("C:\\pdfs\\", "*.pdf");
var i = 0;
foreach (var pdf_file in pdf_files)
{
var read = new PdfReader(pdf_file);
var size = read.GetPageSizeWithRotation(1);
var document = new Document(size);
var write = PdfWriter.GetInstance(document, new FileStream("C:\\temp\\" + "file_" + i, FileMode.Create, FileAccess.Write));
var datas = File.ReadAllLines("C:\\pdfs\\" + #"meta_data.txt");
var str = datas[i].Split('#');
document.AddTitle(str[1]);
document.AddSubject(str[2]);
document.AddCreator(str[3]);
document.AddAuthor(str[4]);
document.AddKeywords(str[5]);
document.Open();
var cb = write.DirectContent;
for (var pageNum = 1; pageNum <= read.NumberOfPages; pageNum++)
{
document.NewPage();
var page = write.GetImportedPage(read, pageNum);
cb.AddTemplate(page, 0, 0);
}
document.Close();
read.Close();
File.Delete(pdf_file);
File.Move("C:\\temp\\" + "file_" + i, "C:\\created\\" + "file_" + i);
i++;
}
This codes get an instance of main pdf files, while creation to temp directory, injects metadatas and later move the created directory. I don't find more practical method than this.
Anyway, in some pdf files (generated as an original pdf file) there is no problem like this:
But some other pdf files (generated from scan or very old dated pdf file) are rotated programmatically. And it seems disgusting like this:
Worse than all, I don't know how I fix the problem. Could you help me how I manage this problem.
The correct answer to this question looks like this:
PdfReader reader = new PdfReader(src);
using (PdfStamper stamper = new PdfStamper(reader,
new FileStream("C:\\temp\\" + "file_" + i, FileMode.Create, FileAccess.Write))) {
Dictionary<String, String> info = reader.Info;
info["Title"] = "Hello World stamped";
info["Subject"] = "Hello World with changed metadata";
info["Keywords"] = "iText in Action, PdfStamper";
info["Creator"] = "Silly standalone example";
info["Author"] = "Bruno Lowagie";
stamper.MoreInfo = info;
}
Habip OĞUZ ignored what I wrote in Chapter 6 of "iText in Action - Second Edition", namely that using Document, PdfWriter and AddTemplate() is wrong when you want to manipulate a single existing PDF. By using AddTemplate(), you throw away plenty of features, such as interactivity, structure, and so on. You also create a PDF that is suboptimal because every page will be stored as a Form XObject.
I am successfully merging PDF documents; now as I'm trying to implement the error handling in case no PDF document has been selected, it throws an error when closing the document: The document has no pages
In case no PDF document has been added in the "foreach" - loop, I still need to close the document!? Or not? If you open an object then it has do be closed at some point. So how to I escape correctly in case no page had been added?
private void MergePDFs()
{
DataSourceSelectArguments args = new DataSourceSelectArguments();
DataView view = (DataView)SourceCertCockpit.Select(args);
System.Data.DataTable table = view.ToTable();
List<PdfReader> readerList = new List<PdfReader>();
iTextSharp.text.Document document = new iTextSharp.text.Document();
PdfCopy copy = new PdfCopy(document, Response.OutputStream);
document.Open();
int index = 0;
foreach (DataRow myRow in table.Rows)
{
if (ListadoCertificadosCockpit.Rows[index].Cells[14].Text == "0")
{
PdfReader Reader = new PdfReader(Convert.ToString(myRow[0]));
Chapter Chapter = new Chapter(Convert.ToString(Convert.ToInt32(myRow[1])), 0);
Chapter.NumberDepth = 0;
iTextSharp.text.Section Section = Chapter.AddSection(Convert.ToString(myRow[10]), 0);
Section.NumberDepth = 0;
iTextSharp.text.Section SubSection = Section.AddSection(Convert.ToString(myRow[7]), 0);
SubSection.NumberDepth = 0;
document.Add(Chapter);
readerList.Add(Reader);
for (int i = 1; i <= Reader.NumberOfPages; i++)
{
copy.AddPage(copy.GetImportedPage(Reader, i));
}
Reader.Close();
}
index++;
}
if (document.PageNumber == 0)
{
document.Close();
return;
}
document.Close();
string SalesID = SALESID.Text;
Response.ContentType = "application/pdf";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.AppendHeader("content-disposition", "attachment;filename=" + SalesID + ".pdf");
}
In the old days, iText didn't throw an exception when you created a document and "forgot" to add any content. This resulted in a document with a single, blank page. This was considered a bug: people didn't like single-page, empty documents. Hence the design decision to throw an exception.
Something similar was done for newPage(). A new page can be triggered explicitly (when you add document.newPage() in your code) or implicitly (when the end of a page is reached). In the old days, this often resulted in unwanted blank pages. Hence the decision to ignore newPage() in case the current page is empty.
Suppose you have this:
document.newPage();
document.newPage();
One may expect that two new pages are created. That's not true. We've made a design decision to ignore the second document.newPage() because no content was added after the first document.newPage().
This brings us to the question: what if we want to insert a blank page? Or, in your case: what if it's OK to create a document with nothing more than a single blank page?
In that case, we have to tell iText that the current page shouldn't be treated as an empty page. You can do so by introducing the following line:
writer.setPageEmpty(false);
Now the current page will be fooled into thinking that it has some content, even though it may be blank.
Adding this line to your code will avoid the The document has no pages exception and solve your problem of streams not being closed.
Take a look at the NewPage example if you want to experiment with the setPageEmpty() method.
You can add an empty page before closing the document, or catch the exception and ignore it.
In case you are still interested in a solution, or may be someone else.
I had exactly the same issue and I workaround-ed it by:
Declaring a boolean to figure out if at least one page have been added and before closing the document I referred on it.
If no pages have been copied, I add a new page in the document thanks to the AddPages method, with a rectangle as parameter. I did not find a simplest way to add a page.
So the code should be as bellow (with possibly some syntax errors as I'm not familiar with C#):
private void MergePDFs()
{
DataSourceSelectArguments args = new DataSourceSelectArguments();
DataView view = (DataView)SourceCertCockpit.Select(args);
System.Data.DataTable table = view.ToTable();
List<PdfReader> readerList = new List<PdfReader>();
iTextSharp.text.Document document = new iTextSharp.text.Document();
PdfCopy copy = new PdfCopy(document, Response.OutputStream);
document.Open();
int index = 0;
foreach (DataRow myRow in table.Rows)
{
if (ListadoCertificadosCockpit.Rows[index].Cells[14].Text == "0")
{
PdfReader Reader = new PdfReader(Convert.ToString(myRow[0]));
Chapter Chapter = new Chapter(Convert.ToString(Convert.ToInt32(myRow[1])), 0);
Chapter.NumberDepth = 0;
iTextSharp.text.Section Section = Chapter.AddSection(Convert.ToString(myRow[10]), 0);
Section.NumberDepth = 0;
iTextSharp.text.Section SubSection = Section.AddSection(Convert.ToString(myRow[7]), 0);
SubSection.NumberDepth = 0;
document.Add(Chapter);
readerList.Add(Reader);
bool AtLeastOnePage = false;
for (int i = 1; i <= Reader.NumberOfPages; i++)
{
copy.AddPage(copy.GetImportedPage(Reader, i));
AtLeastOnePage = true;
}
Reader.Close();
}
index++;
}
if (AtLeastOnePage)
{
document.Close();
return true;
}
else
{
Rectangle rec = new Rectangle(10, 10, 10, 10);
copy.AddPage(rec, 1);
document.Close();
return false;
}
string SalesID = SALESID.Text;
Response.ContentType = "application/pdf";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.AppendHeader("content-disposition", "attachment;filename=" + SalesID + ".pdf");
}
I have an HTML table in a view. I'm using ITextSharp 4 to convert the HTML to a PDF using the htmlParser. The table spans multiple pages. How do I get it to show the header on each page? Is there some setting I can turn on in HTML so that ITextSharp can recognise it?
I don't have access to iTextSharp 4.0 but since the HTML parser writes directly to the document I'm not sure if it would be possible without modify the original source. Is it an option to upgrade to 5.0 which completely replaced the HtmlParser with a much more robust HTMLWorker object?
To have a PdfPTable's headers span multiple page you need to set its HeaderRows property to the number of rows in your header. Unfortunately if you're using the HTMLParser or the HTMLWorker they do not currently treat THEAD and TH tags differently than TBODY and TD tags. The solution is to modify the PdfPTable sometime after parsing but before being written to the document. I don't have 4.0 available here but in 5.1.1.0 using the HTMLWorker you can easily do that and manually set the HeaderRows property:
//Output file
string outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Table.pdf");
using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.Read))
{
using (Document doc = new Document(PageSize.LETTER))
{
using (PdfWriter w = PdfWriter.GetInstance(doc, fs))
{
doc.Open();
doc.NewPage();
//Create some long text to force a new page
string longText = String.Concat(Enumerable.Repeat("Lorem ipsum.", 40));
//Create our table using both THEAD and TH which iTextSharp currently ignores
string html = "<table>";
html += "<thead><tr><th>Header Row 1/Cell 1</th><th>Header Row 1/Cell 2</th></tr><tr><th>Header Row 2/Cell 1</th><th>Header Row 2/Cell 2</th></tr></thead>";
html += "<tbody>";
for (int i = 3; i < 20; i++)
{
html += "<tr>";
html += String.Format("<td>Data Row {0}</td>", i);
html += String.Format("<td>{0}</td>", longText);
html += "</tr>";
}
html += "</tbody>";
html += "</table>";
using (StringReader sr = new StringReader(html))
{
//Get our list of elements (only 1 in this case)
List<IElement> elements = iTextSharp.text.html.simpleparser.HTMLWorker.ParseToList(sr, null);
foreach (IElement el in elements)
{
//If the element is a table manually set its header row count
if (el is PdfPTable)
{
((PdfPTable)el).HeaderRows = 2;
}
doc.Add(el);
}
}
doc.Close();
}
}
}
you should just be able to set: table.HeaderRows = 1;
this will repeat the header on each page.
Apply the "repeat-header" style, and set to "yes", like so:
<table style="repeat-header:yes;">