RTF文件结构分析及其应用
RTF是一種非常流行的文件結(jié)構(gòu),很多文字編輯器都支持它,VB等開發(fā)工具
甚至還提供了Richtxtbox的控件。編寫通用工具的程序員應(yīng)該考慮在自己的軟
件中加入讀寫RTF文件的功能,這樣就需要對RTF的結(jié)構(gòu)有充分的了解。而現(xiàn)在
最重要的信息發(fā)布手段莫過于WWW了,在編輯軟件中提供RTF到HTML的轉(zhuǎn)換也是程
序員應(yīng)該考慮的事情。盡管WORD中已經(jīng)有這個(gè)功能,但不能因此就對您的顧客
說:“先用我的程序存成RTF,然后再用WORD......”。
下面將對RTF文件結(jié)構(gòu)分析及其應(yīng)用進(jìn)行討論。
一、RTF文件結(jié)構(gòu)分析
RTF的結(jié)構(gòu)并不復(fù)雜,但內(nèi)容繁多,本文不可能一一說明,只能從總體上討
論一下(如果想閱讀詳盡的RTF文檔,則可在Internet上尋找或與筆者聯(lián)系。)
每個(gè)RTF文件都是一個(gè)文本文件,顯示時(shí)由RTF閱讀器格式化。文件開始處是
{\rtf,它作為RTF文件的標(biāo)志是必不可少的,RTF閱讀器根據(jù)它來判斷一個(gè)文件
是否為RTF格式。然后是文件頭和正文,文件頭包括字體表、文件表、顏色表等
幾個(gè)數(shù)據(jù)結(jié)構(gòu),正文中的字體、表格的風(fēng)格就是根據(jù)文件頭的信息來格式化的。
每個(gè)表用一對大括號括起來,當(dāng)中包含了很多用字符“\”開始的命令。例如,
某個(gè)顏色表如下:
{\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;}
開始時(shí)用\colortbl標(biāo)明大括號內(nèi)是顏色表,接著是\red0\green0\blue0,
登記了一種顏色,這種顏色的紅綠藍(lán)分量都為0。其它表依此類推。文件頭之后是
正文,正文由版面格式化命令、文字和各種特殊命令組成。其中只有特殊命令
用大括號括起來,而版面格式化命令和文字是“開放式”的,從而把文字和命
令分離。文件結(jié)束時(shí)有一個(gè)“}”,和第一個(gè)“{”對應(yīng)。在整個(gè)文件中,“}”
和“{”必須一一對應(yīng)。這種格式是RTF閱讀器和轉(zhuǎn)換器算法的基礎(chǔ)。
RTF格式還有一個(gè)特別之處,就是有些字符在命令中有特殊的含義,所以當(dāng)
它們作為文本出現(xiàn)時(shí)需要在它們的前面加一個(gè)“\”,例如“\”本身就要表示
為“\\”。事實(shí)上,這種形式在大多數(shù)編程語言中是很常見的。
二、算法分析
本節(jié)介紹的算法雖然是針對RTF的讀寫,但也是一般文件過濾器通用的方
法,適用于各種格式文件之間的轉(zhuǎn)換。具體來說就是把各種文件都轉(zhuǎn)換成一種
中間格式,再根據(jù)要求進(jìn)行顯示或轉(zhuǎn)換。其中有個(gè)原則是一定要遵守的:程序必
須能過濾掉不認(rèn)識的格式。各種文件都有其特殊的格式,在轉(zhuǎn)換過程中不可避免
會(huì)出現(xiàn)格式損失的現(xiàn)象,在算法中要考慮這種情況。對于RTF這類格式化文本
文件來說,最重要的是要正確地顯示或轉(zhuǎn)換文件的大小、顏色、字體等風(fēng)格。
因此,在程序中應(yīng)該用一個(gè)數(shù)據(jù)結(jié)構(gòu)把這些信息存起來,這個(gè)結(jié)構(gòu)就是所謂的
中間格式,怎樣規(guī)定悉聽尊便。以下是其流程圖:
三、難點(diǎn)分析
在開發(fā)過程中我們遇到了不少問題,其中有兩個(gè)問題特別有意思。
第一個(gè)問題是中文的表示方式。在RTF中中文用命令的形式表示:
“\'內(nèi)碼”。內(nèi)碼就是漢字機(jī)內(nèi)碼。不過,請注意:RTF是文本文件,內(nèi)碼
是用ASCII碼來儲(chǔ)存的,必須把它轉(zhuǎn)換成數(shù)字才能使用。例如,“電子與電腦”
在RTF中的形式是:
\'b5\'e7\'d7\'d3\'d3\'eb\'b5\'e7\'c4\'d4
第二個(gè)是圖片的問題,這也是本文的重點(diǎn)。RTF中圖片以兩種方式存在:第
一種方式是直接嵌入,以{\pict開始;第二種方式是作為OLE對象嵌入,這時(shí)以
{\object開始。當(dāng)RTF處理器能直接使用OLE時(shí),RTF文件中提供了OLE的數(shù)據(jù);否
則,文件中直接提供圖片的數(shù)據(jù),以{\result開始。在使用中最常見的圖片格式
是內(nèi)含DIB BITMAP的元文件(METAFILE),這種格式在SDK中沒有說明,而且
在RTF中是以壓縮形式儲(chǔ)存的,所以在轉(zhuǎn)換時(shí)有一定困難。我們采取了一種比較
新的方法:先把META FILE的數(shù)據(jù)讀出來存成一個(gè)文件,然后用GetMetafile和
PlayMetafile函數(shù)把文件中的圖形打印在一個(gè)內(nèi)存DC上,最后用抓圖的方法把
它存成BITMAP文件。以下是具體程序:
voidWmfToBmp(intwidth,intheight,char *metafile)
{
//width為圖片寬度,height為圖片高度,*metafile為元文件名
static HMETAFILE hmf;
charnum[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);
//把字符串轉(zhuǎn)換成數(shù)字的函數(shù)
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()
用這種方法還有一個(gè)好處,那就是當(dāng)你從最底層開始開發(fā)RTF閱讀器時(shí),只
需把PlayMetaFile的參數(shù)從內(nèi)存DC換成屏幕DC就可以顯示圖片了。
四.RTF格式的擴(kuò)展
最后討論一下RTF格式的擴(kuò)展。RTF格式作為一個(gè)標(biāo)準(zhǔn)應(yīng)該是統(tǒng)一的,但在
某種情況下進(jìn)行擴(kuò)展是必要的。最明顯的例子是微軟的WORD,它有自己獨(dú)有
的RTF命令。如果想使自己的軟件在技術(shù)上占有優(yōu)勢,也可以通過創(chuàng)造新的RTF
命令來實(shí)現(xiàn)。例如,如果你希望在軟件中支持DHTML,則可在RTF中嵌入
{\dhtml或{\java之類的命令。由于RTF閱讀器有過濾不認(rèn)識命令的功能,所以
這樣做不會(huì)影響RTF文件的通用性。
總結(jié)
以上是生活随笔為你收集整理的RTF文件结构分析及其应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你可能不知道的java、python、J
- 下一篇: 通过border来实现各种三角符号