Click here to Skip to main content
14,304,886 members

Writing Your Own RTF Converter

Rate this:
4.95 (228 votes)
Please Sign up or sign in to vote.
4.95 (228 votes)
1 Aug 2013CPOL
An article on how to write a custom RTF parser and converter.

Build your own RTF Converter

Introduction

In 1992, Microsoft introduced the Rich Text Format for specifying simple formatted text with embedded graphics. Initially intended to transfer such data between different applications on different Operating Systems (MS-DOS, Windows, OS/2, and Apple Macintosh), today this format is commonly used in Windows for enhanced editing capabilities (RichTextBox).

However, as soon as you have to work with such data in RTF format, additional wishes start to get strong:

  • Simple extraction of text without consideration of any format information
  • Extraction and conversion of embedded image information (scaled or unscaled)
  • Conversion of the RTF layout and/or data into another format such as XML or HTML
  • Transferring RTF data into a custom data model

The component introduced in this article has been designed with the following goals in mind:

  • Support for the current RTF Specification 1.9.1
  • Open Source C# code
  • Unlimited usage in console, WinForms, WPF, and ASP.NET applications
  • Independence of third party components
  • Unicode support
  • Possibility to analyze RTF data on various levels
  • Separation of parsing and the actual interpretation of RTF data
  • Extensibility of parser and interpreter
  • Providing simple predefined conversion modules for text, images, XML, and HTML
  • Ready-to-use RTF converter applications for text, images, XML, and HTML
  • Open architecture for simple creation of custom RTF converters

Please keep the following shortcomings in mind:

  • The component offers no high-level functionality to create RTF content
  • The present RTF interpreter is restricted to content data and basic formatting options
  • There is no special support for the following RTF layout elements:

    • Tables
    • Lists
    • Automatic numbering
    • All features which require knowledge of how Microsoft Word might mean it ...

In general, this should not pose a big problem for many areas of use. A conforming RTF writer should always write content with readers in mind that they do not know about tags and features which were introduced later in the standards history. As a consequence, a lot of the content in an RTF document is stored several times (at least if the writer cares about other applications). This is taken advantage of by the interpreter here, which just simply focuses on the visual content. Some writers in common use, however, improperly support this alternate representation, which will result in differences in the resulting output.

Thanks to its open architecture, the RTF parser is a solid base for development of an RTF converter which focuses on layout.

RTF Parser

RTF Parser

The actual parsing of the data is being done by the class RtfParser. Apart from the tag recognition, it also handles (a first level of) character encoding and Unicode support. The RTF parser classifies the RTF data into the following basic elements:

  • RTF Group: A group of RTF elements
  • RTF Tag: The name and value of an RTF tag
  • RTF Text: Arbitrary text content (not necessarily visible!)

The actual parsing process can be monitored by ParserListeners (Observer Pattern), which offers an opportunity to react on specific events and perform corresponding actions.

The integrated parser listener RtfParserListenerFileLogger can be used to write the structure of the RTF elements into a log file (mainly intended for use during development). The produced output can be customized using its RtfParserLoggerSettings. The additional RtfParserListenerLogger parser listener can be used to log the parsing process to any ILogger implementation (see System functions).

The parser listener RtfParserListenerStructureBuilder generates the Structure Model from the RTF elements encountered during parsing. That model represents the basic elements as instances of IRtfGroup, IRtfTag, and IRtfText. Access to the hierarchical structure can be gained through the RTF group available in RtfParserListenerStructureBuilder.StructureRoot. Based on the Visitor Pattern, it is easily possible to examine the structure model via any IRtfElementVisitor implementation:

// ----------------------------------------------------------------------
public class MyVisitor : IRtfElementVisitor
{
    void RtfWriteStructureModel()
    {
      RtfParserListenerFileLogger logger =
         new RtfParserListenerFileLogger( @"c:\temp\RtfParser.log" );
      IRTFGroup structureRoot =
         RtfParserTool.Parse( @"{\rtf1foobar}", logger );
      structureRoot.Visit( this );
    } // RtfWriteStructureModel

    // ----------------------------------------------------------------------
    void IRtfElementVisitor.VisitTag( IRtfTag tag )
    {
      Console.WriteLine( "Tag: " + tag.FullName );
    } // IRtfElementVisitor.VisitTag

    // ----------------------------------------------------------------------
    void IRtfElementVisitor.VisitGroup( IRtfGroup group )
    {
      Console.WriteLine( "Group: " + group.Destination );
      foreach ( IRtfElement child in group.Contents )
      {
        child.Visit( this ); // recursive
      }
    } // IRtfElementVisitor.VisitGroup

    // ----------------------------------------------------------------------
    void IRtfElementVisitor.VisitText( IRtfText text )
    {
      Console.WriteLine( "Text: " + text.Text );
    } // IRtfElementVisitor.VisitText

} // MyVisitor

Note, however, that the same result for such simple functionality could be achieved by writing a custom IRtfParserListener (see below). This can, in some cases, be useful to avoid the overhead of creating the structure model in memory.

The utility class RtfParserTool offers the possibility to receive RTF data from a multitude of sources, such as string, TextReader, and Stream. It also allows, via its IRtfSource interface, to handle all these (and even other) scenarios in a uniform way.

The interface IRtfParserListener, with its base utility implementation RtfParserListenerBase, offers a way to react in custom ways to specific events during the parsing process:

// ------------------------------------------------------------------------
public class MyParserListener : RtfParserListenerBase
{
    // ----------------------------------------------------------------------
    protected override void DoParseBegin()
    {
      Console.WriteLine( "parse begin" );
    } // DoParseBegin

    // ----------------------------------------------------------------------
    protected override void DoGroupBegin()
    {
      Console.WriteLine( "group begin - level " + Level.ToString() );
    } // DoGroupBegin

    // ----------------------------------------------------------------------
    protected override void DoTagFound( IRtfTag tag )
    {
      Console.WriteLine( "tag " + tag.FullName );
    } // DoTagFound

    // ----------------------------------------------------------------------
    protected override void DoTextFound( IRtfText text )
    {
      Console.WriteLine( "text " + text.Text );
    } // DoTextFound

    // ----------------------------------------------------------------------
    protected override void DoGroupEnd()
    {
      Console.WriteLine( "group end - level " + Level.ToString() );
    } // DoGroupEnd

    // ----------------------------------------------------------------------
    protected override void DoParseSuccess()
    {
      Console.WriteLine( "parse success" );
    } // DoParseSuccess

    // ----------------------------------------------------------------------
    protected override void DoParseFail( RtfException reason )
    {
      Console.WriteLine( "parse failed: " + reason.Message );
    } // DoParseFail

    // ----------------------------------------------------------------------
    protected override void DoParseEnd()
    {
      Console.WriteLine( "parse end" );
    } // DoParseEnd

} // MyParserListener

Note that the used base class already provides (empty) implementations for all the interface methods, so only the ones which are required for a specific purpose need to be overridden.

RTF Interpreter

RTF Interpreter

Once an RTF document has been parsed into a structure model, it is subject to interpretation through the RTF interpreter. One obvious way to interpret the structure is to build a Document Model which provides high-level access to the meaning of the document's contents. A very simple document model is part of this component, and consists of the following building blocks:

  • Document info: title, subject, author, etc.
  • User properties
  • Color information
  • Font information
  • Text formats
  • Visuals
    • Text with associated formatting information
    • Breaks: line, paragraph, section, page
    • Special characters: tabulator, paragraph begin/end, dash, space, bullet, quote, hyphen
    • Images

The various Visuals represent the recognized visible RTF elements, and can be examined with any IRtfVisualVisitor implementation.

Analogous to the possibilities of the RTF parser, the provided RtfInterpreter supports monitoring the interpretation process with InterpreterListeners for specific purposes.

Analyzing documents might be simplified by using the RtfInterpreterListenerFileLogger interpreter listener, which writes the recognized RTF elements into a log file. Its output can be customized through its RtfInterpreterLoggerSettings. The additional RtfInterpreterListenerLogger interpreter listener can be used to log the interpretation process to any ILogger implementation (see System functions).

Construction of the document model is also achieved through such an interpreter listener (RtfInterpreterListenerDocumentBuilder) which, in the end, delivers an instance of an IRtfDocument.

The following example shows how to make use of the high-level API of the document model:

// ----------------------------------------------------------------------
void RtfWriteDocumentModel( Stream rtfStream )
{
    RtfInterpreterListenerFileLogger logger =
      new RtfInterpreterListenerFileLogger( @"c:\temp\RtfInterpreter.log" );
    IRtfDocument document = RtfInterpreterTool.BuildDoc( rtfStream, logger );
    RtfWriteDocument( document );
} // RtfWriteDocumentModel

