Display Chinese Characters in PDF created by iTextSharp
Introduction
I have been using iTextSharp for sometime now but had not been able to create a dynamic PDF that can display both English and Chinese characters successfully until today. There are not many writings out there that would give me a complete coverage on how this is done, so I figured it will be beneficial to folks who are still struggling like I was that I summarize all the important steps in one post for easier reference on this tricky issue. Even though my case only deals with Simplified Chinese characters, the same technique is applicable to any double-byte Unicode character set, I believe.
There is plenty of documentation about how to use the iTextSharp API to create dynamic PDF, so here I will only focus on what is generally missing in those web posts – getting Chinese or Asian characters in general to display correctly alongside with English ones.
Getting the API
Get the latest version of iTextSharp.dll from here. Once downloaded and unzipped, there is only one file itextsharp.dll; I added a reference to it in my C# project and that was it. I also downloaded iTextAsian.dll and iTextAsianCmaps.dll (from the Extras link on the same download page for iTextSharp.dll) and added references to them, but it turned out I did not need them at all for what I wanted to accomplish, so later I removed them from the project.
Getting the Font File
This was a turning point for me and everything turned out just fine after I downloaded the correct TTF file for the Simplified Chinese characters I wanted to display. There are many font files for the Simplified Chinese language (used mostly in mainland China); my eyes almost dried up after exhaustive Google searches, and I used a trick in Microsoft Word to help me sort this out – I opened Word, switched the input language to Simplified Chinese, and started typing in a few Simplified Chinese letters into the document. When I looked at the Font faces dropdown box on the top-left corner of the menu bar, it automatically changed from the default “Calibri” to “SimSun”, so that settled it – “SimSun.ttf” was what I wanted to get. I then simply typed “simsun.ttf” on the Google search box and picked the top one from the results: http://www.gamefront.com/files/16488629/simsun.ttf/. There is no need to install the font file. I just placed it in a “Fonts” folder (you can name it whatever) inside my ASP.NET project that is accessible by the runtime ASP.NET code.
Generating a Mixed-Language PDF
Now, it’s show time. In this theme, I have an ASP.NET grid view that contains both English and Chinese texts that are pulled from a SQL Server 2008 database. This is a calendar displaying school events and schedules; so it is natural that a “Save as PDF” link is displayed here to allow the user to grab a copy of the school calendar to go. It was quite straightforward to accomplish this, if there were no Chinese characters involved - I wrapped the grid view data into a DataTable
object and passed it to a pre-written function called ExportPdfTable
that in turn made the appropriate iTextSharp API calls to carry out the dirty work. Below is the code snippet that traverses the DataTable
object and spits out a PDF document on the fly:
…
using iTextSharp.text
using iTextSharp.text.pdf;
..
/// <summary>
/// Print a table to a Pdf file in tabular format,
/// with header image and text on every page
/// </summary>
/// <param name="PdfFileName">This is pyhsical file name
/// of Pdf document that you wanto write to</param>
/// <param name="dt">Datatable that contain the data to print</param>
/// <param name="DocTitle">This is the title of the
/// document to be printed once on first page</param>
/// <param name="PageHeader">Header text to go
/// with header image on every page</param>
/// <param name="HeaderImgPath">the physical file path of a image
/// that you want to print out on every page header</param>
/// <returns></returns>
public static bool ExportPdfTable(string PdfFileName, DataTable dt,
string DocTitle,string PageHeader,string HeaderImgPath)
{
Document doc = new Document(); //iTextSharp document
try
{
string physicalFile = PdfFileName;
PdfWriter pw=PdfWriter.GetInstance(doc,
new FileStream(physicalFile, FileMode.Create));
//prepare for inserting header on every page, using Pageevent
//DocumentEevent e = new DocumentEevent(HeaderImgPath, PageHeader);
//pw.PageEvent = e;
doc.Open();
if (PageHeader.Length > 0)
doc.Add(new Paragraph(new Phrase("")));
if (DocTitle.Length > 0)
doc.Add(new Phrase(DocTitle));
if (dt.Columns.Count == 0) return false;
int cols = dt.Columns.Count;
int rows = dt.Rows.Count;
//prepare the table object
PdfPTable t = new PdfPTable(cols);
t.WidthPercentage = 100;
//cell object
PdfPCell c;
//Use BaseFont to load unicode fonts like Simplified Chinese font
string fontpath = System.Web.HttpContext.Current.Request.PhysicalApplicationPath +
"\\includes\\fonts\\simsun.ttf";
//"simsun.ttf" file was downloaded from web and placed in the folder
BaseFont bf = BaseFont.CreateFont(fontpath,BaseFont.IDENTITY_H,
BaseFont.EMBEDDED);
//create new font based on BaseFont
Font fontContent = new Font(bf, 11);
Font fontHeader = new Font(bf, 12);
//write header
for (int j = 0; j < cols; j++)
{
Phrase pr=new Phrase((dt.Columns[j].Caption != null &&
dt.Columns[j].Caption.Length > 0) ? dt.Columns[j].Caption :
dt.Columns[j].ColumnName,fontHeader);
c = new PdfPCell(pr);
c.PaddingBottom = 5f;
c.PaddingTop = 5f;
c.PaddingLeft = 8f;
c.PaddingRight = 8f;
t.AddCell(c);
}
//write table content
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
//c = new Cell(dt.Rows[i][j].ToString());
//c.Header = false;
c = new PdfPCell(new Phrase(dt.Rows[i][j].ToString(),fontContent));
c.PaddingBottom = 5f;
c.PaddingTop = 5f;
c.PaddingLeft = 8f;
c.PaddingRight = 8f;
t.AddCell(c);
}
}
return doc.Add(t);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
finally
{
doc.Close();
}
}
The four lines that are critical for allowing Chinese characters to show up in the dynamically generated PDF are shighlighted here:
string fontpath =
System.Web.HttpContext.Current.Request.PhysicalApplicationPath +
"\\includes\\fonts\\simsun.ttf";
//"simsun.ttf" file was downloaded from web and placed in the folder
BaseFont bf = BaseFont.CreateFont(fontpath,
BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
//create new font based on BaseFont
Font fontContent = new Font(bf, 11);
Font fontHeader = new Font(bf, 12);
If these four lines are taken out, the function would still output the same good-looking PDF file except that all Chinese characters would disappear completely. The key in creating a correct base font in this case is loading the correct TTF file and setting the encoding to BaseFont.IDENTITY_H
. I tried “UTF-8” and some other values, but none of them seemed to work. I got this tip from a very brief but helpful post at http://stackoverflow.com/questions/1727765/itextsharp-international-text and I am grateful to its author StewBob and to stackoverflow.com that hosted the post.
Deployment
Everything ran perfectly on my local development machine... the PDF file got created and the Chinese characters showed up...but a "That assembly does not allow partially trusted callers." error was thrown after the project was deployed to an external hosting site. What was going on? Well, this was actually not a new problem and had nothing to do with the Chinese font. As it turned out, I was not supposed to just simply upload itextsharp.dll to the hosting server. I needed to download the iTextSharp source files and compile the DLL with some additional security attribute added. So these extra steps were taken to fix this DLL error:
- Downloaded the iTextSharp source files (version 5.xx) from http://sourceforge.net/projects/itextsharp/files/itextsharp/.
- Launched the iTextSharp solution and opened AssemblyInfo.cs and added the following lines to the end of the file:
- Compiled the DLL and copied it to the hosting site's bin folder, and done.
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
//added this atribute to allow the dll to be callable on a hosting website
[assembly: AllowPartiallyTrustedCallers()]
Summary
Wrapping it up, the four key steps are:
- Download the correct font file and place it in a folder inside the web project.
- Create a
BaseFont
with the font file loaded and set the encoding toBaseFont.IDENTITY_H
; also set embedding the font in the PDF document to true (BaseFont.EMBEDDED
). - Create new fonts based on the
BaseFont
and use them inParagraph
orPhrase
constructors. - Make sure when iTextSharp.dll is deployed to the remote hosting server, the DLL must be re-compiled with the "
AllowPartiallyTrustedCallers
" attribute set.
History
- First submitted on 5/12/2011.
Post Comment
It'аs actually a nice and useful piece of info. I am happy that you shared this useful information with us. Please keep us up to date like this. Thank you for sharing.
that is the end of this write-up. Here you will find some web pages that we think you will appreciate, just click the links over
You definitely put a brand new spin on a subject that has been
I value the blog article.Really looking forward to read more. Really Cool. this site
There as definately a lot to find out about this issue. I like all the points you made.
I would add something else, of course, but in fact almost everything is mentioned!
WONDERFUL Post.thanks for share..more wait..
It as hard to come by experienced people in this particular topic, but you seem like you know what you are talking about! Thanks
I would like to know what app this is also.
You have a very great layout for your blog i want it to make use of on my website also.
This awesome blog is without a doubt awesome and besides amusing. I have picked up a bunch of helpful advices out of this amazing blog. I ad love to return again soon. Thanks a bunch!
This is very interesting, You are a very skilled blogger. I have joined your feed and look forward to seeking more of your magnificent post. Also, I ave shared your web site in my social networks!
I went over this internet site and I believe you have a lot of great information, saved to favorites (:.
Only wanna state that this is very useful , Thanks for taking your time to write this.
Thanks-a-mundo for the article post.Really looking forward to read more. Really Cool.
Really appreciate you sharing this article.Thanks Again. Keep writing.
You made some nice points there. I did a search on the subject and found most guys will approve with your site.
I truly appreciate this blog post.Really looking forward to read more. Cool.
you continue this in future. A lot of people will be benefited from your writing.
Very nice post. I just stumbled upon your weblog and wanted to say that I have truly enjoyed browsing your blog posts. After all I will be subscribing to your rss feed and I hope you write again soon!
wow, awesome blog article.Really thank you! Great.
Major thankies for the blog post.Really thank you!
Thanks for sharing, this is a fantastic article.Really looking forward to read more. Will read on
I?аАТаЂаll right away grasp your rss as I can not in finding your e-mail subscription hyperlink or newsletter service. Do you ave any? Please allow me recognize in order that I could subscribe. Thanks.
Recently, Washington State Police arrested cheap jersey quarterback Josh Portis on suspicion of driving
Way cool! Some extremely valid points! I appreciate you penning this write-up plus the rest of the site is really good.|
Jak zosta dobrym sprzedawc Sprzeda przez telefon
You are my inhalation , I have few web logs and infrequently run out from to brand.
Your style is really unique compared to other people I ave read stuff from. Thanks for posting when you have the opportunity, Guess I all just bookmark this blog.
Thank you for your post.Really looking forward to read more. Keep writing.
right here, certainly like what you are stating and the way wherein you assert it.
Some really select articles on this web site , saved to bookmarks.
WONDERFUL Post.thanks for share..more hold your fire..
It is truly a nice and helpful piece of info. I am glad that you simply shared this helpful information with us. Please stay us informed like this. Thanks for sharing.
I was suggested this web site by my cousin. I am not sure whether this post is written by him as nobody else know such detailed about my problem. You are incredible! Thanks!
You have brought up a very wonderful points , thanks for the post.
Of course, what a great blog and educative posts, I will bookmark your site.Have an awsome day!
Lovely website! I am loving it!! Will come back again. I am bookmarking your feeds also.
It as really a cool and useful piece of information. I am glad that you shared this helpful information with us. Please keep us up to date like this. Thanks for sharing.
Your style is unique compared to other people I have read stuff from. Thank you for posting when you ave got the opportunity, Guess I will just book mark this site.
Wow, marvelous blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your web site is excellent, let alone the content!
Major thanks for the blog post.Thanks Again. Awesome.
Im thankful for the blog post. Much obliged.
Im thankful for the blog.Really looking forward to read more. Will read on
I truly appreciate this post. I ave been looking everywhere for this! Thank goodness I found it on Bing. You have made my day! Thanks again!
Some truly great blog posts on this website , thankyou for contribution.
Way cool! Some very valid points! I appreciate you writing this write-up and the rest of the site is really good.
It'аs really a great and helpful piece of information. I'аm satisfied that you just shared this useful information with us. Please stay us informed like this. Thanks for sharing.
the excellent information you have here on this post. I am returning to your web site for more soon.
to carry this out efficiently, appropriately and safely.