青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

franksunny的個人技術空間
獲得人生中的成功需要的專注與堅持不懈多過天才與機會。 ——C.W. Wendte

 

Symbian程序動態加載TTF字體使用小結

 圖片看不到,這次文檔已上傳到了百度文庫,需要的可以去百度文庫查看完整版 http://wenku.baidu.com/view/c9ac1f1f650e52ea551898eb.html

Symbian手機支持的字體文件,有gdr字體文件、bdf字體文件和ttf字體文件,相對來說ttf字體用的更為普遍一些,他是由Apple公司和微軟公司聯合發起的一套標準,在Symbian手機目前所知有兩種使用ttf字體文件的方法:一種是實現基于ECom插件形式的光柵化插件方法,該方法是靜態加載,每次選擇一個字體后,需要重啟手機才能生效,網上有開源的FontRouter可以作為參考;另一種是通過CFbsTypefaceStore或由應用程序框架控制環境動態加載字體文件,該種方法可以實時生效,沒錯的話Go瀏覽器就是通過這種方法實現的。本文就是對在Symbian手機上動態加載TTF字體并使用的整理小結。

字體使用效果截圖演示

因為后續內容比較枯燥無味,為了增加本文的可讀性,先將字體使用的效果截圖如下

方正胖娃字體

華康少女字體

方正柳體

方正準圓字體

 

字體文件加載使用流程

動態加載ttf字體文件和使用的方法,其實也是可以通用于gdr等字體的,具體的加載使用步驟流程可以參考nokia官方的wiki文檔,地址見下面鏈接

http://wiki.forum.nokia.com/index.php/Custom_font

步驟1:準備好需要使用的TTF字體文件