// ----------------------------------------------------------------------
void RtfWriteDocument( IRtfDocument document )
{
    Console.WriteLine( "RTF Version: " + document.RtfVersion.ToString() );

    // document info
    Console.WriteLine( "Title: " + document.DocumentInfo.Title );
    Console.WriteLine( "Subject: " + document.DocumentInfo.Subject );
    Console.WriteLine( "Author: " + document.DocumentInfo.Author );
    // ...

    // fonts
    foreach ( IRtfFont font in document.FontTable )
    {
      Console.WriteLine( "Font: " + font.Name );
    }

    // colors
    foreach ( IRtfColor color in document.ColorTable )
    {
      Console.WriteLine( "Color: " + color.AsDrawingColor.ToString() );
    }

    // user properties
    foreach ( IRtfDocumentProperty documentProperty in document.UserProperties )
    {
      Console.WriteLine( "User property: " + documentProperty.Name );
    }

    // visuals (preferably handled through an according visitor)
    foreach ( IRtfVisual visual in document.VisualContent )
    {
      switch ( visual.Kind )
      {
        case RtfVisualKind.Text:
          Console.WriteLine( "Text: " + ((IRtfVisualText)visual).Text );
          break;
        case RtfVisualKind.Break:
          Console.WriteLine( "Tag: " +
                  ((IRtfVisualBreak)visual).BreakKind.ToString() );
          break;
        case RtfVisualKind.Special:
          Console.WriteLine( "Text: " +
                 ((IRtfVisualSpecialChar)visual).CharKind.ToString() );
          break;
        case RtfVisualKind.Image:
          IRtfVisualImage image = (IRtfVisualImage)visual;
          Console.WriteLine( "Image: " + image.Format.ToString() +
           " " + image.Width.ToString() + "x" + image.Height.ToString() );
          break;
      }
    }
} // RtfWriteDocument

As with the parser, the class RtfInterpreterTool offers convenience functionality for easy interpretation of RTF data and creation of a corresponding IRtfDocument. In case no IRtfGroup is yet available, it also provides for passing any source to the RtfParserTool for automatic on-the-fly parsing.

The interface IRtfInterpreterListener, with its base utility implementation RtfInterpreterListenerBase, offers the necessary foundation for a custom interpreter listener:

// ------------------------------------------------------------------------
public class MyInterpreterListener : RtfInterpreterListenerBase
{
    // ----------------------------------------------------------------------
    protected override void DoBeginDocument( IRtfInterpreterContext context )
    {
      // custom action
    } // DoBeginDocument

    // ----------------------------------------------------------------------
    protected override void DoInsertText( IRtfInterpreterContext context,
                                          string text )
    {
      // custom action
    } // DoInsertText

    // ----------------------------------------------------------------------
    protected override void DoInsertSpecialChar( IRtfInterpreterContext context,
                                                 RtfVisualSpecialCharKind kind )
    {
      // custom action
    } // DoInsertSpecialChar

    // ----------------------------------------------------------------------
    protected override void DoInsertBreak( IRtfInterpreterContext context,
                                           RtfVisualBreakKind kind )
    {
      // custom action
    } // DoInsertBreak

    // ----------------------------------------------------------------------
    protected override void DoInsertImage( IRtfInterpreterContext context,
      RtfVisualImageFormat format,
      int width, int height, int desiredWidth, int desiredHeight,
      int scaleWidthPercent, int scaleHeightPercent,
      string imageDataHex
    )
    {
      // custom action
    } // DoInsertImage

    // ----------------------------------------------------------------------
    protected override void DoEndDocument( IRtfInterpreterContext context )
    {
      // custom action
    } // DoEndDocument

} // MyInterpreterListener

The IRtfInterpreterContext passed to all of these methods contains the document information which is available at the very moment (colors, fonts, formats, etc.) as well as information about the state of the interpretation.

RTF Base Converters

As a foundation for the development of more complex converters, there are four base converters available for text, images, XML, and HTML. They are designed to be extended by inheritance.

RTF Interpreter

Text Converter

The RtfTextConverter can be used to extract plain text from an RTF document. Its RtfTextConvertSettings determines how to represent special characters, tabulators, white space, breaks (line, page, etc.), and what to do with them.

// ----------------------------------------------------------------------
void ConvertRtf2Text( Stream rtfStream )
{
    // logger
    RtfInterpreterListenerFileLogger logger =
      new RtfInterpreterListenerFileLogger( @"c:\temp\RtfInterpreter.log" );

    // text converter
    RtfTextConvertSettings textConvertSettings = new RtfTextConvertSettings();
    textConvertSettings.BulletText = "-"; // replace default bullet text '°'

    RtfTextConverter textConverter = new RtfTextConverter( textConvertSettings );

    // interpreter
    RtfInterpreterTool.Interpret( rtfStream, logger, textConverter );
    Console.WriteLine( textConverter.PlainText );
} // ConvertRtf2Text

Image Converter

The RtfImageConverter offers a way to extract images from an RTF document. The size of the images can remain unscaled or as they appear in the RTF document. Optionally, the format of the image can be converted to another ImageFormat. File name, type, and size can be controlled by an IRtfVisualImageAdapter. The RtfImageConvertSettings determines the storage location as well as any scaling.

// ----------------------------------------------------------------------
void ConvertRtf2Image( Stream rtfStream )
{
    // logger
    RtfInterpreterListenerFileLogger logger =
       new RtfInterpreterListenerFileLogger( @"c:\temp\RtfInterpreter.log" );

    // image converter
    // convert all images to JPG
    RtfVisualImageAdapter imageAdapter = new RtfVisualImageAdapter( ImageFormat.Jpeg );
    RtfImageConvertSettings imageConvertSettings =
            new RtfImageConvertSettings( imageAdapter );
    imageConvertSettings.ImagesPath = @"c:\temp\images\";
    imageConvertSettings.ScaleImage = true; // scale images
    RtfImageConverter imageConverter = new RtfImageConverter( imageConvertSettings );

    // interpreter
    RtfInterpreterTool.Interpret( rtfStream, logger, imageConverter );
    // all images are saved to the path 'c:\temp\images\'
} // ConvertRtf2Image

XML Converter

The RtfXmlConverter converts the recognized RTF visuals into an XML document. Its RtfXmlConvertSettings allows to specify the used XML namespace and the corresponding prefix.

// ----------------------------------------------------------------------
void ConvertRtf2Xml( Stream rtfStream )
{
    // logger
    RtfInterpreterListenerFileLogger logger =
      new RtfInterpreterListenerFileLogger( @"c:\temp\RtfInterpreter.log" );

    // interpreter
    IRtfDocument rtfDocument = RtfInterpreterTool.BuildDoc( rtfStream, logger );

    // XML convert
    XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
    xmlWriterSettings.Indent = true;
    xmlWriterSettings.IndentChars = ( "  " );
    string fileName = @"c:\temp\Rtf.xml";
    using ( XmlWriter writer = XmlWriter.Create( fileName, xmlWriterSettings ) )
    {
      RtfXmlConverter xmlConverter = new RtfXmlConverter( rtfDocument, writer );
      xmlConverter.Convert();
      writer.Flush();
    }
} // ConvertRtf2Xml

HTML Converter

The RtfHtmlConverter converts the recognized RTF visuals into an HTML document. File names, type, and size of any encountered images can be controlled through an IRtfVisualImageAdapter, while the RtfHtmlConvertSettings determines storage location, stylesheets, and other HTML document information.

// ----------------------------------------------------------------------
void ConvertRtf2Html( Stream rtfStream )
{
    // logger
    RtfInterpreterListenerFileLogger logger =
      new RtfInterpreterListenerFileLogger( @"c:\temp\RtfInterpreter.log" );

    // image converter
    // convert all images to JPG
    RtfVisualImageAdapter imageAdapter =
       new RtfVisualImageAdapter( ImageFormat.Jpeg );
    RtfImageConvertSettings imageConvertSettings =
                   new RtfImageConvertSettings( imageAdapter );
    imageConvertSettings.ScaleImage = true; // scale images
    RtfImageConverter imageConverter =
            new RtfImageConverter( imageConvertSettings );

    // interpreter
    IRtfDocument rtfDocument = RtfInterpreterTool.Interpret( rtfStream,
                                              logger, imageConverter );

    // html converter
    RtfHtmlConvertSettings htmlConvertSettings =
           new RtfHtmlConvertSettings( imageAdapter );
    htmlConvertSettings.StyleSheetLinks.Add( "default.css" );
    RtfHtmlConverter htmlConverter = new RtfHtmlConverter( rtfDocument,
                                                 htmlConvertSettings );
    Console.WriteLine( htmlConverter.Convert() );
} // ConvertRtf2Html

