Today I've been writting some code to add an "Export to PDF" button to the ticket view of
SlickTicket, an open source, web based help desk application. SlickTicket, and the
SlickTicket codeplex site.
It is written in C# (C Sharp), and has provided me with a nice entry platform into the world of .NET development.
I wanted to add the ability to print out a ticket including all the comments (entries added since the initial submission) without having to print it from the web browser.
After finding out about the ability of
iTextSharp to create PDFs using C#, I was initially obsessed with trying to convert the already created HTML to a PDF. After a little head banging, as the ability of iTextSharp to parse HTML is a bit limited, I decided to scrap that method and then focus on dynamically creating the PDF.
The code I ended up with is as follows:
//Namespaces required in addition to defaults on Ticket.aspx.cs:
//using iTextSharp.text;
//using iTextSharp.text.pdf;
//using System.Threading;
protected void btnExport_Click(object sender, EventArgs e)
{
//The following code creates a PDF of the Ticket view, with a logo in the top right corner
//The path for the PDF to be written to
string strPath = Request.PhysicalApplicationPath.ToString() + "Ticket_" + t.id + ".pdf";
//The path of the font to be used to create the PDF
string strFontPath = Request.PhysicalApplicationPath.ToString() + "Fonts\\Calibri.ttf";
//The path of the Logo to be used in the PDF
string strLogoPath = Request.PhysicalApplicationPath.ToString() + "Images\\Logo.png";
//Defining the layout of the sections to be used in the Ticket body
//It is done this way to simplify the logic of the strTicket definition
string strTicketDetails = "Details: " + t.details + "\n";
string strTicketDate = "Date Submitted: " + t.submitted.ToString().Substring(0, 10) + "\n";
string strTicketPriority = "Priority: " + t.priority1.priority_name + "\n";
//Defining the Title and Sub-title strings
string strTitle = "Ticket " + t.id + " - " + t.title;
string strTitle2 = "Owner: " + t.user.userName.capitalize() + " (" + t.sub_unit1.unit.unit_name + " - " + t.sub_unit1.sub_unit_name + ")" + "\n" + "Status: " + t.statuse.status_name;
//Defining the Ticket body string
string strTicket = strTicketDate + strTicketPriority + strTicketDetails;
//Creation of a document-object
Document document = new Document();
try
{
//Writer that listens to the document and directs a PDF-stream to a file
PdfWriter.GetInstance(document, new FileStream(strPath, FileMode.Create));
//Open the document
document.Open();
//Adding fonts
BaseFont fntBase = BaseFont.CreateFont(strFontPath, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
Font fntUse = new Font(fntBase, 11, Font.NORMAL);
Font fntTitle = new Font(fntBase, 16, Font.BOLD);
Font fntSubTitle = new Font(fntBase, 14, Font.BOLD);
Font fntBreak = new Font(fntBase, 5, Font.NORMAL);
//Adding the Logo to the top of the page
iTextSharp.text.Image imgLogo = iTextSharp.text.Image.GetInstance(strLogoPath);
imgLogo.Alignment = iTextSharp.text.Image.RIGHT_ALIGN;
document.Add(imgLogo);
//Defining the blank paragraph "pBlank"
Paragraph pBreak = new Paragraph(" ", fntBreak);
//Adding the title
document.Add(new Paragraph(strTitle, fntTitle));
//Adding the sub-title
document.Add(new Paragraph(strTitle2, fntSubTitle));
//Adding a gap between the sub-title and the body text
document.Add(pBreak);
//Adding the body
document.Add(new Paragraph(strTicket, fntUse));
//Adding a gap
document.Add(pBreak);
//Comment building code
IEnumerable<comment> comments = Tickets.Comments.List(db, t.id);
foreach (comment c in comments)
{
//This changes the Submitted date to a string, and returns the date in dd/mm/yyyy format
string cDateFull = c.submitted.ToString();
string cDate = "No Date Given";
if (cDateFull.Length > 10)
{
cDate = cDateFull.Substring(0, 10);
}
//Defining the layout of the Comment body section(s)
string strComment =
"Date: " + cDate + "\n" +
"Priority: " + c.priority.priority_name + "\n" +
"Details: " + c.comment1;
//Adding the comment to the PDF
document.Add(new Paragraph(strComment, fntUse));
//Adding a gap
document.Add(pBreak);
}
}
//These are included in the iTextSharp Examples
catch (DocumentException de)
{
Console.Error.WriteLine(de.Message);
}
catch (IOException ioe)
{
Console.Error.WriteLine(ioe.Message);
}
//Close the pdf
document.Close();
if (File.Exists(strPath))
{
//Run a seperate thread that will delete the server copy of the PDF after 5 seconds
Thread thrWait = new Thread(deleteMe);
thrWait.Start(strPath);
}
//Offer the user a chance to download the PDF
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader
("Content-Disposition", "attachment; filename=Ticket_" + t.id + ".pdf");
Response.TransmitFile(strPath);
}
static void deleteMe(object fileObject)
{
string filePath = (string)fileObject;
Thread.Sleep(5000);
if (File.Exists(filePath))
{
File.Delete(filePath);
}
}
I simply refernced that code with a simple ASP Button on the Ticket.aspx page
<asp:button id="btnExportPdf" runat="server" onclick="btnExport_Click" text="Export to PDF">
If you plan on doing the same, or similar, I'd recommend putting the button between pnlShowTicket and pnlDisplay. Personally, I used another ASP Panel, and set it so the button aligned to the right.