标题：rtf文件
结构分析及其应用
邱立铭 王键 
首先它是一般来写字板的默认文档之一，但除了它以外，Word、WPS Office、Excel等都可以打开RTF格式的文件。它的打开速度快，rtf是一种非常流行的文件结构，而且无损害的的一种格式。很多文字编辑器都支持它，vb等开发工具甚至还提供了richtxtbox的控件。编写通用工具的程序员应该考虑在自己的软件中加入读写rtf文件的功能，这样就需要对rtf的结构有充分的了解。而现在最重要的信息发布手段莫过于www了，在编辑软件中提供rtf到html的转换也是程序员应该考虑的事情。尽管word中已经有这个功能，但不能因此就对您的顾客说：“先用我的程序存成rtf，然后再用word......”。
讨论
结构分析下面将对rtf文件结构分析及其应用进行讨论。 
一、rtf文件结构分析 
rtf的结构并不复杂，但内容繁多，本文不可能一一说明，只能从总体上讨论一下（如果想阅读详尽的rtf文档，则可在internet上寻找或与笔者联系。）每个rtf文件都是一个文本文件，显示时由rtf阅读器格式化。文件开始处是{
tf，它作为rtf文件的标志是必不可少的，rtf阅读器根据它来判断一个文件是否为rtf格式。然后是文件头和正文，文件头包括字体表、文件表、颜色表等几个数据结构，正文中的字体、表格的风格就是根据文件头的信息来格式化的。每个表用一对大括号括起来，当中包含了很多用字符“”开始的命令。例如，某个颜色表如下： 
{colortbl;
ed0green0lue0;
ed0green0lue255;
ed0green255lue255;
ed0green255lue0;
ed255green0lue255;
ed255green0lue0;
ed255green255lue0;
ed255green255lue255;
ed0green0lue128;
ed0green128lue128;
ed0green128lue0;
ed128green0lue128;
ed128green0lue0;
ed128green128lue0;
ed128green128lue128;
ed192green192lue192;}特别之处开始时用colortbl标明大括号内是颜色表，接着是
ed0green0lue0，登记了一种颜色，这种颜色的红绿蓝分量都为0。其它表依此类推。文件头之后是正文，正文由版面格式化命令、文字和各种特殊命令组成。其中只有特殊命令用大括号括起来，而版面格式化命令和文字是“开放式”的，从而把文字和命令分离。文件结束时有一个“}”，和第一个“{”对应。在整个文件中，“}”和“{”必须一一对应。这种格式是rtf阅读器和转换器算法的基础。 
rtf格式还有一个特别之处，就是有些字符在命令中有特殊的含义，所以当它们作为文本出现时需要在它们的前面加一个“”，例如“\”本身就要表示为“\”。事实上，这种形式在大多数编程语言中是很常见的。
算法分析
本节介绍的算法虽然是针对rtf的读写，但也是一般文件过滤器通用的方法，适用于各种格式文件之间的转换。具体来说就是把各种文件都转换成一种中间格式，再根据要求进行显示或转换。其中有个原则是一定要遵守的：程序必须能过滤掉不认识的格式。各种文件都有其特殊的格式，在转换过程中不可避免会出现格式损失的现象，在算法中要考虑这种情况。对于rtf这类格式化文本文件来说，最重要的是要正确地显示或转换文件的大小、颜色、字体等风格。因此，在程序中应该用一个数据结构把这些信息存起来，这个结构就是所谓的中间格式，怎样规定悉听尊便。以下是其流程图：
难点分析
表示方式在开发过程中我们遇到了不少问题，其中有两个问题特别有意思。 
第一个问题是中文的表示方式。在rtf中中文用命令的形式表示：“'内码”。内码就是汉字机内码。不过，请注意：rtf是文本文件，内码是用ascii码来储存的，必须把它转换成数字才能使用。例如，“电子与电脑”在rtf中的形式是： 
'b5'e7'd7'd3'd3'eb'b5'e7'c4'd4图片的问题第二个是图片的问题，这也是本文的重点。rtf中图片以两种方式存在：第一种方式是直接嵌入，以{pict开始；第二种方式是作为ole对象嵌入，这时以{object开始。当rtf处理器能直接使用ole时，rtf文件中提供了ole的数据；否则，文件中直接提供图片的数据，以{
esult开始。在使用中最常见的图片格式是内含dib bitmap的元文件（metafile），这种格式在sdk中没有说明，而且在rtf中是以压缩形式储存的，所以在转换时有一定困难。我们采取了一种比较新的方法：先把meta file的数据读出来存成一个文件，然后用getmetafile和playmetafile函数把文件中的图形打印在一个内存dc上，最后用抓图的方法把它存成bitmap文件。以下是具体程序： 
void wmftobmp(int width,int height,char *metafile) 
{ 
//width为图片宽度，height为图片高度，*metafile为元文件名 
static hmetafile hmf; 
char num[4]; 
file *fh; 
hdc hmemdc; 
hbitmap hbmp,hold; 
bitmapfileheader hdr; 
lpbitmapinfoheader lpbmpih; 
hglobal hg; 
bitmapcount++; 
if(bitmapcount==3) 
{ 
width=128; 
height=132; 
} 
if(bitmapcount==1) 
{ 
width=80; 
height=50; 
} 
tostring10(bitmapcount,num); 
//把字符串转换成数字的函数 
lstrcpy(bmpfile,filepath); 
lstrcat(bmpfile,num); 
lstrcpy(giffile,bmpfile); 
lstrcat(bmpfile,".bmp"); 
lstrcat(giffile,".gif"); 
hmf=getmetafile(metafile); 
hdisplaydc=createdc("display",null,null,null); 
hmemdc=createcompatibledc(hdisplaydc); 
hg=globalalloc(ghnd,sizeof(bitmapinfoheader)); 
lpbmpih=(lpbitmapinfoheader)globallock(hg); 
lpbmpih->bisize=sizeof(bitmapinfoheader); 
lpbmpih->biwidth=width; 
lpbmpih->biheight=height; 
lpbmpih->biplanes=1; 
lpbmpih->bibitcount=8; 
lpbmpih->bicompression=0; 
hbmp=createcompatiblebitmap(hdisplaydc,width,height); 
globalunlock(hg); 
globalfree(hg); 
hold=selectobject(hmemdc,hbmp); 
setmapmode(hmemdc,mm_anisotropic); 
setwindoworgex(hmemdc,0,0,null); 
setviewportextex(hmemdc,width,height,null); 
playmetafile(hmemdc,hmf); 
hbmp=selectobject(hmemdc,hold); 
if((fh=fopen(bmpfile,"w+b"))==null) 
{ 
return; 
} 
hdr.bftype=0x4d42; 
hdr.bfsize=sizeof(bitmapfileheader)+sizeof(bitmapinfoheader)+256*sizeof(rgbquad)+width*height; 
hdr.bfreserved1=0; 
hdr.bfreserved2=0; 
hdr.bfoffbits=sizeof(bitmapfileheader)+sizeof(bitmapinfoheader)+256*sizeof(rgbquad); 
fwrite((lpstr)&hdr,sizeof(bitmapfileheader),1,fh); 
hg=globalalloc(ghnd,sizeof(bitmapinfoheader)+256*sizeof(rgbquad)); 
lpbmpih=(lpbitmapinfoheader)globallock(hg); 
lpbmpih->bisize=sizeof(bitmapinfoheader); 
lpbmpih->biwidth=width; 
lpbmpih->biheight=height; 
lpbmpih->biplanes=1; 
lpbmpih->bibitcount=8; 
lpbmpih->bicompression=0; 
lpbmpih->bisizeimage=width*height; 
lpbmpih->biclrused=256; 
lpbmpih->biclrimportant=0; 
j=getdibits(hmemdc,hbmp,0,height,null,(bitmapinfo*)lpbmpih,dib_rgb_colors); 
lpbmpih->bisize=sizeof(bitmapinfoheader); 
fwrite(lpbmpih,sizeof(bitmapinfoheader)+256*sizeof(rgbquad),1,fh); 
getdibits(hmemdc,hbmp,0,height,(lpstr)filebuffer,(bitmapinfo*)lpbmpih,dib_rgb_cols); 
fwrite(filebuffer,width*height,1,fh); 
globalunlock(hg); 
globalfree(hg); 
fclose(fh); 
deletedc(hmemdc); 
deletedc(hdisplaydc); 
deleteobject(hbmp); 
deleteobject(hold); 
deletemetafile(hmf); 
}//end function wmftobmp()好处用这种方法还有一个好处，那就是当你从最底层开始开发rtf阅读器时，只需把playmetafile的参数从内存dc换成屏幕dc就可以显示图片了。
简介
以纯文本描述内容，能够保存各种格式信息，可以用写字版，Word等创建。 
也称富文本格式（Rich Text Format, 一般简称为RTF）是由微软公司开发的跨平台文档格式。大多数的文字处理软件都能读取和保存RTF文档。
RTF版本标准文件
作为微软公司的标准文件，早期外间需要数十美元向微软付款，才能购买一本薄薄的RTF标准文件。不过随着采用RTF格式标准的软件愈来愈多，RTF格式也愈来愈普遍，微软公司就把标准文件公开，放在网上供开发者下载。现时可供下载的各个RTF版本标准文件如下： 
RTF 1.9.1 specification (March 2008) 
RTF 1.8 specification (April 2004) 
RTF 1.6 specification (May 1999) 
RTF 1.5 specification (April 1997) 
RTF 1.3 and 1.5 specifications 
RTF 1.0 specification (June 1992) 
RTF格式是许多软件都能够识别的文件格式。比如Word、WPS Office、Excel等都可以打开RTF格式的文件，这说明这种格式是较为通用的。 
RTF是Rich Text Format的缩写，意即多文本格式。这是一种类似DOC格式（Word文档）的文件，有很好的兼容性，使用Windows“附件”中的“写字板”就能打开并进行编辑。使用“写字板”打开一个RTF格式文件时，将看到文件的内容；如果要查看RTF格式文件的源代码，只要使用“记事本”将它打开就行了。这就是说，你完全可以像编辑HTML文件一样，使用“记事本”来编辑RTF格式文件。
RTF的特点
对普通用户而言，RTF格式是一个很好的文件格式转换工具，用于在不同应用程序之间进行格式化文本文档的传送。 
通用兼容性应该是RTF的最大优点，但同时也就具有它的缺点，比如文件一般相对较大（可能因为嵌入了兼容各种应用程序的控制符号吧）、WORD等应用软件特有的格式可能无法正常保存等。
rtf格式的扩展
最后讨论一下rtf格式的扩展。rtf格式作为一个标准应该是统一的，但在某种情况下进行扩展是必要的。最明显的例子是微软的word，它有自己独有的rtf命令。如果想使自己的软件在技术上占有优势，也可以通过创造新的rtf命令来实现。例如，如果你希望在软件中支持dhtml，则可在rtf中嵌入{dhtml或{java之类的命令。由于rtf阅读器有过滤不认识命令的功能，所以这样做不会影响rtf文件的通用性。
需要什么软件打开
RTF格式是许多软件都能够识别的文件格式。比如Word、WPS Office、Excel等都可以打开RTF格式的文件，这说明这种格式是较为通用的。 RTF是Rich Text Format的缩写，意即多文本格式。这是一种类似DOC格式（Word文档）的文件，有很好的兼容性，使用Windows“附件”中的“写字板”就能打开并进行编辑。使用“写字板”打开一个RTF格式文件时，将看到文件的内容；如果要查看TRF格式文件的源代码，只要使用“记事本”将它打开就行了。这就是说，你完全可以像编辑HTML文件一样，使用“记事本”来编辑RTF格式文件。 对普通用户而言，RTF格式是一个很好的文件格式转换工具，用于在不同应用程序之间进行格式化文本文档的传送。 通用兼容性应该是RTF的最大有点，但同时也就具有它的缺点，比如文件一般相对较大（可能因为嵌入了兼容各种应用程序的控制符号吧）、WORD等应用软件特有的格式可能无法正常保存等。