HTML Styles can be integrated in two ways:

  • Inline through RtfHtmlCssStyle in RtfHtmlConvertSettings.Styles
  • Link through RtfHtmlConvertSettings.StyleSheetLinks

RtfHtmlConvertScope allows to restrict the target range:

  • RtfHtmlConvertScope.All: complete HTML document (=Default)
  • ...
  • RtfHtmlConvertScope.Content: only paragraphs

RTF Converter Applications

The console applications Rtf2Raw, Rtf2Xml, and Rtf2Html demonstrate the range of functionality of the corresponding base converters, and offer a starting point for the development of our own RTF converter.

Rtf2Raw

The command line application Rtf2Raw converts an RTF document into plain text and images:

Rtf2Raw source-file [destination] [/IT:format] [/BC:color] [/CE:encoding]
                    [/IS] [/XS] [/UI] [/ST] [/SI] [/LD:path] [/IDF] [/IUF] [/LP]
                    [/LI] [/D] [/O] [/HT] [/?]

      source-file       source rtf file
      destination       destination directory (default=source-file directory)
      /IT:format        images type format: bmp, emf, exif, gif, icon, jpg,
                               png, tiff or wmf (default=original)
      /BC:color         image background color name (default=none)
      /CE:encoding      character encoding: ASCII, UTF7, UTF8, Unicode,
                               BigEndianUnicode, UTF32, OperatingSystem (default=UTF8)
      /IS               image scale (default=off)
      /XS               extended image scale - border fix (default=off)
      /UI               enforce unscaled images (default=off)
      /ST               don't save text to the destination (default=on)
      /SI               don't save images to the destination (default=on)
      /LD:path          log file directory (default=destination directory)
      /IDF              ignore duplicated fonts (default=off)
      /IUF              ignore unknown fonts (default=off)
      /LP               write rtf parser log (default=off)
      /LI               write rtf interpreter log (default=off)
      /D                write text to screen (default=off)
      /O                open text in associated application (default=off)
      /HT               show hidden text (default=off)
      /?                this help

Samples:
     Rtf2Raw MyText.rtf
     Rtf2Raw MyText.rtf c:\temp
     Rtf2Raw MyText.rtf c:\temp /CSS:MyCompany.css
     Rtf2Raw MyText.rtf c:\temp /CSS:MyCompany.css,ThisProject.css
     Rtf2Raw MyText.rtf c:\temp /CSS:MyCompany.css,ThisProject.css /IT:png /BC:white
     Rtf2Raw MyText.rtf c:\temp /CSS:MyCompany.css,ThisProject.css /IT:png /BC:white
                                /LD:log /LP /LI

Rtf2Xml

The command line application Rtf2Xml converts an RTF document into an XML document:

Rtf2Xml source-file [destination] [/CE:encoding] [/P:prefix]
                    [/NS:namespace] [/LD:path] [/IDF] [/IUF] [/LP] [/LI] [/HT] [/?]

      source-file       source rtf file
      destination       destination directory (default=source-file directory)
      /CE:encoding      character encoding: ASCII, UTF7, UTF8, Unicode,
                               BigEndianUnicode, UTF32, OperatingSystem (default=UTF8)
      /P:prefix         xml prefix (default=none)
      /NS:namespace     xml namespace (default=none)
      /LD:path          log file directory (default=destination directory)
      /IDF              ignore duplicated fonts (default=off)
      /IUF              ignore unknown fonts (default=off)
      /LP               write rtf parser log (default=off)
      /LI               write rtf interpreter log (default=off)
      /HT               show hidden text (default=off)
      /?                this help

Samples:
     Rtf2Xml MyText.rtf
     Rtf2Xml MyText.rtf c:\temp
     Rtf2Xml MyText.rtf c:\temp /NS:MyNs
     Rtf2Xml MyText.rtf c:\temp /LD:log /LP /LI

Rtf2Html

The command line application Rtf2Html converts an RTF document into an HTML document:

Rtf2Html source-file [destination] [/CSS:names] [/IS] [/ID:path]
                     [/IT:format] [/BC:color] [/XS] [/CE:encoding] [/CS:charset]
                     [CS:mappings] [/DS:scope] [/IDF] [/IUF] [/SH] [/UI] [/SI] [/LD:path]
                     [/LP] [/LI] [/D] [/O] [/HT] [/NBS] [/CH] [/HP:pattern] [/?]

      source-file             source rtf file
      destination             destination directory (default=source-file directory)
      /CSS:name1,name2        style sheet names (default=none)
      /IS                     use inline styles (default=on)
      /ID:path                images directory (default=destination directory)
      /IT:format              images type format: jpg, gif or png (default=jpg)
      /BC:color               image background color name (default=none)
      /XS                     extended image scale - border fix (default=off)
      /CE:encoding            character encoding: ASCII, UTF7, UTF8, Unicode,
                                     BigEndianUnicode, UTF32, OperatingSystem (default=UTF8)
      /CS:charset             document character set used for the HTML header meta-tag
                                     'content' (default=UTF-8)
      /SC:mapping1,mapping2   special character mapping (default=none)
                                     mapping: special-character=replacement
                                     special characters: Tabulator, NonBreakingSpace,
                                     EmDash, EnDash, EmSpace, EnSpace, QmSpace,
                                     Bullet, LeftSingleQuote,
                                     RightSingleQuote, LeftDoubleQuote,
                                     RightDoubleQuote, OptionalHyphen, NonBreakingHyphen
      /DS:scope               document scope, comma separated list of document sections:
                                     doc, html, head, body, content, all (default=all)
      /IDF                    ignore duplicated fonts (default=off)
      /IUF                    ignore unknown fonts (default=off)
      /SH                     don't save HTML to the destination (default=on)
      /SI                     don't save images to the destination (default=on)
      /UI                     enforce unscaled images (default=off)
      /LD:path                log file directory (default=destination directory)
      /LP                     write rtf parser log file (default=off)
      /LI                     write rtf interpreter log file (default=off)
      /D                      display HTML text on screen (default=off)
      /O                      open HTML in associated application (default=off)
      /NBS                    use non-breaking spaces (default=off)
      /HT                     show hidden text (default=off)
      /CH                     convert visual hyperlinks (default=off)
      /HP:pattern             regular expression pattern to recognize visual hyperlinks
      /?                      this help

Samples:
     Rtf2Html MyText.rtf
     Rtf2Html MyText.rtf /DS:body,content
     Rtf2Html MyText.rtf c:\temp
     Rtf2Html MyText.rtf c:\temp /CSS:MyCompany.css
     Rtf2Html MyText.rtf c:\temp /CSS:MyCompany.css,ThisProject.css
     Rtf2Html MyText.rtf c:\temp /CSS:MyCompany.css,ThisProject.css
                                 /ID:images /IT:png /BC:white
     Rtf2Html MyText.rtf c:\temp /CSS:MyCompany.css,ThisProject.css
                                 /ID:images /IT:png /BC:white /LD:log /LP /LI
     Rtf2Html MyText.rtf c:\temp /SC:Tabulator=>,Bullet=:

RTF to HTML Input

Sample RTF to HTML Converter - RTF Input

RTF to HTML Output

Sample RTF to HTML Converter - HTML Output

Projects

The following projects are provided in the RTF converter component:

SysSystem functions. See below for a short description.
ParserParsing of RTF data.
ParserTestsUnit tests for parser.
InterpreterInterpretation of parsed RTF data. Functionality for conversion of RTF to plain text and images.
InterpreterTestsUnit tests for interpreter.
ConverterXmlFunctionality for conversion of RTF to XML.
ConverterHtmlFunctionality for conversion of RTF to HTML.
Rtf2RawCommand line application to convert from RTF to text- and image data.
Rtf2XmlCommand line application to convert from RTF to XML.
Rtf2HtmlCommand line application to convert from RTF to HTML.
RtfWinFormsWindows Forms sample application which demonstrates a simple conversion from RTF to Text/XML/HTML.
RtfWindowsWPF sample application which demonstrates a simple conversion from RTF to Text/XML/HTML.

System Functions

The project Sys contains some base functionality for use in all the other applications/projects:

HashToolFunctions to simplify implementing overrides of the object.GetHashCode() method.
StringToolFunctions for String formatting.
CollectionToolFunctions to simplify handling of collections.
ApplicationArgumentsFunctions to interpret command line arguments. Offers support for the argument types ToggleArgument, ValueArgument, and NamedValueArgument.
LoggingFunctionality to abstract the embedding of a Logger facility. Supports the logger types LoggerNone, LoggerTrace, and LoggerLog4net.
TestFunctionality to build a unit-based test application.