可以去網絡上下載你想要在手機上顯示的ttf字體文件(比如http://www.font5.com.cn/index.html),也可以使用Windows操作系統自帶的字體,可以通過“控制面板”、“字體”或者直接到"C:\Windows\Fonts"目錄下尋找你需要的字體文件。

步驟2:將準備好的TTF字體文件拷貝到手機中

拷貝的路徑由你自己選擇,可以手機存儲或者TF卡上,由于TTF字體文件本身都比較大,所以本文試驗時將其放在TF卡上(“e:\Data\Fonts\”)。

步驟3:在Draw()函數中加載并使用這個字體文件

具體代碼如下:

CFont* myNewFont = NULL;

TFileName iFileName;

iFileName.Copy(_L("e:\\Data\\Fonts\\abc.ttf"));

TInt static fontID = 0;

iCoeEnv->ScreenDevice()->AddFile(iFontFile, fontID);

TBuf<KMaxTypefaceNameLength> aTypefaceName;

TTypefaceSupport myTypefaceSupport; 

iCoeEnv->ScreenDevice()->TypefaceSupport(myTypefaceSupport,0);//通常是新增加的在序列里面是第一個

aTypefaceName.Copy(myTypefaceSupport.iTypeface.iName.Des());

TFontSpec myFontSpec;

myFontSpec.iTypeface.iName = aTypefaceName; 

TPoint pixelPoint(16,16);//字體大小模式

myFontSpec.iHeight =  iCoeEnv->ScreenDevice()->PixelsToTwips(pixelPoint).iY;

iCoeEnv->ScreenDevice()->GetNearestFontToDesignHeightInTwips(myNewFont, myFontSpec);

gc.UseFont(myNewFont);

gc.SetPenColor(KRgbBlack);

gc.DrawText(_L("hello"),TPoint(5,20));

 

步驟4:卸載這個字體

卸載代碼如下:

iCoeEnv->ScreenDevice()->ReleaseFont(myFont);

iCoeEnv->ScreenDevice()->RemoveFile(aid);

 

字體動態加載的問題討論

雖然整個操作步驟如上述簡單流程,但是實際實現時你會發現很多意想不到的問題,我在具體操作時曾一度不相信通過上述方法真能實現所謂的動態加載,下面就對實際使用中遇到的幾個問題進行闡釋。

如何正確獲得要用的字體

通常情況下,通過AddFile或者InstallFile加載的字體,位于字體表的首項,所以可以通過以下代碼獲取新加載的字體

TTypefaceSupport myTypefaceSupport; 

iCoeEnv->ScreenDevice()->TypefaceSupport(myTypefaceSupport,0);//通常是新增加的在序列里面是第一個

但是有時候也并非都是在首項(存在偶然因素),特別是當選中的這個ttf字體已經有加載的情況下,想繼續加載另一個非同文件名的ttf字體時,系統會報錯(-11KErrAlreadyExists),這個就使得需要使用的字體不位于字體表的首項成為必然了,這個時候用戶選擇的僅僅是ttf字體文件,而ttf字體文件的文件名是可以任意修改的,所以程序無法靠字體文件名來識別,那該如何正確獲得要用的字體呢?

慶幸ttf字體文件有一個唯一識別的字體名(fontname),通過這個特性就可以通過字體名來選擇需要使用的字體。至于如何去獲取這個唯一識別的字體名,就要去了解下ttf字體文件的結構信息,慶幸網絡上有Windows平臺上的實現代碼,具體詳見http://www.codeproject.com/KB/GDI/fontnamefromfile.aspx,我就偷梁換柱,將其改成如下代碼,用以在Symbian上實現從字體文件獲取字體名。具體的ttf文件結構可以通過百度或google搜索得到,因為很復雜,這里就不做贅述了。

#define MAKEWORD(a, b)      ((TText16)(((TText8)(a)) | ((TText16)((TText8)(b))) << 8))

#define MAKELONG(a, b)      ((TInt32)(((TText16)(a)) | ((TUint32)((TText16)(b))) << 16))

 

#define LOBYTE(w)           ((TText8)(w))

#define HIBYTE(w)           ((TText8)(((TText16)(w) >> 8) & 0xFF))

 

#define LOWORD(l)           ((TText16)(l))

#define HIWORD(l)           ((TText16)(((TUint32)(l) >> 16) & 0xFFFF))

 

#define SWAPWORD(x)     MAKEWORD(HIBYTE(x), LOBYTE(x))

#define SWAPLONG(x)     MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))

 

 

typedef struct _tagTT_OFFSET_TABLE

{

    TText16  uMajorVersion;

    TText16  uMinorVersion;

    TText16  uNumOfTables;

    TText16  uSearchRange;

    TText16  uEntrySelector;

    TText16  uRangeShift;

}TT_OFFSET_TABLE;

 

typedef struct _tagTT_TABLE_DIRECTORY

{

    char    szTag[4];           //table name

    TUint32   uCheckSum;          //Check sum

    TUint32   uOffset;            //Offset from beginning of file

    TUint32   uLength;            //length of the table in bytes

}TT_TABLE_DIRECTORY;

 

typedef struct _tagTT_NAME_TABLE_HEADER

{

    TText16  uFSelector;         //format selector. Always 0

    TText16  uNRCount;           //Name Records count

    TText16  uStorageOffset;     //Offset for strings storage, from start of the table

}TT_NAME_TABLE_HEADER;

 

typedef struct _tagTT_NAME_RECORD

{

    TText16  uPlatformID;

    TText16  uEncodingID;

    TText16  uLanguageID;

    TText16  uNameID;

    TText16  uStringLength;

    TText16  uStringOffset;  //from start of storage area

}TT_NAME_RECORD;

 

TInt GetFontNameFromFile(const TDesC16 &aFontFile, TDes16 &aFontName)

{

    RFs vFs;

    RFile vFile;

    TFileName vFileTemp;

    TBuf8<56> vBufTemp;

    TInt vErr = vFs.Connect();

    if(KErrNone != vErr)

    {

        return -1;

    }   

    vErr = vFile.Open(vFs, aFontFile, EFileRead|EFileShareAny);

    if(KErrNone != vErr)

    {

        vFs.Close();

        return -1;

    }

    else

    {

        TT_OFFSET_TABLE ttOffsetTable;

        TPtr8 vPtrttOffsetTable((TUint8 *)&ttOffsetTable, sizeof(TT_OFFSET_TABLE));

        vErr = vFile.Read(vPtrttOffsetTable, sizeof(TT_OFFSET_TABLE));

        if(KErrNone != vErr)

        {

            vFile.Close();

            vFs.Close();

            return -1;

        }

       

        ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);

        ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);

        ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);

 

        //check is this is a true type font and the version is 1.0

        if(ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0)

        {

            vFile.Close();

            vFs.Close();

            return -1;

        }

       

        TT_TABLE_DIRECTORY tblDir;

        TPtr8 vPtr8tblDir((TUint8*)&tblDir, sizeof(TT_TABLE_DIRECTORY));

        TBool bFound = EFalse;       

        for(TInt i = 0; i < ttOffsetTable.uNumOfTables; i++)

        {

            vErr = vFile.Read(vPtr8tblDir, sizeof(TT_TABLE_DIRECTORY));

            if(KErrNone != vErr)

            {

                vFile.Close();

                vFs.Close();

                return -1;

            }

            else

            {

                vBufTemp.Copy((TUint8*)tblDir.szTag, 4);

                if(vBufTemp.Compare(_L8("name")) == 0)

                {

                    bFound = ETrue;

                    tblDir.uLength = SWAPLONG(tblDir.uLength);

                    tblDir.uOffset = SWAPLONG(tblDir.uOffset);

                    break;

                }

            }

        }

       

        if(bFound)

        {

            TInt vDataTemp = tblDir.uOffset;

            vErr = vFile.Seek(ESeekStart, vDataTemp);

            if(KErrNone != vErr)

            {

                vFile.Close();

                vFs.Close();

                return -1;

            }

           

            TT_NAME_TABLE_HEADER ttNTHeader;

            TPtr8 vPtr8ttNTHeader((TUint8*)&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER));

            vErr = vFile.Read(vPtr8ttNTHeader, sizeof(TT_NAME_TABLE_HEADER));

            if(KErrNone != vErr)

            {

                vFile.Close();

                vFs.Close();

                return -1;

            }

            ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);

            ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);

           

            TT_NAME_RECORD ttRecord;

            TPtr8 vPtr8ttRecord((TUint8*)&ttRecord, sizeof(TT_NAME_RECORD));

            bFound = EFalse;

            for(TInt j = 0; j < ttNTHeader.uNRCount; j++)

            {

                vErr = vFile.Read(vPtr8ttRecord, sizeof(TT_NAME_RECORD));

                if(KErrNone != vErr)

                {

                    vFile.Close();

                    vFs.Close();

                    return -1;

                }

                ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);

                if(ttRecord.uNameID == 1)

                {

                    ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);

                    ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);

                    TInt nPos = 0;

                    vErr = vFile.Seek(ESeekCurrent, nPos);

                    if(KErrNone != vErr)

                    {

                        vFile.Close();

                        vFs.Close();

                        return -1;

                    }

                    vDataTemp = tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset;

                    vErr = vFile.Seek(ESeekStart, vDataTemp);

                    if(KErrNone != vErr)

                    {

                        vFile.Close();

                        vFs.Close();

                        return -1;

                    }

                    //bug fix: see the post by SimonSays to read more about it

                    HBufC8* vNameTemp = HBufC8::New(ttRecord.uStringLength + 1);

                    TPtr8 vPtrFontName(vNameTemp->Des());

                    vErr = vFile.Read(vPtrFontName, ttRecord.uStringLength);

                    if(KErrNone != vErr)

                    {

                        delete vNameTemp;

                        vNameTemp = NULL;

                        vFile.Close();

                        vFs.Close();

                        return -1;

                    }

                    if(vPtrFontName.Length() > 0)

                    {

                        aFontName.Copy(vPtrFontName);

                        delete vNameTemp;

                        vNameTemp = NULL;

                        break;

                    }

                    vErr = vFile.Seek(ESeekStart, nPos);

                    if(KErrNone != vErr)

                    {

                        delete vNameTemp;

                        vNameTemp = NULL;

                        vFile.Close();

                        vFs.Close();

                        return -1;

                    }

                   

                    delete vNameTemp;

                    vNameTemp = NULL;

                }

            }

        }

    }

   

    vFile.Close();

    vFs.Close();

    return 0;

}

