Click here to Skip to main content
15,909,325 members
Articles / Programming Languages / C#
Article

Gios WORD .NET Library (using RTF specification)

Rate me:
Please Sign up or sign in to vote.
4.85/5 (47 votes)
8 Aug 2005LGPL31 min read 364K   4.6K   149   110
A .NET library for generating Word documents (.DOC) using the RTF (Rich Text Format) specification.

This is the output of "Example 1", included in the library.

Introduction

The Gios WORD .NET is the second thing that a good C# developer needs to deploy in his business projects... The first one?!? You probably know it is the Gios PDF .NET library!

So, that's why I decided to develop this library: after the need for generating PDFs, you will need the same for WORDs!

Gios WORD .NET supports:

  • Tables with rows and columns span.
  • Images
  • Header and Footer
  • Line indent - paragraph
  • Custom Control Words (See the Rich Text Format (RTF) Specification for this implementation.)
  • Output to a generic System.IO.Stream object.

Background

Building a library for exporting documents in the Rich Text Format is quite easier than for PDFs. In fact, the Rich Text Format (RTF) Specification, version 1.8 shows how simple it is to generate a word document with all the well known features. I used the version 1.5 (which is fully compatible with WORD 97).

Using the code

The library is very simple to be used! The first thing you need to do is instantiating a new WordDocument:

C#
WordDocument myWordDocument=
    new WordDocument(WordDocumentFormat.Letter_8_5x11);

and with the WordDocument object you can start with the description of the document. It's like an automation. For example, if you want to set the font, you can write:

C#
myWordDocument.SetFont(new Font("Comic Sans MS",
                                60,FontStyle.Bold));
myWordDocument.SetForegroundColor(Color.Red);
myWordDocument.SetFontBackgroundColor(Color.Yellow);

And now we set some alignment:

C#
myWordDocument.SetTextAlign(WordTextAlign.Center);

To write a text... You can imagine:

C#
myWordDocument.Write("Hello World!");

And, in the end, you output the document!

C#
myWordDocument.SaveToFile("HelloWorld.doc");

And this is the result:

Remember, you can also output the WORD Document to a generic stream. These are the lines for a web response:

C#
Response.ClearHeaders();
Response.AppendHeader("Content-disposition",
   "attachment;filename=HelloWorld.doc");
Response.ContentType="application/msword"; 
myPdfDocument.SaveToStream(Response.OutputStream);
Response.End();

To continue with the training, please download the library and follow the examples!

History

  • August 8th, 2005 - First release.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Web Developer
Italy Italy
Freelance software ASPNET / C# Software Developer

I live in Torino, Italy

my homepage is: http://www.paologios.com

Comments and Discussions

 
GeneralGreat code! Pin
Alessio.NET18-Aug-05 2:54
Alessio.NET18-Aug-05 2:54 
GeneralRe: Great code! Pin
Paolo Gios18-Aug-05 9:50
Paolo Gios18-Aug-05 9:50 
Generalgood , but Pin
Huisheng Chen8-Aug-05 20:25
Huisheng Chen8-Aug-05 20:25 
GeneralRe: good , but Pin
Rei Miyasaka8-Aug-05 21:05
Rei Miyasaka8-Aug-05 21:05 
GeneralRe: good , but Pin
Paolo Gios8-Aug-05 23:29
Paolo Gios8-Aug-05 23:29 
GeneralRe: good , but Pin
Rei Miyasaka9-Aug-05 2:26
Rei Miyasaka9-Aug-05 2:26 
GeneralRe: good , but Pin
Huisheng Chen9-Aug-05 2:44
Huisheng Chen9-Aug-05 2:44 
GeneralI think I got it Pin
Rei Miyasaka9-Aug-05 16:32
Rei Miyasaka9-Aug-05 16:32 
I had to make several changes, and unfortunately there's a P/Invoke involved... here's what I've done.

Like I explained earlier, first WordDocument.Header had to be changed to emit \ansicpg and \uc:
<br />
internal string Header<br />
{<br />
get<br />
{<br />
string s= "{";<br />
s+="\\rtf1\\ansi";<br />
s+="\\ansicpg" + Encoding.Default.CodePage.ToString();<br />
s+="\\uc" + Encoding.Default.GetMaxByteCount(1);<br />
s+=this.FontTable;<br />
s+=this.ColorTable;<br />
if (this.StartPage>-1) s+="\\pgnstart"+this.StartPage+"\n";<br />
return s;<br />
}<br />
}<br />