Acknowledgement

Special thanks to Leon Poyyayil for the design and his support and contribution in the development of this component.

History

  • 1th August, 2013 - v1.7.0.0
    • RtfHtmlConverter: Replaced align attributes with style attributes
  • 20th January, 2013 - v1.6.0.0
    • RtfHtmlConverter: Added support for HTML tags superscript and subscript
    • RtfImageBuilder.VisitTag: Fixed negative image dimensions by enforcing the absolute value
    • RtfFontTableBuilder: Added option to ignore duplicated fonts
    • RtfInterpreter: Added option to ignore unknown fonts
    • RtfInterpreterSettings: New class to customize the interpreter
    • RtfInterpreter/RtfInterpreterTool: Added support fo the interpreter settings
    • Rtf2Xml/Rtf2Raw/Rtf2Html: New command line argument /IDF to ignore duplicated fonts
    • Rtf2Xml/Rtf2Raw/Rtf2Html: New command line argument /IUF to ignore unknown fonts
    • Rtf2Raw/Rtf2Html: New command line argument /UI to enforce unscaled images
  • 12th September, 2012 - v1.5.0.0
    • ToggleArgument: Fixed parsing of the off-toggle
    • RtfInterpreter: Allowed font with zero size
    • RtfEmptyHtmlStyleConverter: New class with empty style converter
    • Rtf2Html: New command line argument /IS to suppress inline styles using RtfEmptyHtmlStyleConverter
  • 3rd March, 2011 - v1.4.0.0
    • RtfTextFormat: Fixed reset of super script in DeriveWithSuperScript
  • 26th April, 2011 - v1.3.0.0
    • RtfVisualImageAdapter: Relaxed handling for non-hex image data
  • 8th April, 2011 - v1.2.0.0
    • RtfFontBuilder: Relaxed handling for missing font names, generating font name 'UnnamedFont_{fond-id}'
  • 14th February, 2011
    • Replaced RtfHmltCpecialCharConverter with RtfHtmlSpecialCharCollection
    • RtfHtmlConverter: New property SpecialCharacters
  • 25th January, 2011
    • RTF Interpreter: Fixed retroactive paragraph changes
  • 1st December, 2010
    • RtfHtmlSpecialCharConverter: New class to handle special character conversion
    • RtfHtmlConverterSettings: New property SpecialCharsRepresentation
    • RtfHtmlConverter: Added support for special character conversion
    • Rtf2Html: New command line argument /SC to control the special character conversion
    • Removed projects and solutions for Visual Studio 2005
    • Added projects and solutions for Visual Studio 2010
  • 20th August, 2009
    • RtfHtmlConverterSettings: New property UseNonBreakingSpaces
    • Rtf2Html: New command line argument /NBS to replace spaces with non-breaking spaces (default=off)
  • 18th August, 2009
    • Signed assemblies
    • RtfImageConverterSettings: New property BackgroundColor
    • Rtf2Raw, Rtf2Html: New command line argument /BC for the image background color
  • 3rd August, 2009
    • RtfHtmlConverter: Replacing text spaces with non-breaking-spaces
    • RtfImageConverter: Fixed missing converted image info in case of undefined target format
  • 20th May, 2009
    • RtfHtmlConverter: Added support for Justify alignment
    • RtfHtmlConverter: Fixed missing closing tag </ul> for bulleted lists, in cases when ConvertScope is set to Content
  • 5th May, 2009
    • RtfSpec: New tag highlight for highlighted text
    • RtfInterpreter: Added support for text highlighting
    • Rtf2Raw, Rtf2Xml, Rtf2Html: Enumeration ProgramExitCode contains all program exit codes
  • 20th February, 2009
    • RtfParser: Various new specialized exceptions based on RtfParserException
    • RtfInterpreter: Various new specialized exceptions based on RtfInterpreterException
    • Projects Sys, Parser, and Interpreter: Extracted localizable strings to Strings.cs and Strings.resx
    • Rtf2Html: New command line argument /DS to control the conversion scope
  • 18th February, 2009
    • RtfSpec: New tag nonshppict for alternative images
    • RtfInterpreter: Ignoring alternative images
    • RtfInterpreterTest: New unit-test for alternative images
  • 16th February, 2009
    • RtfImageConvertSettings: New properties ScaleOffset and ScaleExtension to control image scaling
    • Rtf2Raw and Rtf2Html: New command line argument /XS to fix the BorderBug
    • Changed binaries from debug to release (slightly better performance)
  • 5th February, 2009
    • RtfInterpreter: Extended group handling to recognize state transition from header to document in case no other mechanism detects it and the content starts with a group with such a 'destination'
  • 3rd February, 2009
    • Rtf2Html: Added support to convert visual hyperlinks
    • New command line argument /CH to convert visual hyperlinks (default is off)
    • New command line argument /HP:pattern with the Regular Expression pattern to recognize visual hyperlinks (optional)
    • Programmatic control with RtfHtmlConvertSettings.ConvertVisualHyperlinks and RtfHtmlConvertSettings.VisualHyperlinkPattern
    • Only visible hyperlinks will be converted; does not support hyperlinks which are represented by a display text and the actual hyperlink stored in a (hidden) field content
    • Refactored code - or rather 'ReSharped' Smile | <img src= " src="http://www.codeproject.com/script/Forums/Images/smiley_smile.gif" />
  • 22nd October, 2008
    • RtfParser: Fixed to properly handle skipping of Unicode alternative representation in case these are written in hex-encoded form
    • RtfHtmlConverter: New property DocumentImages which provides information about the converted images using IRtfConvertedImageInfo
    • Added ChangeHistory.txt
  • 15th October, 2008
    • Added support for tags
      • \sub: Changes font size to 2/3 of the current font size and moves 'down' by half the current font size
      • \super: Changes font size to 2/3 of the current font size and moves 'up' by half the current font size
      • \nosupersub: Resets the 'up'/'down' baseline alignment to zero; Attention: this leaves the font size unchanged as it is not known by the current implementation what the 'previous' font size was; hence, depending on the RTF-writer, this might lead to content that is displayed with a smaller font size than intended
      • \v*: Toggles the new IsHidden property of IRtfTextFormat; \v and \v1 turn it on while \v0 turns it off (according to the behavior or 'boolean tags')
      • \viewkind: Triggers the transition from interpreter state InHeader to InDocument (but only if the font table is already defined); this supports documents without color table and prevents formatting or content at the beginning from being ignored
    • Extended/fixed support for tags
      • \dn and \up: will use the specified default value of '6' if none is given in the RTF (instead of resetting to zero)
    • RtfTextConverterSettings/ RtfXmlConverterSettings/ RtfHtmlConverterSettings: have a new flag IsShowHiddenText which defaults to false
    • RtfTextConverter/ RtfXmlConverter/ RtfHtmlConverter: will only append found text to the plain text buffer if it is not marked hidden in its text format or if the new setting IsShowHiddenText is explicitly set to true
    • Rtf2Raw/Rtf2Xml/Rtf2Html: New command-line argument /HT to convert hidden text
    • RtfWinForms/RtfWindows: Conversion is considering the text selection
    • Added projects and solutions for Visual Studio 2005
    • Download now contains the binaries
  • 13th October, 2008
    • RtfImageConverter: New property ConvertedImages which provides information about the converted images using IRtfConvertedImageInfo
  • 3rd October, 2008
    • RtfHtmlConverter: Fixed encoding of image file names
  • 26th September, 2008
    • Added support for \pict tags wrapped in a \*\shppict group
    • RtfGroup: Extended debugging visualization
  • 23rd September, 2008
    • RtfParser: Fixed local group fonts
  • 18th September, 2008
    • RtfSpec: New tag constants for the theme fonts and stylesheet
    • RtfParser: Added support for dealing with theme fonts during decoding (ugly but necessary when such fonts are used for hex encoded content)
    • RtfFontBuilder: Added support for theme fonts
    • RtfFontBuilder: Added support for font names with an alternative representation
    • RtfFontTableBuilder: Added support for theme fonts
    • RtfInterpeter: Added special support for stylesheets by ignoring their content (to prevent the style names from appearing in the document content)
    • Added the test document (in two variants) as unit test input
  • 31st July, 2008
    • New Windows Forms sample application which demonstrates a simple conversion from RTF to Text/XML/HTML
    • New WPF sample application which demonstrates a simple conversion from RTF to Text/XML/HTML
    • IRtfInterpreterContext: Replaced int DefaultFontIndex by string DefaultFontId to support WPF RichTextBox font indexing
  • 14th July, 2008
    • RtfHtmlConverter: New class IRtfHtmlStyleConverter which provides external style conversion
    • RtfHtmlConverter: Changed default image type from GIF to JPEG
    • RtfHtmlConverter: Fixed alignment of images
  • 11th July, 2008
    • Support for character set decoding per font
    • Support for decoding multi-byte hex-encoded characters (this handles East Asian fonts commonly encoded in this way instead of using Unicode)
    • Special treatment for the Windows legacy pseudo codepage 42 (mapped to the ANSI codepage)
    • All command line applications: new command line parameter /CE for specifying the output encoding (such as UTF-8 or UTF-16 a.k.a. Unicode)
    • Rtf2Html: Fixed HTML-encoded string
    • Command line application Rtf2Html: New command line parameter /CS for the HTML character set
    • RtfParserTest and RtfInterpreterTest: New unit-tests for multi-byte character set decoding
    • Minor bug fixes
  • 3rd July, 2008
    • Command line applications: Fixed exception in cases when log parser is not used
  • 1st July, 2008
    • Initial public release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author