通過上述實現,獲取了字體文件的字體名之后,我們就可以不用TypefaceSupport這種枚舉的方法了,直接設定TFontSpec的屬性然后通過調用GetNearestFont…相關函數來獲取需要的字體。

目前發現的還有一個問題,就是存在一種很特殊的情況,有時候調用了RemoveFile卸載了字體文件,但是字體文件卻還是處于打開或者在用的狀態,這個時候,通過上述的GetFontNameFromFile是無法取到字體名的,這種情況下,有時候就只能通過重啟手機,來將字體文件從內存中解綁。

正確加載并使用了字體卻顯示不出來

字體正確的加載并選擇使用了,但是通過這個選擇的字體,在UIDrawText的時候居然沒有繪制出來,不得不讓人懷疑這種方法是否可行。最后經過試驗發現,假如在一個局部函數內對同一字體分別調用AddFile或者InstallFile方法,然后繪制結束后調用RemoveFile方法,那么就是顯示不出繪制的東西。所以在A函數內加載字體(AddFile或者InstallFile),甚至在A函數內使用字體,但是就是不能在A函數內卸載剛剛添加的字體。

那既然加載的字體卸載起來這么麻煩,我干脆就不卸載了可以嗎,就好比程序在堆棧上申請的內容在程序退出的時候,系統會將程序所擁有的堆棧上申請的內容釋放掉,但是字體文件就是個特例,因為Symbian OS是通過C/S架構來實現的,程序加載只是通知OS內核中的CFbsServer去加載字體,假如不人為卸載,那么CFbsServer不會自己去卸載字體,而且程序一旦退出,就只有通過手機重啟的方法來卸載字體了。

