RTF (Rich Text Foramt) is a very ancient and horrible format for "word processing" documents. It is from very ancient times and a quasi standard of Microsoft. It can prove useful when trying to generate documents that people will open with Word. It is much harder to take a modern version of Word and make comprehensive reversible RTF, but creating simple things with RTF that can be seen on any version of Word should be possible.

In case the point is missed here, when you are required to create some unholy output that some wretch needs to see with Microsoft Word because they haven’t the wherewithal to handle it any other way, using RTF you might just be able to synthesize something using only wholesome tools that could work. For example, a Python program, an XSLT transformation, or just by hand in Vim.

If you need more of the ghastly details, here is the full RTF specification.


Check out apt-get install catdoc for a simple conversion of RTF.


Uses twips (1/20th of a point aka 1/1440th of an inch). 1 pt = 20twips. 1 inch = 1440 twips. Plenty of precision there.


Font size is specified in half points (14 point here).

Minimal RTF Code

Here is a very small sample document.

{\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}} \f0\fs24 Sample\line Minimal RTF Document}

Here’s some stuff to include for polite operation of a general document. Put this in before the first real content:

\deflang1033 \plain \fs26 \widowctrl \hyphauto \ftnbj
{\header \pard\qr\plain\f0\fs16 \chpgn \par}

This resets everything and sets a default language (us-en). It also sets a default header. The \chpgn inserts the current page number.


Note that spacing is lax where it is lax and important where it is important (usually when literal in your text). New lines don’t usually cause trouble.

Braces are nested properly and the entire document must be enclosed in curly braces.

Major RTF component classes:


Does stuff. Matches /\\[a-z]+(-?[0-9]+)? ?/


Specify the hard to specify stuff. See below.


Use braces to save state ({) and then do something and then revert state (}). Think gsave and grestore in PostScript.


Literal text. The actual content. What a concept!


Commands end in a space or a newline. Otherwise newlines don’t do anything in the text at all. Many spaces after a command will be inserted literally except for the first one which ends the command. That first space could have been a newline with the same effect. You can use newlines pretty safely for formatting the source.


RTF version 1 document follows. Required first thing. Always use 1.


Windows Code Page 1252 character set.


Default font is font #0 in the font table. See next item.

{\fonttbl {\f0 Times New Roman;}}

This is the font table defining font #0 as TNR.


Set text to 12 point.








Superscript. I’m super, thanks for asking!




Small capitals. Sort of an oxymoron.


Strike through. Maybe good for generating fake <hr> sorts of things. Or try {\pard \brdrb \brdrs \brdrw10 \brsp20 \par} {\pard\par}.


Turns off any formatting stuff and resets stuff in general.


Start a new line within the paragraph.


"Quadding" (alignment) center.


Left justify.


Right justify.


Full justify.


Page break here.


Don’t split this paragraph across pages.


Keep this paragraph with the next one.


Turns on a reluctance to break near the first or last sentence (or two?). Widow/orphan control it’s called.


Turns off widctlpar if it’s on.


Turns on automatic hyphenation for the paragraph. With parameter 0 (\hyphpar0) it is canceled for this paragraph.


Turns on automatic hyphenation for the whole doc if used near the beginning.


Single line spacing. 1.5 spacing is 360. Single spacing (240) is the default.


Exact paragraph positioning X,Y from top left in twips and W wide.

Those Microsoft people love their backslashes.


RTF only uses ASCII values 32-126. To get something else use this kind of escape:


Where a9 is a hex number (representing the copyright symbol).

Escapes of interest:


Non-breaking space, like  


Optional hyphenation point.


Real hyphen that should not be broken


Something else.

There are no optional spaces after escape sequences.

Unicode works and is done like this:


Looks like the star ends it? There are some other funky rules for very high unicode values.


In theory a document should have a font table.

Something like this will do:

{\fonttbl {\f0\froman Times;} {\f1\fswiss Helvetica;} {\f2\fmodern Courier;} }

And then you can do {\f1 A Swiss typeface.}.


A basic paragraph syntax looks like this:

{\rtf1\ansi\deff0 {\fonttbl {\f0 Times New Roman;}}\f0\fs24
{\pard Some lengthy explanation of how paragraphs in RTF are
structured is probably occurring right now somewhere.\par}

Note that there needs to be a literal space after are in the source because the newline isn’t converted to it. It is simply dropped from the source.

The "d" in pard means "default" and it is implied that the paragraph defaults are set at the start of a paragraph. YMMV.

Here is a 20pt Centered title line using the paragraph delimters:

{\pard \qc \fs40 Chris X Edwards\par}

I don’t know if it makes a difference which kind of formatting command comes first in cases like this.


To get vertical space around paragraphs, use:


Add N twips of space before the paragraph.


Add N twips of space after the paragraph.

Best to add space after for best general effect, but this can be done at the beginning of the paragraph definition:

{\pard\sa720 \fs24 Some text is followed by 1/2".\par}



Indent lines N twips of space from the left margin.


Indent lines N twips of space from the paragraph margin (set with \liN). You can use a negative number to have the first line be not as indented as the rest.


Indent lines N twips of space from the right margin.



Where N is the distance in twips from the top.


Where N is the distance in twips from the bottom.


Where N is the distance in twips from the left.


Where N is the distance in twips from the right.

US Letter:

\paperw15840 \paperh12240

Landscape US Letter: \paperw15840 \paperh12240 \margl1440 \margr1440 \margt1800 \margb1800 \landscape

Also: \twoonone God help us.



Where N is the number of columns you want.


Where N is the spacing between columns in twips.


Draw a line between columns.


Tables can be done. Not fun but can be done. Here’s an example:

\trowd \trgaph180
\pard\intbl Content off upper left box.\cell
\pard\intbl Content off upper right box.\cell

\trowd \trgaph180
\pard\intbl Content off lower left box.\cell
\pard\intbl Content off lower right box.\cell

Info Section

You can have an optional info section of metadata. This looks like:

{\doccomm Any random comment, URL, version number, etc.}

Speaking of comments, it seems that RTF does not really support them (since they never expected people like me to compose human readable documents directly in RTF from an editor). But there is some weird syntax designed to allow backwards compatibility. The idea is newfangled commands can get parsed and attended to by newfangled parsers. But old parsers were instructed to be ready for newfangled commands and to skip over them if they didn’t understand them. So basically if you just make up a new command with this syntax, you can have what amounts to a comment. Here’s how:

{\*\xednote{Chris X Edwards}}
{\*\xednote{As long as "xednote" isn't a real function in a parser,
everything in this block should be ignored.}}