Comments and Discussions

 
GeneralOut of memory exception Pin
japss18-Apr-11 12:59
memberjapss18-Apr-11 12:59 
AnswerRe: Out of memory exception Pin
Jani Giannoudis20-Apr-11 4:39
memberJani Giannoudis20-Apr-11 4:39 
GeneralRe: Out of memory exception Pin
japss26-Apr-11 8:03
memberjapss26-Apr-11 8:03 
AnswerRe: Out of memory exception Pin
Jani Giannoudis26-Apr-11 8:34
memberJani Giannoudis26-Apr-11 8:34 
AnswerRe: Out of memory exception [v1.3.0.0] Pin
Jani Giannoudis26-Apr-11 19:17
memberJani Giannoudis26-Apr-11 19:17 
GeneralRe: Out of memory exception [v1.3.0.0] Pin
japss6-May-11 12:39
memberjapss6-May-11 12:39 
AnswerRe: Out of memory exception [v1.3.0.0] Pin
Jani Giannoudis6-May-11 22:17
memberJani Giannoudis6-May-11 22:17 
GeneralIt is missing header and footer while converting rtf to html Pin
Robkapsig12-Apr-11 2:18
memberRobkapsig12-Apr-11 2:18 
I am trying to get the whole rich text file to be incorporate to HTML the same way it look in windows document.

That is my rtf code below.
Thanks,
Rob