Then I had to change Utility.Encode so that rather than encoding just the first byte, it encodes every byte of each character, and use the correct system encoding (this could be a potential problem for documents that use a language other than the system default codepage -- the only way to solve this would be to make a public Encoding property in WordDocument, and pass that to every call to Encoding.Utility):
<br />
if ((c>=48&&c<=122)||c=='\n'||c==' ') sb.Append(c);<br />
else<br />
{<br />
if (c=='€')<br />
sb.Append("\\'80");<br />
else<br />
{<br />
byte[] Bytes=System.Text.Encoding.Unicode.GetBytes(new char[]{c});<br />
foreach(byte b in Bytes)<br />
sb.Append("\\'" + Utility.ToHexString(b));<br />
}<br />
}<br />

Then I added a LOGFONT class, which is a Windows API class invoke:
<br />
using System.Runtime.InteropServices;<br />
<br />
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]<br />
class LOGFONT<br />
{<br />
public int lfHeight;<br />
public int lfWidth;<br />
public int lfEscapement;<br />
public int lfOrientation;<br />
public int lfWeight;<br />
public byte lfItalic;<br />
public byte lfUnderline;<br />
public byte lfStrikeOut;<br />
public byte lfCharSet;<br />
public byte lfOutPrecision;<br />
public byte lfClipPrecision;<br />
public byte lfQuality;<br />
public byte lfPitchAndFamily;<br />
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]<br />
public string lfFaceName;<br />
}<br />

Lastly, I changed WordDocument.AddFontAndGetID() to save the whole font rather than just the name (Font.Equals is implented; searching shouldn't be a problem), and had WordDocument.FontTable create a LOGFONT, specify the character set and the font name to the "real" one (apparently Japanese fonts have a Japanese name and an English name, Drawing.Font gives only the English one):
<br />
get<br />
{<br />
string s="{\\fonttbl\n";<br />
for (int index=0;index {<br />
Font f = FontList[index] as Font;<br />
LOGFONT logFont = new LOGFONT();<br />
f.ToLogFont(logFont);<br />
s+="{\\f"+index.ToString()+" \\fcharset" + logFont.lfCharSet.ToString() + " " + Utility.Encode(logFont.lfFaceName) + ";}\n";<br />
}<br />
s+="}\n";<br />
return s;<br />
}<br />

Real messy eh? According to this[^], Font.GdiCharSet isn't set unless you specify it. It just sets it to 1 (default)... which makes no sense. I hope they fix this in future versions, along with the font face name issue.

Hopefully I got everything right. I might have missed some things from the 1.5 specification, but it works in Word 2003 and Wordpad on XPSP2, so it should be better than nothing Smile | :)
GeneralRe: I think I got it Pin
Huisheng Chen10-Aug-05 5:22
Huisheng Chen10-Aug-05 5:22 
GeneralRe: I think I got it Pin
Paolo Gios10-Aug-05 6:55
Paolo Gios10-Aug-05 6:55 
GeneralA little bit of sad news Pin
Rei Miyasaka12-Aug-05 14:20
Rei Miyasaka12-Aug-05 14:20 
GeneralRe: I think I got it Pin
percyboy16-Aug-05 23:02
percyboy16-Aug-05 23:02 
GeneralRe: I think I got it Pin
Paolo Gios16-Aug-05 23:24
Paolo Gios16-Aug-05 23:24 
GeneralRe: I think I got it Pin
Simon Pham25-Aug-05 4:57
Simon Pham25-Aug-05 4:57 
GeneralRe: I think I got it Pin
dunglesi2-Jan-06 22:46
dunglesi2-Jan-06 22:46 
GeneralRe: I think I got it Pin
Mausi23-Nov-05 0:34
Mausi23-Nov-05 0:34 
GeneralRe: I think I got it Pin
Member 95538034-Dec-12 22:03
Member 95538034-Dec-12 22:03 
GeneralRe: good , but Pin
meduza19-Oct-06 23:46
meduza19-Oct-06 23:46 
GeneralRe: good , but Pin
Marcin Lew11-Aug-06 7:30
Marcin Lew11-Aug-06 7:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.