所以起初設計Demo代碼采用了加載一個字體,將對應的fontID放到一個CArray隊列里,最后程序退出的時候,在類的析構函數中再一一卸載已經加載的字體。這種方法適合在一個程序中同時加載多個ttf字體。假如用戶的程序中始終只需要加載一個ttf字體,那么就可以通過在A函數中,進行加載新字體之前,先把已加載的字體卸載掉,然后再加載新的字體并使用。這樣的情況下,就不會造成用加載的字體繪制文本內容時顯示空白的問題。

其它還有一些問題,目前就不做整理了。

 

posted on 2011-02-21 10:28 frank.sunny 閱讀(3078) 評論(0)  編輯 收藏 引用 所屬分類: symbian 開發

常用鏈接

留言簿(13)

隨筆分類

個人其它博客

基礎知識鏈接

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲自拍偷拍网址| 日韩午夜av| 亚洲欧洲日本国产| 欧美女同视频| 亚洲免费在线精品一区| 午夜精品成人在线| 亚洲三级视频| 久久久久青草大香线综合精品| 亚洲国产日韩欧美综合久久| 亚洲午夜久久久久久久久电影网| 国产婷婷一区二区| 亚洲乱码日产精品bd| 在线观看亚洲精品视频| 亚洲先锋成人| 一区二区三区产品免费精品久久75| 亚洲欧美成人| 久久久国产精彩视频美女艺术照福利| 欧美激情在线| 亚洲黄色高清| 亚洲第一中文字幕在线观看| 午夜精品一区二区三区在线视| 亚洲黄色成人久久久| 久久久蜜桃精品| 欧美成人蜜桃| 亚洲欧洲日本国产| 欧美777四色影视在线| 久久男人av资源网站| 亚洲剧情一区二区| 欧美黄色一级视频| 91久久一区二区| 亚洲第一偷拍| 在线精品一区| 亚洲第一精品夜夜躁人人爽| 国产啪精品视频| 国产视频自拍一区| 欧美高清在线| 久久久久久精| 日韩视频在线一区二区| 欧美午夜精品久久久久久久| 欧美中文字幕精品| 亚洲全黄一级网站| 久久男人资源视频| 亚洲网站在线看| 在线日韩日本国产亚洲| 欧美性猛交xxxx乱大交蜜桃 | 久久久久久久高潮| 亚洲精品在线观看免费| 性欧美8khd高清极品| 一本色道久久综合| 亚洲第一页在线| 韩曰欧美视频免费观看| 国产精品国产三级国产| 欧美国产高潮xxxx1819| 久久国产黑丝| 久久精品国产清高在天天线| 亚洲一级电影| 亚洲午夜激情免费视频| 99精品国产热久久91蜜凸| 亚洲福利精品| 亚洲伦伦在线| 日韩系列欧美系列| 亚洲新中文字幕| 午夜一级在线看亚洲| 久久久中精品2020中文| 欧美成人免费视频| 欧美高清hd18日本| 欧美日韩国产精品自在自线| 欧美国产日韩亚洲一区| 欧美理论在线| 国产欧美不卡| 亚洲国产高清在线| 亚洲视频欧洲视频| 久久久久久一区二区| 久久亚洲免费| 亚洲午夜久久久| 香蕉av福利精品导航| 亚洲一区尤物| 久久国产精品99国产精| 免费看黄裸体一级大秀欧美| 免费看精品久久片| 国产精品久久久久久久久久三级 | 欧美电影在线| 亚洲裸体视频| 国产精品永久免费在线| 亚洲精品久久久久中文字幕欢迎你| 亚洲美女诱惑| 欧美激情一区二区三区四区| 一本色道久久综合亚洲精品小说 | 亚洲综合导航| 欧美激情中文字幕一区二区| 欧美午夜久久久| 在线一区欧美| 日韩亚洲欧美成人| 久久综合电影| 亚洲国产合集| 91久久精品国产91性色tv| 久久亚洲国产精品一区二区| 曰本成人黄色| 一区二区久久久久| 国产日韩亚洲欧美| 免费久久久一本精品久久区| 欧美激情久久久久| 性欧美大战久久久久久久久| 可以看av的网站久久看| 夜夜嗨av一区二区三区网站四季av| 亚洲人成网站777色婷婷| 美女主播精品视频一二三四| 亚洲欧美国产一区二区三区| 亚洲国内自拍| 欧美在线关看| 国内精品久久久久影院色| 久久精品五月婷婷| 久久综合伊人77777麻豆| 亚洲国产一区在线观看| 9i看片成人免费高清| 国产伦精品一区二区三区免费迷 | 欧美激情欧美狂野欧美精品| 欧美激情第9页| 久久精品国产亚洲一区二区| 免费成人性网站| 销魂美女一区二区三区视频在线| 久久电影一区| 亚洲欧美激情四射在线日 | 欧美日韩福利| 欧美freesex交免费视频| 欧美午夜一区| 亚洲国产精品福利| 狠狠色狠狠色综合日日五| 欧美激情第五页| 精品成人在线视频| 亚洲一区二区三区精品动漫| 亚洲人成网在线播放| 久久福利视频导航| 久久激情综合网| 久久精品成人一区二区三区蜜臀 | 欧美精品videossex性护士| 久久人人看视频| 在线看片日韩| 久热成人在线视频| 亚洲第一精品影视| 亚洲毛片在线观看| 欧美日韩三级视频| 亚洲日本欧美| 亚洲天天影视| 欧美一级网站| 最新成人av网站| 蜜臀99久久精品久久久久久软件 | 国产精品久久一卡二卡| 亚洲一区精品视频| 久久亚洲精品中文字幕冲田杏梨| 在线观看日韩国产| 欧美日韩另类字幕中文| 亚洲综合大片69999| 卡通动漫国产精品| 一区二区高清视频在线观看| 国产精品wwwwww| 久久精品首页| 一区二区三区视频观看| 久久国产精品久久精品国产| 国模一区二区三区| 欧美日韩国产在线一区| 久久精品人人爽| 亚洲午夜av在线| 欧美激情一区二区| 久久久久久日产精品| 亚洲一区二区欧美| 亚洲激情欧美| 在线日本欧美| 国产亚洲欧美日韩美女| 欧美日韩亚洲一区二| 理论片一区二区在线| 先锋影音国产精品| 亚洲永久免费观看| 一区二区三区不卡视频在线观看 | 欧美日韩国产色综合一二三四 | 久久精品国产v日韩v亚洲| 亚洲综合国产| 亚洲女人av| 欧美一区免费| 久久久久久久97| 久久久久一本一区二区青青蜜月| 欧美在线视频二区| 久久久国产亚洲精品| 久久黄色小说| 美女黄网久久| 欧美日韩中文另类| 国产精品亚洲第一区在线暖暖韩国| 欧美日韩精品久久| 国产精品久久二区二区| 欧美日韩中文字幕综合视频 | 亚洲一区国产精品| 翔田千里一区二区| 亚洲黄色影片| 亚洲国产精品va在线看黑人动漫 | 国产午夜精品一区二区三区视频| 国产自产精品| 亚洲欧美精品中文字幕在线| 久久九九精品99国产精品| 欧美大片第1页| 欧美在线观看日本一区|