{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}
{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f16\froman\fcharset238\fprq2 Times New Roman CE;}{\f17\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f19\froman\fcharset161\fprq2 Times New Roman Greek;}
{\f20\froman\fcharset162\fprq2 Times New Roman Tur;}{\f21\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f28\fmodern\fcharset238\fprq1 Courier New CE;}{\f29\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f31\fmodern\fcharset161\fprq1 Courier New Greek;}
{\f32\fmodern\fcharset162\fprq1 Courier New Tur;}{\f33\fmodern\fcharset186\fprq1 Courier New Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;
\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{
\widctlpar\adjustright \fs20\cgrid \snext0 Normal;}{\s1\keepn\nowidctlpar\outlinelevel0\adjustright \b\i\fs72\cf1 \sbasedon0 \snext0 heading 1;}{\s2\keepn\nowidctlpar\outlinelevel1\adjustright \b\fs36\cf1 \sbasedon0 \snext0 heading 2;}{
\s3\keepn\nowidctlpar\outlinelevel2\adjustright \cf1 \sbasedon0 \snext0 heading 3;}{\*\cs10 \additive Default Paragraph Font;}{\s15\widctlpar\tqc\tx4320\tqr\tx8640\adjustright \fs20\cgrid \sbasedon0 \snext15 header;}{\s16\widctlpar
\tqc\tx4320\tqr\tx8640\adjustright \fs20\cgrid \sbasedon0 \snext16 footer;}{\*\cs17 \additive \ul\cf2 \sbasedon10 Hyperlink;}{\s18\qc\nowidctlpar\adjustright \i\fs20\cf1 \sbasedon0 \snext0 caption;}}{\info{\title Top of typing area}{\author Jan Bloom}
{\operator DLLR}{\creatim\yr2003\mo4\dy22\hr10\min29}{\revtim\yr2003\mo4\dy22\hr10\min29}{\version2}{\edmins0}{\nofpages1}{\nofwords0}{\nofchars0}{\*\company State of Maryland}{\nofcharsws0}{\vern89}}\margl360\margr360\margt360\margb360
\widowctrl\ftnbj\aenddoc\hyphcaps0\formshade\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot \fet0\sectd \linex0\headery360\footery360\endnhere\titlepg\sectdefaultcl {\headerf \trowd \trgaph108\trrh1080\trleft-108 \clvertalt\cltxlrtb \cellx4140
\clvertalt\cltxlrtb \cellx11610\pard\plain \s1\keepn\nowidctlpar\intbl\outlinelevel0\adjustright \b\i\fs72\cf1 {\fs96 DLLR}{\i0\fs96 \cell }\pard \s1\qr\keepn\nowidctlpar\intbl\outlinelevel0\adjustright {\b0\i0\fs20 MARTIN O'MALLEY, Governor
\par }\pard\plain \qr\widctlpar\intbl\adjustright \fs20\cgrid {ANTHONY G. BROWN, Lt. Governor
\par THOMAS E. PEREZ, Secretary\cell }\pard \widctlpar\intbl\adjustright {\i \row }\pard\plain \s2\keepn\nowidctlpar\outlinelevel1\adjustright \b\fs36\cf1 {STATE OF MARYLAND
\par }\pard\plain \s3\keepn\nowidctlpar\outlinelevel2\adjustright \cf1 {\ul DEPARTMENT OF LABOR, LICENSING AND REGULATION__________________________________________
\par }\pard\plain \qr\nowidctlpar\adjustright \fs20\cgrid {\fs16\cf1\cgrid0 DLLR Home Page * }{\field{\*\fldinst {\fs16\cf1\cgrid0 HYPERLINK http://www.dllr.state.md.us }{\cf1\cgrid0 {\*\datafield
00d0c9ea79f9bace118c8200aa004ba90b02000000170000001c00000068007400740070003a002f002f007700770077002e0064006c006c0072002e00730074006100740065002e006d0064002e00750073000000e0c9ea79f9bace118c8200aa004ba90b3a00000068007400740070003a002f002f007700770077002e00
64006c006c0072002e00730074006100740065002e006d0064002e00750073002f000000000000000000000000000000000020010000000000000000000000005000000000000000000000000000b44c00000000000000000000005600000000000000000000ffffff00}}}{\fldrslt {\cs17\ul\cf2
http://www.dllr.state.md.us}}}{\fs16\cf1\cgrid0
\par DLLR E-mail * dllr@dllr.state.md.us
\par }}{\footerf \pard\plain \li1440\nowidctlpar\adjustright \fs20\cgrid {\cf1\cgrid0
\par }\trowd \trgaph108\trleft-108 \clvertalt\cltxlrtb \cellx4770\clvertalt\cltxlrtb \cellx6210\clvertalt\cltxlrtb \cellx11628\pard \nowidctlpar\intbl\adjustright {\cf1\cgrid0
\par
\par
\par 1100 N. EUTAW STREET }{\cf1\cgrid0 {\field{\*\fldinst SYMBOL 240 \\f "Symbol" \\s 10}{\fldrslt\f3\fs20}}}{\cf1\cgrid0 BALTIMORE, MD 21201\cell }{\cf1\cgrid0 {\*\shppict{\pict{\*\picprop\shplid1026{\sp{\sn shapeType}{\sv 75}}{\sp{\sn fFlipH}{\sv 0}}
{\sp{\sn fFlipV}{\sv 0}}{\sp{\sn pibName}{\sv \'51\'3a\'5c\'56\'6f\'32\'35\'62\'5c\'42\'69\'74\'6d\'61\'70\'73\'5c\'53\'45\'41\'4c\'4e\'32\'2e\'42\'4d\'50}}{\sp{\sn pibFlags}{\sv 2}}{\sp{\sn fillColor}{\sv 268435473}}
{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fLine}{\sv 0}}}\picscalex29\picscaley29\piccropl0\piccropr0\piccropt0\piccropb0\picw7253\pich8024\picwgoal4112\pichgoal4549\pngblip\bliptag-1436411371{\*\blipuid aa621a15813862e134fbe4d205a62f30}
89504e470d0a1a0a0000000d49484452000000bc000000d0010300000087b199c90000000467414d410000b1889598f4a600000006504c5445000000ffffffa5
d99fdd000000097048597300000a2000000a2001d1aaeda8000007c449444154789ccdd7418b1bc91500e0d753ceb642c4b496c94126b24acb1ef62ab3970928
d30a0e760e81fc84c8bbc1be2c8b865ce4a0a85bcc609960acc042c86141fb1ff6929b5bab103964621d72c921303dab25ba84a8c722b8b5aaa9daf7aaba359a
d9d642420ed18c87567fae7aafbaaaab5f83cafe44f0ff027de56e03febf02476443a4826c58283f1b3c054e164825b34128910d17db21ca86a50ab78000c84c
77b9f033417c7b90dd42e45cb0b320820370b320acd7b2e18f50dde559e04335cfdd0c0822c80e3e446059300e2070caeed76112c109bff5fceba062eb78c2b3
20027f7c99d606bc0ec1fa5746703a86832de07c6b0bd8d616b0b60164438cd72413c456e0ea281bf696a32d31eaf696183fce5c89df087c5bbad920b78182dc
36d8da02bc6cf0c1cd86602bfc684b57a3780b04db827f03fca75901f43301afeef5a93dd3c7b87cceae41e0996338bf064703133b5773b7c08186680dbd53fa
8b77fa29a5255b5e0a6ca2b3cdbb929689f478029135a7ef387fbeadb3eb2710be394b000cfc3481808fcd30cc728f890d38b34d88d6e0eb1e428006d4ae01fd
c760079a40238c37c07a8e7f193459895f8901805040700afd4d086fe00cc97d065546438d076b78438395c2f314623b20d0e912f035309a103a0f16c6103b6b
d03b42a005b3901b609be940c071c8379c04a4197903cf5708ca29988b1a552069514b4118d0316859d0153213751dacf525b9043cf812da09f4429ece87e940
7a066cbfec111c1fe6e96b37b8302d24835d975238795daad32cd49318d2958f70c589ef568047147c329d691008a7690c046f323310633f934b906a2ea706bc
2b8091e5f91ae6b44a9a0ebc70f199abe45243642040b0fee6aad5ba4528bdd385ea07d006f67b77f25a0de4f70d086fb0a067d44fc02efc6036eba770166385
2121f91c0eece7f2968621de418b7fa650776d258b1a8e424ffdf9449f2de0bf0e53a2a4a147f0346d41101f18182a75b23e0fc21245034743758a90c727a7a8
801559b278e011d8476a320999c3022eaac07c0bbb4a613e9eb23e42bc8f60abb86cc0f7d468874d58c8a31a06e9e16276112441c0d898852e42017af3ab304a
c0eecd853d4860ee3316ac01bbe2690bffdd3b083fc3acf63c82c1258c1028dd3dd59bc4ce20cd0a1653ea4a03fb0bd829ccd96281502290b09f40d7b743be10
088552b58620caf6c48015ba087770d3d0d029a580f7cb42c02f10f6d59ef2f18269f0831b1a0e43baa13e527ea1602068e43a04ad90fd35c0acba2a643a78d8
cc7b061c15e8717c6e9d6ac03d4f03a4101b88b067aec11e1a882caed72ec14ae45ac086e3e147aadb0b13c869c8b7c0ea8e479895ed5b3ab8c873ea6ab7857b
cc78fa296e782d03f24083b34f80e3e8fa42cf87921d47433167a0771d7279b04604dd38055b0d1060176c827ed7cca0921f3075ba42c09f40b710d65cef0c75
6b39d980c79002400af610e1186402b85327c028868f37233760fbf6aa4da0b3faf52570ff68b58f59d5a127f63046abea25d01d1138b8a38506cc7e05bc3b5e
d1cd445bef9b984bd242ae01341437c09fae5cda64981feec922342aae0157431d9fce414400159e76355b795113e07d02dab01d0d9f6808111604b863bfa5e1
c24080704e70008db7f482bb68d8ddc54a25c008ee6b58224c4d5711508b5c745f5fc458838a52e0c54be84d175ed4808281526ce04b0371038a1aca25614036
f1ee5f7938c0b289514e010b5d7b130ea4817f538dbf8ae27aa15c2d6ae86c42b359af96aba54d384370f0b237c401d49a083579153c822a665593ef27d0004e
20cb1a766bf2e18ce04f51a3a8412014104a094cc2b0cc572eae2704a001ca7b6382711872be4ce15d592a751e8ecd861cbafcc2ed21ec941076af82c39e4199
610b552e75dee921043676e50a607dbbccfe4e506bcf087c3b6a965de1b3be2ab313785b156bbf9ad1f2f1dfd9803fe0d33fd77ef40f5a709f40189595a86b08
76eea952023f6f545f21800198a88f3b1ae407adeae7b7e8e9ee6818a8df25f061a7f900a162db04165fb7f8b0d37a70134b1fe74871dcae5df5ac73a8e1aed4
f0c2c08e8b2d0e4303edf76e525976445ddd50aa8480e390f784019b11e494aa750e030d4bf9e07b5413ea74ef28d9de006c21ea3add1116966d1d43d94b455d
891c82f5d45171bbfd48d70c470bf55e11971dc5b062ae62d932d0edc96619cbaad099944a585fd871f37c45f01b473671ab50119b172b0c5bc68767bac5132e
9a70872a981ac306c20bee4d35bcf0e2a6ae2045de61548cf8f8f832c54473a7a58bea40972b672aa87103057ba5ebe8d014dd2a6c1930959a2e5375494d5b45
0218f354d7595c43544ccb28da5f1cac0fd5c8bc2de28344c76063f50576275c75aecb36d9b01378fc108787676910a02e8e2b698bc7f75f465dec47bd7283ca
dddc7123c9ca797a787211c89bae3a1b07adbb705c4882b38f6f9fa840ecf3dbc36900089096cef2f6491dce9f3c81d17e003b377e7b3f2d84d512cb8f51fe09
bcace50057ef685da4e26fde85a8d97e1b4b0de5af8bd480e346e8ed8c44cd1a7ec1635803ed8f6cd173a4f343ba085cad5f7ef0bdc7feb4cfa533cce3d1f34b
c0b1ac189659e12b4b9837d5f5eb52ed26a399fea5f5d975c84da8c8e7d6e8d906e0c4d5e02555cd8e353ebedaa2f41d7a17c20d6774adabbc33d4df5b9ff1ab604b3df1c209ddab90bef2a5afb06b88ac74a5a8ab907e626b0ba49fff02be029dbe8271003d3cf80000000049454e44ae426082}}{\nonshppict
{\pict\picscalex29\picscaley29\piccropl0\piccropr0\piccropt0\piccropb0\picw7253\pich8024\picwgoal4112\pichgoal4549\wmetafile8\bliptag-1436411371\blipupi65{\*\blipuid aa621a15813862e134fbe4d205a62f30}
0100090000030a0a00000000e609000000000400000003010800050000000b0200000000050000000c02d000bc0005000000070104000000e6090000430f2000
cc000000d000bc0000000000d000bc000000000028000000bc000000d0000000010001000000000080130000200a0000200a0000020000000200000000000000
ffffff00fffffffffffffffffffffffffffffffffffffffffffffff0fffffffffffffffffffffffffffffffffffffffffffffff0ffffffffffffffffffffffff
fffffffffffffffffffffff0fffffffffffffffffffffffffffffff801fffffffffffff0fffffffffffffff001ffffffffffffe000fffffffffffff0ffffffff
ffffffc0003fffffffffff00007ffffffffffff0ffffffffffffff07fe07fffffffffc0fe03ffffffffffff0ffffffffffffff0c0fc1fffffffff078c21fffff
fffffff0ffffffffffffff1c0bf0ffffffffe1f0c30ffffffffffff0ffffffff7fffff3c00ce3ffffffe0f01c784fffffffffff0ffffffffffffff3c08cf8fff
fff81f01c38efffffffffff0ffffffffffffff3c1903e1fffff07a01c20ffffffffffff0fffffffffffffe0ffb03f0ffffe0f201fc0ffffffffffff0ffffffff
fffc000007b38f1ffe0fc10c000007bffffffff0fffffffffe00000003f3870ffe0f41f80000001ffffffff0ffffffffc01ffe00007f02c3fc3c01c1e41ff800
0ffffff0fffffffe00fffe000c3f00f0707c2303c01fff800ffffff0ffffffe0fff9cc0000c30c8800ce3c08000207ffc3fffff0ffffff80fe31cc4000f18888
00c338c00002049661fffff0ffffff039c31ccffc0fc381f31c1e3c00046008400fffff0fffffe0f8c71ccfdc0fe193fffe1c7c078460084107ffff0fffff803
8661cef081ffc3fffff23fc020460884601ffff0fffff8038667fff003fff1fffffc7fc000fffd84200ffff0fffff803c7ffe40007fffc3ffff1fff00007fffe
6007fff0ffffff07f80000000ffffc02ffc3fff0000001ffe00ffff0fffffe0001ffffdfffffffc0001ffffffffffff0187ffff0fffffe0007ffffffffffffe0
003ffffffffffffe003ffff0fffff81007fbffffffffffe0c07fffffffffffe0781ffff0fffff87002787fffffffffc0f07fffffffe1ffc03c1ffff0ffc87ff8
700003fffffffc0c0f03fffffc3f800787fffff0ff881ffc700043fffffff03c0301fffffc7fc047e3fffff0ff900ffe7001c3fffff003ef182003fffe07f871
e1fffff0ff8187fe701e8fffffe00fcf1c1c01ffff07f870f1fbfff0ff83f3ff6218fffffe0703ff1e01f81ffff8fe7879fffff0ff07f9ff6219fffffc080fff
1e018c0ffff87c7c79fffff0fe47f9fe6619fffffc400fff1e03c0c3fffe787c71e07ff0fe47f9fe661bfffff0018fff1e03c043fffe7c7e71c03ff0fe47fc7c
6219ffffc00703ff1e03c008ffff3c7e71c03ff0fe46fe7c6219ffffc00f83ff1e03c004ffff1c7e71e03ff0fe46fe786619ffffc80f83ff1f03c0023fff9c7e
71e07ff0fe6e7e786619ffff100f83ff1f03c0033fff8e7e71e67ff0fe6e7e70661dffff200707ff1e03c0011fff9c7e79e67ff0fe6c7830e21dffff00030fff
1e03c0009fff987e79e67ff0ff646030f21efffc00038fff1e03c000cfff9c7e79e67ff0ffa000e0f01efffc40038fff1e03c00247ff1c7c79e67ff0ff8027f0
701e3ffc80038fff1e03c40207ff087c79e67ff0ff8007f0701e3ffc80038fff1e03cc0023ff183c7de73ff0ffc007e0e01f3ffc00038f071e03dc0033ff1e3c
7ce787f0ffff87e0e03f1ffd0f038e001e033c0033ff1e1c7e2787f0ffff87e0e03f1ffd3f8780001e021c0033fe0e1c7e67c7f0ffffc7e0e01f1ff93fff8000
1e003c0033fe1c1c7e67c7f0ffffcfe0e01e1ffb3fff80001e003c0013fe1e1cfe47c7f0ffffc9f060181ffb00007ffc1e003c1013fe0e1cfe67e7f0ffffe1f0
60001ffb00007ffe1e003c3013fe0e3cfe67e7f0ffffe1f000000ffb00007ffc3e003c3013fe1e3cfe63eff0ffffe1f000000ffb000060fc3e003c7013fe3e3c
fe61eff0fffff5f0000003fb707040301e301cf013fe3e3e7e61eff0fffff5f0000003fbf0f840101e3018f013fe3e3e7e61eff0fffffef0000107fb7ff84000
1ef000f013fe3e3efe61eff0fffffe700303c7fb7ff840001ef000f013fe3e1efc61eff0fffffa600787e3f37ff8600018f000f013fe1e1cfc61eff0fffff860
0787e3f37ff0600010f000f013fe1f1cf861eff0fffff8600781e3fbfff0700000f000f013fe1f18f061eff0fffff9600781e3fb7fe0700000f000f013fe3e08
f061eff0fffffd600781f3fbffc0700000f1c0f003fe3e006061cff0fffffda01f81e7fb7fc0700000f1c0f013fe3e006021cff0fffffea01f81e7fb7fe07000
00f3c0f013fe200000210ff0fffffe001f81e7fb7ff070000063c0f013fe000000200ff0fffffe003f80e3fb3ff8400000c3c0f013fe180000201ff0fffffe00
1f80e3fb3ff80000000380e013fe180060203ff0fffffe001f81c7fb000000000000000011ff180078307ff0ffffff001f81c7fb00000000c000000011ff0000
78307ff0ffffff801f81c3fb380f000fc00007e013ff86007830fff0ffffff801f8083fb380f000e400087fc13ff860078307ff0ffffff80078007fb7c0f000f
0001c3ff93ff8a007c001ff0ffffff800001cffbfc0f000f0003c3ff93ff80007c001ff0ffffff0000f9cffbfc0f000f0007c1ff93ff8400fe01eff0ffffff40
01f9cffbfc0f000f000fc0ff93ff8600fc01eff0fffffe6c03ffdffbfc0f000f000fc0ff93ff8781fc01eff0fffffe7e07ff9ff3fc0f000e0007c3ff93ff8f81
f8079ff0fffffe7e0fff1ff3fc0f080c0001c3ff93ff8781f8071ff0fffffe7e0fff1ff3fc0f18080001c7ff93ff8780fc071ff0fffffe3e1fff1ff3fc0f3800
0001c7ff93ff8180fc071ff0fffffc0c1fff1ff3fc0e78000001c7e3b3ff800078019ff0fffff8083fff1ffbfc0c78000181c7c393ff800780019ff0fffff800
3fff1ffbfc08780003c1c7c193ff8187e0011ff0fffff0003fff1ff3fc00780007c1c00013ff87cff0011ff0ffffe0001fff3ff3fc0078000fffc00013ff87cf
f801dff0ffffe0700c7f3ff3fc0078e00fffc00013ff87cfe201dff0ffffc060087e3ff3fc0078e003d3c00013ff81ffe0039ff0ffff80c004003ff3fc0071e0
00003fff93ff80101003cff0ffff818000003ff3fc0073e0000038ff13ff80300003cff0ffff818001e03ff3fcc043e00000303c13fe007e1c07cff0ffff8180
07e01ff3fcc003e0101c303c13fe00fc1e07cff0ffff07807fef03f3f3c003e01cfc300013fe003800079ff0ffff07807fff00f3e3c003e03ffc300013ff03cd
00079ff0fffe07807fff8033c3c003e01ffc300013ff87cff80f9ff0fffe07807fff803343c003e05ffc3000137f87fff8079ff0fffe07807fef800303c003e0
3ff03c00100787fff8071ff0fffe07807fffc00303c303e03ff03c00100787effc079ff0fffe07807fffc00303c703e03ff03c00100087eff8073ff0ffff0780
7fffc30203cf03e01ff03c00000087fff8073ff0ffff0783ffefc7e3038f03c01ff83800038007fff81e7ff0ffff0783ffcfcfe0030f03c01ffc3000038001ff
f83e7ff0ffff83c1ffdfcc00000c00c00ffc200001f001fe183e7ff0ffff87c1ffffcc00000000000000000000fc01fc183efff0ffff87e07fffcb8c00000000
00000000007e03fff83efff0ffff83e07fffcbcc0000000000100000007e03fffc1cfff0ffffc1f0fffff3ec0000000000000000403f07fffe18fff0ffffe1f8
fffff3fe0000000000000000719f07bffe1dfff0ffffe0fc7f9ff3ffc7c0004c0007103de7e78f9ffe39fff0ffffe0fe7fdff3ff8fc0007c0003b83fcff7ff9f
fe39fff0fffff07fffffefffffc000700f01d83ffffbfffffef1fff0fffff87fffffefffffe000700f00c83ffff9fffffef9fff0fffff87fffffcffffff80000
0000007ffffdfffffef1fff0fffff83fffffcffffff800000000007ffffeffeffee3fff0fffffc3ffe79dffffff800000000007fffff7fcfe7e7fff0fffffe3f
fe799ffffffc1420001ff07fffffffcfe3e7fff0fffffe03000e3ffffffc00ccf71c40ffffff804001fffff0ffffff07801e7ffffff80084710c00ffffff81c0
fdfffff0ffffff87e01ffffffff80000000000fffffff000fe7ffff0ffffffc00007fffffff00000000000fffffffa007cfffff0fffffff00007fffffff00000
0000007fffffff0001fffff0fffffffc0007fffffff000000000007fffffff0003fffff0ffffffff0007fffffff020000000003ffffffe3c0ffffff0fffffffe
0007ffffffe060000000203ffffffe1e0ffffff0fffffff80007ffffffc000080000003ffffffe060ffffff0fffffff80001ffffffc00000000000bffffffe02
07fffff0fffffff803c07fffff0000000000018ffffffc0207fffff0fffffff807c03ffffe380000000003cffffff81f07fffff0ffffffe006003ffffe380100
300303cffffff8bf07fffff0ffffffe004003ffffe380300300303cffffff89f07fffff0ffffffc00000bfffff100300700f108ffffff80007fffff0ffffff80
0001bfffff80030070031c1ffffff80007fffff0ffffff800003ffffffc0020070003c3ffffff80007fffff0ffffff800007ffffffe0000060003cfffffff000
07fffff0ffffffc00fe7fffffff80000000003fffffff00007fffff0ffffffc01fc7fffffff80000000003fffffff80007fffff0ffffffe011e7fffffffe001f
ff0007fffffff8004ffffff0fffffff001effffffffe001fff8007fffffff8008ffffff0ffffffff03cfffffffff000c3ffe0ffffffffe7f1ffffff0ffffffff
87dfffffffff800030df8ffffffffe787ffffff0ffffffff839fffffffffc000083e3ffffffffff0fffffff0ffffffff839fffffffffc000083c3fffffffffff
fffffff0ffffffffc07ffffffffff00000f1fffffffffffffffffff0ffffffffe1fffffffffff80000e1fffffffffffffffffff0fffffffffffffffffffffc00
00c3fffffffffffffffffff0ffffffffffffffffffffff00008ffffffffffffffffffff0ffffffffffffffffffffffc0003ffffffffffffffffffff0ffffffff
ffffffffffffffc0003ffffffffffffffffffff0ffffffffffffffffffffffc0007ffffffffffffffffffff0ffffffffffffffffffffffc0007fffffffffffff
fffffff0ffffffffffffffffffffffc3f87ffffffffffffffffffff0ffffffffffffffffffffffc0447ffffffffffffffffffff0ffffffffffffffffffffffc0
003ffffffffffffffffffff0ffffffffffffffffffffff80003ffffffffffffffffffff0ffffffffffffffffffffff00007ffffffffffffffffffff0ffffffff
ffffffffffffff00001ffffffffffffffffffff0ffffffffffffffffffffff00081ffffffffffffffffffff0fffffffffffffffffffffe00001fffffffffffff
fffffff0fffffffffffffffffffffc00001ffffffffffffffffffff0fffffffffffffffffffffc00481ffffffffffffffffffff0fffffffffffffffffffffc00
480ffffffffffffffffffff0fffffffffffffffffffffc00480ffffffffffffffffffff0fffffffffffffffffffff8004007fffffffffffffffffff0ffffffff
fffffffffffffc13f9c3fffffffffffffffffff0fffffffffffffffffffffc1fff83fffffffffffffffffff0fffffffffffffffffffffc000003ffffffffffff
fffffff0fffffffffffffffffffff8000003fffffffffffffffffff0fffffffffffffffffffff0000001fffffffffffffffffff0fffffffffffffffffffff000
0101fffffffffffffffffff0fffffffffffffffffffff0000701fffffffffffffffffff0fffffffffffffffffffff0000f05fffffffffffffffffff0ffffffff
fffffffffffff000003efffffffffffffffffff0fffffffffffffffffff7e00001eefffffffffffffffffff0fffffffffffffffffff00080c71f3fffffffffff
fffffff0fffffffffffffffffff80184cf1fbffffffffffffffffff0ffffffffffffffffcff000cc1f1dbffffffffffffffffff0ffffffffffffffffc7c000c0
0f1e3ffffffffffffffffff0ffffffffffffffffc1f00000031ffffffffffffffffffff0ffffffffffffffffc0f00000071ffffffffffffffffffff0ffffffff
ffffffff8000300c1f3ffffffffffffffffffff0ffffffffffffffffc600300e1f1ffffffffffffffffffff0ffffffffffffffffe0403c003f1fffffffffffff
fffffff0fffffffffffffffff0003e003f1ffffffffffffffffffff0fffffffffffffffffc083f00071ffffffffffffffffffff0fffffffffffffffffc099f00
001ffffffffffffffffffff0fffffffffffffffffff9f380001ffffffffffffffffffff0fffffffffffffffffff9fc00001ffffffffffffffffffff0ffffffff
fffffffffff9ffe0000ffffffffffffffffffff0fffffffffffffffffffdfff0000ffffffffffffffffffff0fffffffffffffffffffdfffc000fffffffffffff
fffffff0fffffffffffffffffffcfffc000ffffffffffffffffffff0fffffffffffffffffffefffe000ffffffffffffffffffff0ffffffffffffffffffff7fff
000ffffffffffffffffffff0fffffffffffffffffffff3ff801ffffffffffffffffffff0fffffffffffffffffffff0ffc01ffffffffffffffffffff0ffffffff
ffffffffffffff0ffc1ffffffffffffffffffff0ffffffffffffffffffffff8fff1ffffffffffffffffffff0ffffffffffffffffffffff8fff1fffffffffffff
fffffff0ffffffffffffffffffffff8fff1ffffffffffffffffffff0ffffffffffffffffffffff8fff3ffffffffffffffffffff0ffffffffffffffffffffffff
fffffffffffffffffffffff0fffffffffffffffffffffffffffffffffffffffffffffff0fffffffffffffffffffffffffffffffffffffffffffffff0ffffffff
fffffffffffffffffffffffffffffffffffffff0fffffffffffffffffffffffffffffffffffffffffffffff0fffffffffffffffffffffffffffffffffffffffffffffff005000000070101000000030000000000}}}{\cf1\cgrid0 \cell }\pard \qr\nowidctlpar\intbl\adjustright {\cf1\cgrid0
\par
\par
\par TTY FOR THE DEAF (410) 767-2117
\par \cell }\pard \widctlpar\intbl\adjustright {\cf1\cgrid0 \row }\pard\plain \s18\qc\nowidctlpar\adjustright \i\fs20\cf1 {Keeping Maryland Working and Safe
\par }}{\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}
{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8
\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \li720\widctlpar\adjustright \fs20\cgrid {\fs24
\par
\par
\par
\par \tab \tab \tab \tab \tab \tab |DATE
\par
\par |NAME1
\par |ADD1
\par |CITY1, |STATE1 |ZIP1
\par
\par \tab \tab \tab \tab \tab \tab Re: |ACCT
\par
\par
\par }{\f2\fs18
\par }{\fs24
\par
\par
\par }}
AnswerRe: It is missing header and footer while converting rtf to html Pin
Jani Giannoudis12-Apr-11 4:21
memberJani Giannoudis12-Apr-11 4:21 
Generalspecial exception while parsing Pin
Huisheng Chen7-Apr-11 23:13
memberHuisheng Chen7-Apr-11 23:13 
AnswerRe: special exception while parsing Pin
Jani Giannoudis8-Apr-11 11:25
memberJani Giannoudis8-Apr-11 11:25 
Generalname argument null in RtfFont Pin
Huisheng Chen7-Apr-11 22:57
memberHuisheng Chen7-Apr-11 22:57 
AnswerRe: name argument null in RtfFont Pin
Jani Giannoudis8-Apr-11 11:21
memberJani Giannoudis8-Apr-11 11:21 
Generaltoo many braces Pin
Huisheng Chen6-Apr-11 23:59
memberHuisheng Chen6-Apr-11 23:59 
AnswerRe: too many braces Pin
Jani Giannoudis7-Apr-11 0:15
memberJani Giannoudis7-Apr-11 0:15 
GeneralRe: too many braces Pin
Huisheng Chen7-Apr-11 12:50
memberHuisheng Chen7-Apr-11 12:50 
JokeRe: too many braces Pin
Jani Giannoudis7-Apr-11 20:11
memberJani Giannoudis7-Apr-11 20:11 
GeneralSupport for multi-byte encodings Pin
nklarsen15-Mar-11 9:51
membernklarsen15-Mar-11 9:51 
AnswerRe: Support for multi-byte encodings Pin
Jani Giannoudis16-Mar-11 10:26
memberJani Giannoudis16-Mar-11 10:26 
GeneralRe: Support for multi-byte encodings Pin
nklarsen16-Mar-11 11:05
membernklarsen16-Mar-11 11:05 
AnswerRe: Support for multi-byte encodings Pin
Jani Giannoudis18-Mar-11 23:24
memberJani Giannoudis18-Mar-11 23:24 
GeneralIt can't canvert the RTF File Pin
stulzc28-Feb-11 20:48
memberstulzc28-Feb-11 20:48 
AnswerRe: It can't canvert the RTF File Pin
Jani Giannoudis8-Mar-11 3:19
memberJani Giannoudis8-Mar-11 3:19 
QuestionRTF to text get Exception"System.ArgumentNullException: Value cannot be null" Pin
Member 769070824-Feb-11 4:57
memberMember 769070824-Feb-11 4:57 
AnswerRe: RTF to text get Exception"System.ArgumentNullException: Value cannot be null" Pin
Jani Giannoudis24-Feb-11 20:09
memberJani Giannoudis24-Feb-11 20:09 

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.

Article
Posted 2 Jul 2008

Tagged as

Stats

1.5M views
35.4K downloads
625 bookmarked