玄铁剑

成功的途径:抄,创造,研究,发明...
posts - 128, comments - 42, trackbacks - 0, articles - 174
 

作者:奚江華(TaiWan)

本頁內容

中文字顯示之前言

*
範例程式 collapse menu

*
* *

Silverlight 1.0 正式版內建只支援 9 種英文字型,這對於歐美國家的 Silverlight 程式開發人員與使用者而言至少有 9 種英文字型可供挑選變化(圖1),但令人玩味的是沒有 "直接" 支援中文字型的顯示,而這對於使用中文、日文與韓文等語系的使用者便會造成困擾,因為在 Silverlight1.0 中無法正確顯示中文、日文與韓文等相關字型,例如中文字顯示會是像亂碼般的四方形框框(圖 2)。其原因並不是 Silverlight 1.0 對於字元的處理沒有採用 Unicode 編碼設計,而導致中文以類似亂碼般顯示,事實上 Silverlight 1.0 本身設計是以 Unicode 方式來處理編碼沒錯,但真正的問題出在於 Silverlight 的 Runtime Component 並沒有包含中文字型檔(如.ttf),或者無法呼叫使用作業系統的中文字型,故 Silverlight 陷入了空有 Unicode 的編碼設計,但卻沒有中文字型可供顯示中文字的窘境。


圖 1 Silverlight 1.0 內建支援 9 種英文字型


圖 2 中文字無法正常顯示

Silverlight 1.0 中文字顯示解決方案

雖然 Silverlight 本身具備極為優越的 2D 向量文字、繪圖與影音能力,但是若缺乏中文字顯示的支援能力,對亞洲國家的使用者、程式設計人員乃至於企業端都會造成很大的困擾,故本文將針對如何讓 Silverlight 可以正確顯示中文字型而提供數種解決方案,然而這幾種中文字的顯示方式各有其不同的特性與優缺點,故您可依個案情境,挑選對 Silverlight 應用程式及開發成本最佳的方式,所以各位可以視情況而懂得變通,不一定得墨守成規,一個方式用到底。

在此整理一下 Silverlight 1.0 用於顯示中文字的幾種解決方案,以下是解決方案架構圖。


圖 3 中文字解決方案架構圖

在上面的架構圖中,我們可以看到顯示中文的途徑有三大類,分別是文字物件、繪圖物件與圖片檔三種,然而這三種方式有著截然不同特性與處理議題,會對您的 Silverlight 程式的設計與執行有著顯著的影響,讓我們先來瞭解其個別內容,最後再來針對此三種方案進行初步的比較,中文字解決方案架構圖說明如下:

(一)文字物件

Silverlight 用來直接顯示文字的物件有 Glyphs 與 TextBlock,然而此二者有者相當不同的特性,說明如下:

  • Glyphs

    Glyphs 顯示中文字時,會以非同步的方式從 Web 伺服器下載完整的字型檔,但其中最大的困擾是 Glyphs 下載整個字型檔會造成網路頻寬的爆增,而過大的下載位元則是 Internet 應用程式的殺手之一,同時下載整個字型檔也會涉及字型版權的法律問題。

    範例一 使用預設的 Glyphs 顯示中文字(完整 TTF 字型檔下載)

    本範例將示範如何運用預設的 Glyphs 物件來顯示中文字,其最關鍵點在於指定字型檔所在的網路位置給 FontUri 屬性即可。請參考 GlyphsTTF.html 及 GlyphsTTF.xaml 程式,以下為 GlyphsTTF.xaml 程式碼:

    GlyphsTTF.xaml
    <Canvas xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
        <Canvas Name="myCanvas" Background="LightBlue" Width="600"
        Height="400" MouseLeftButtonDown="handleMouseUp">
        <!--Glyphs1-->
        <Glyphs
        FontUri = "http://localhost/ChineseFont/fonts/CURLZ___.TTF"
        FontRenderingEmSize = "100"
        UnicodeString       = "Silverlight"
        Fill                = "Black"
        OriginX             = "0"
        OriginY             = "100">
        </Glyphs>
        <!--Glyphs2-->
        <Glyphs
        FontUri = "http://localhost/ChineseFont/fonts/MSJH.TTF"
        FontRenderingEmSize = "100"
        UnicodeString       = "正黑體"
        Fill                = "Red"
        OriginX             = "0"
        OriginY             = "200"
        >
        </Glyphs>
        <!--Glyphs3-->
        <Glyphs
        FontUri = "http://localhost/ChineseFont/fonts/KAIU.TTF"
        FontRenderingEmSize = "100"
        UnicodeString       = "楷書體"
        Fill                = "Black"
        OriginX             = "0"
        OriginY             = "300">
        </Glyphs>
        </Canvas>
        </Canvas>
        
    完成後請執行 GlyphsTTF.html 程式,執行結果如下圖。


    圖 4 Glyphs 物件顯示中文字

    表面上 Glyphs 顯示中文字絲毫不費太多的力氣,但最大的問題在於 Glyphs 會下載所有用到的完整字型檔案,一如上面共用到了三個字型檔,所以便會悉數完整下載,這在 Silverlight 的程式開發人員電腦上執行時,問題可能不明顯,但若換成錙銖必較 Internet 有限頻寬,動輒 5MB 甚至是 10MB 以上的中文字型要下載到 Client 端電腦,可能會是網站的致命殺手,故對此問題不可不慎重視之。各位可以到使用者電腦中路徑 C:\Documents and Settings\adminvista\Local Settings\Temporary Internet Files\Content.IE5\ 目錄下搜尋 *.ttf 檔,便可以找到相關 ttf 檔案。

    也許冰雪聰明的各位會想到,如果完整的 TTF 檔過大,那是否有可能擷取應用程式所需的部分字型,然後製作一個較小的字型檔,以便字型檔下載時可以較為迅速,如此不就解決了!?答案正是如此,是真的有方法可以只擷取所需的字型,再加以製作成一個 .odttf 檔,而依字型的種類不同,最終檔案的大小可能是幾百 KB~1000KB,至少比起動輒 5MB 或 10MB 以上的 TTF 檔案快多了,在 Internet 上傳輸也是一個可行的解決方案。在此筆者先製作出一個標楷體的部分字型檔,其檔案名稱為「3F1838BE-604B-601D-DA75-B576DE686443.odttf」,而各位先只管如何使用這個部分字型檔練習即可,後面會有獨立小節解釋 ODTTF 字型檔及製作的詳細步驟。


    圖 5 Glyphs 下載之完整型檔

    範例二 使用 Glyphs 顯示部分嵌入字型檔 ODTTF(部分嵌入字型檔下載)

    本範例將示範 Glyphs 如何使用部分嵌入字型檔 ODTTF 來顯示中文字型,步驟說明如下:

    Step 1:製作部分嵌入字型檔 ODTTF
    首先製作名稱為「3F1838BE-604B-601D-DA75-B576DE686443.odttf」的只含部分嵌入字型的檔案,主要是希望縮小字型檔的體積大小,讓 Glyphs 可以迅速下載讀取,在這請各位直接使用 ODTTF 當做練習,先不急著知道怎麼製作。

    Step 2:在 Glyphs 指定使用 ODTTF 字型檔
    請在 Glyphs 物件的 FontUri 屬性指定 ODTTF 字型檔所在的完整HTTP網路位置,Glyphs 就能夠直接顯示中文字型了,請參考 GlyphsODTTF.html 及 GlyphsODTTF.xaml 程式,以下為 GlyphsODTTF.xaml 程式碼:

    GlyphsTTF.xaml
    <Canvas
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Canvas >
        <Glyphs Fill="Blue" UnicodeString="春花秋月何時了,"
        FontUri="http://localhost/ChineseFont/Fonts/3F1838BE-604B-601D-
        DA75-B576DE686443.odttf"
        FontRenderingEmSize="30" Canvas.Top="0"/>
        <Glyphs Fill="Blue" UnicodeString="往事知多少,"
        FontUri="http://localhost/ChineseFont/Fonts/3F1838BE-604B-601D-
        DA75-B576DE686443.odttf"
        FontRenderingEmSize="30" Canvas.Top="40"/>
        <Glyphs Fill="Red" UnicodeString="小樓昨夜又東風,"
        FontUri="http://localhost/ChineseFont/Fonts/649C70ED-5A7E-7277-
        6038-1A0DBB6BDF08.odttf"
        FontRenderingEmSize="30" Canvas.Top="80"/>
        <Glyphs Fill="Red" UnicodeString="故國不堪回首月明中"
        FontUri="http://localhost/ChineseFont/Fonts/649C70ED-5A7E-7277-
        6038-1A0DBB6BDF08.odttf"
        FontRenderingEmSize="30" Canvas.Top="120"/>
        </Canvas>
        </Canvas>
        
    完成後請執行 GlyphsODTTF.html 程式,執行結果如下圖。


    圖 6 Glyphs 顯示部分字型檔

  • TextBlock

    Silverlight 1.0 的 TextBlock 物件,基本上只能直接顯示英文字型,對於 Unicode 字型如中文字則會以小方框替代,不像 Glyphs 至少可以顯示中文字型,頂多是字型檔下載稍嫌大了點。而 TextBlock 不能直接顯示中文的原因,是出在 Silverlight 本身沒有內建中文字型,亦不能呼叫作業系統的中文字來使用,再加上 TextBlock 根本不能像 Glyphs 可指定網路上某個位置字型檔的機制,故 TextBlock 要顯示中文字會較 Glyphs 麻煩了點。然而要讓 TextBlock 顯示中文需要兩個額外步驟:
    • 使用 Downloader 物件下載中文字型。
    • 在 TextBlock 的 setFontSource 方法設定字型檔來源,以及字型檔名稱。

    如此便可讓 TextBlock 可以正常顯示中文字,讓我們來看以下的範例。

    範例三 以 Downloader 下載完整 TTF 字型供 TextBlock 使用

    本範例將示範如何透過 Downloader 物件從 Web 伺服器下載所需的完整 TTF 字型到使用者電腦端,如此 TextBlock 便有中文字型可供顯示中文字,步驟說明如下:

    Step 1:準備 TTF 中文字型
    在此準備一個標楷體的中文字型檔 Kaiu.ttf,以及另一個壓縮檔 Kaiu.zip,而壓縮或未壓縮的字型檔都可以被 Downloader 下載給 TextBlock 使用,不過想當然爾是壓縮過後的字型下載速度較快,也比較不佔用 Internet 頻寬,例如 Kaiu.ttf 未壓縮前是 5,015KB,壓縮後是 2,825KB,檔案大小約減少了 43%,下載字型檔的速度當然也更快。

    Step 2:建立 XAML 程式主體
    請參考 TextBlockDownloaderTTF.xaml 的程式主體,以下為 XAML 程式碼:

    TextBlockDownloaderTTF.xaml
    <Canvas xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Loaded="handleLoad">
        <!-- 進度列指示器 -->
        <Canvas x:Name="ProgressIndicator" Canvas.Left="10"
        Canvas.Top="10" Canvas.ZIndex="1">
        <Rectangle x:Name="progressRectangle"
        Canvas.Left="10"
        Height="10" Width="0"
        Fill="Maroon" />
        <Rectangle
        Canvas.Top ="-1"
        Canvas.Left="9" Height="12"
        Width="202"
        StrokeThickness="1" Stroke="Black" />
        <TextBlock
        x:Name="progressText"
        Canvas.Top ="-4" Canvas.Left="230"
        Text="0%" FontSize="12" />
        </Canvas>
        <Canvas Name="myCanvas" Background="LightBlue" Width="600"
        Height="400" Canvas.Top="0"  Canvas.ZIndex="0" >
        <TextBlock Name="myTextBlock"
        TextWrapping="Wrap"  Width="300" FontSize="30"
        Canvas.Top="80" Canvas.Left="100" >
        千山鳥飛絕
        萬徑人蹤滅
        孤舟簑笠翁
        獨釣寒江雪
        </TextBlock>
        </Canvas>
        </Canvas>
        
    程式說明:
    • 在 TextBlock 中指定中文字沒有什麼特別的地方,設定方式與英文字相同。
    • 但是有個比較特別的地方是需要額外指定 Downloader 的載入程式,而就是在 Canvas 或 TextBlock 的 Loaded 事件中指定 JavaScript 事件,呼叫 Downloader 執行非同步的字型檔載入

    Step 3:建立 Downloader 下載程式
    請在 TextBlockDownloaderTTF.xaml.js 程式中建立 Downloader 相關程式:

    TextBlockDownloaderTTF.xaml.js
    var delegate1;
        var delegate2;
        // Loaded 事件處理常式。
        function handleLoad(sender, eventArgs)
        {
        // 取得Silverlight Plugin物件
        var slPlugin = sender.getHost();
        // 建立Downloader 物件
        var downloader = slPlugin.createObject("downloader");
        // 建立DownloadProgressChanged與Completed 事件委派
        delegate1= downloader.addEventListener("downloadProgressChanged", onDownloadProgressChanged);
        delegate2= downloader.addEventListener("completed", onCompleted);
        // 初始化下載要求
        downloader.open("GET", "Fonts/Kaiu.zip");
        //下載未壓縮的TTF字型也可以
        //downloader.open("GET", "Fonts/Kaiu.ttf");
        // 開始傳送下載
        downloader.send();
        }
        // Completed 事件處理常式
        function onCompleted(sender, eventArgs)
        {
        // 移除DownloadProgressChanged 事件與其事件處理常式的委派關係
        sender.removeEventListener("downloadProgressChanged", delegate1);
        // 移除Completed 事件與其事件處理常式的委派關係
        sender.removeEventListener("completed", delegate2);
        var textblock = sender.findName("myTextBlock");
        textblock.setFontSource(sender);
        textblock.fontFamily="DFKai-SB";
        //將Downloader物件設定為null
        sender = null;
        }
        // 負責更新進度列
        function onDownloadProgressChanged(sender, eventArgs)
        {
        var progressText = sender.findName("progressText");
        var progressRectangle = sender.findName("progressRectangle");
        // 計算下載的百分比
        var percentage = Math.floor(sender.downloadProgress * 100);
        // 更新進度列的Rectangle 與TextBlock 物件
        progressText.text = percentage + "%";
        progressRectangle.width = percentage * 2;
        }
        
    程式說明:
    onCompleted 事件是用來下載字型檔,它是本程式最重要的核心,而 onDownloadProgressChanged 是用來顯示下載進度的百分比,不過是為了人性化,實質上可有可無。完成後請執行 TextBlockDownloaderTTF.html 程式,執行畫面如下圖。


    圖 7 TextBlock 顯示 TTF 完整字型檔

    範例四 以 Downloader 下載部分嵌入字型檔 ODTTF 供 TextBlock 使用

    在前面介紹過 Glyphs 使用部分嵌入字型檔 ODTTF,ODTTF 字型檔的優點是所需的檔案大小可以減少為原來的好幾倍,而 ODTTF 不止 Glyphs 可以使用,同樣的 TextBlock 也可以使用,只要透過 Downloader 下載 ODTTF 即可,請參考以下的步驟說明:

    Step 1:製作部分嵌入字型檔 ODTTF
    在此製作一個「01026A73-2351-5325-5665-E8572E1A1805.odttf」的正黑體字型檔,裡面所包含的文字為:「千山鳥飛絕,萬徑人蹤滅,孤舟簑笠翁,獨釣寒江雪」,並將其檔壓縮成 EmbededChinese.zip,借此將 ODTTF 字型檔由原來的 1,015KB 進一步壓縮到 22KB 而已,這是一個更為驚人的方式,因為可以在 Internet 以極高的速度下載傳送。

    Step 2:建立 XAML 程式主體
    請參考 TextBlockDownloaderODTTF.xaml 的程式主體,以下為 XAML 程式碼:

    TextBlockDownloaderODTTF.xaml
    <Canvas xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
        <!-- 進度列指示器 -->
        <Canvas x:Name="ProgressIndicator" Canvas.Left="10"
        Canvas.Top="10" Canvas.ZIndex="1">
        <Rectangle x:Name="progressRectangle"
        Canvas.Left="10"
        Height="10" Width="0"
        Fill="Maroon" />
        <Rectangle
        Canvas.Top ="-1"
        Canvas.Left="9" Height="12"
        Width="202"
        StrokeThickness="1" Stroke="Black" />
        <TextBlock
        x:Name="progressText"
        Canvas.Top ="-4" Canvas.Left="230"
        Text="0%" FontSize="12" />
        </Canvas>
        <Canvas Name="myCanvas" Background="LightBlue" Width="600"
        Height="400" Canvas.Top="0"  Canvas.ZIndex="0" >
        <TextBlock Name="myTextBlock"
        TextWrapping="NoWrap"  Width="300" FontSize="30"
        Canvas.Top="100" Canvas.Left="100" Loaded="handleLoad">
        千山鳥飛絕
        萬徑人蹤滅
        孤舟簑笠翁
        獨釣寒江雪
        <TextBlock.RenderTransform>
        <RotateTransform Angle="30" CenterX="150"
        CenterY="150"/>
        </TextBlock.RenderTransform>
        </TextBlock>
        </Canvas>
        </Canvas>
        
    Step 3:建立 Downloader 下載程式
    請在 TextBlockDownloaderODTTF.xaml.js 程式中建立 Downloader 相關程式:

    TextBlockDownloaderODTTF.xaml.js
    var delegate1;
        var delegate2;
        // Loaded 事件的事件處理常式
        function handleLoad(sender, eventArgs)
        {
        // 取得Silverlight Plugin的參考。
        var slPlugin = sender.getHost();
        // 建立Downloader 物件
        var downloader = slPlugin.createObject("downloader");
        // 建立DownloadProgressChanged 與Completed 事件委派。
        delegate1 = downloader.addEventListener("downloadProgressChanged",
        onDownloadProgressChanged);
        delegate2 = downloader.addEventListener("completed", onCompleted);
        // 初始化下載要求
        downloader.open("GET", "Fonts/EmbededChinese.zip");
        // 開始傳送下載
        downloader.send();
        }
        // Completed 事件處理常式
        function onCompleted(sender, eventArgs)
        {
        // 取消DownloadProgressChanged 事件與其事件處理常式的委派關係
        sender.removeEventListener("downloadProgressChanged", delegate1);
        // 取消Completed 事件與其事件處理常式的委派關係。
        sender.removeEventListener("completed", delegate2);
        var textblock = sender.findName("myTextBlock");
        textblock.setFontSource(sender);
        textblock.TextWrapping="Wrap";
        textblock.fontFamily="Microsoft JhengHei";
        // 將Downloader 物件設定成null
        sender = null;
        }
        // 負責更新進度列
        function onDownloadProgressChanged(sender, eventArgs)
        {
        var progressText = sender.findName("progressText");
        var progressRectangle = sender.findName("progressRectangle");
        // 計算下載的百分比
        var percentage = Math.floor(sender.downloadProgress * 100);
        // 更新進度列的Rectangle 與TextBlock 物件
        progressText.text = percentage + "%";
        progressRectangle.width = percentage * 2;
        }
        
    程式說明:
    正黑體字型的英文名稱為「Microsoft JhengHei」,在程式中指定正黑體時必須使用英文名稱而非中文名稱。完成後請執行 TextBlockDownloaderODTTF.html 程式,執行畫面如下圖。


    圖 8 TextBlock 顯示部分嵌入 ODTTF 字型檔

警告:
  • ODTTF 檔的名稱不可以任意做更改,否則便無法作用。
  • 若要使用到的中文字都必須事先出現在 ODTTF 檔之中,不可以臨時使用未曾事先輸入的中文字
ODTTF 字型檔除了事先製作外,也可以動態產生,請參考另一位微軟專家黃忠誠之專欄文章「Silverlight 完全中文解決方案」,網址如下:
http://www.microsoft.com/taiwan/msdn/columns/huang_jhong_cheng/Silverlight_cht_solutions.htm

(二)Path 向量繪圖物件

將中文字型轉換成 Path 向量繪圖物件,其原理是將中文字轉換成大量的繪圖座標資訊,並且透過 Path 幾何繪圖物件來顯示這些座標資料。但是使用這個方法有一點要特別注意,一旦將文字轉換成 Path 物件之後,它就是圖形,無論它是不是向量與否,它已不再是文字了,因此不能被檢索查詢,也不能以字串的型式存入資料庫,更不可被 Search Engine 搜尋引擎所爬文檢索。故倘若您的網站很在意是否能被搜尋引擎爬文檢索,進而影響您的網站或商品在搜尋引擎網站可以被使用者或顧客查詢到,就要特別意識到避免使用這個方法。

然而將中文字型轉換成 Path 向量繪圖物件有兩個簡單的基本型式,第一是使用像 Expression Blend 2 這類的工具將文字轉換成 Path 物件,第二個方式是撰寫一個 Web Services,透過程式呼叫 Web Services 將轉換後的 Path 物件回傳給 Silverlight 應用程式。


圖 9 中文字型轉換成 Path 向量圖形

範例五 使用 Blend 2 將中文字型轉換成 Path 向量繪圖物件

本範例將示範使用 Blend 2 將中文字型轉換成 Path 向量繪圖物件,步驟說明如下:

Step 1:開啟 Blend 2 輸入中文字
首先您必須下載並安裝 Expression Blend 2 開發工具,並在其中以 TextBlock 物件輸入中文字,例如:「月落烏啼霜滿天」的中文字。

Step 2:將 TextBlock 文字轉換成 Path 向量圖形
首先點選 TextBlock 文字物件,並點選【Object】選單 ->【Path】->【Convert to Path】,如此便能將 TextBlock 中文字轉換成 Path 向量圖形。


圖 10 Blend2 將中文字轉換成 Path 向量圖形

這個方法雖然可以將「月落烏啼霜滿天」七個中文字轉換成 Path 向量座標的資訊描述,但是其結果卻是巨幅的84行複雜的描述資料,而這種方式好或不好各位可以自己評估。


圖 11 巨量的 Path 物件座標描述資料

相對於事先用 Blend 2 將中文字轉換成 Path 向量圖形,那還有另一種可以透過事先撰寫好的 Web Services,讓它回傳中文的 Path 向量圖形,一來免除了 Blend 2 工具的需求,二來可以動態產生。可是其缺點是您必須維護一台 Web Services 的伺服器,但如果您是將 Silverlight 應用程式伺服器放在 Linux 作業系統上的 Web Server,這時又該如何?是另外找一台 Windows 主機來建立 Web Services 服務?這也是有點莞爾的,故動態呼叫 Web Services 就有這樣子的缺點存在。

註:
至於動態產生 Path 向量中文圖形,請參考微軟專家周旺暾的一篇文章「以 WPF + AJAX 在執行期間將文字轉成 Path」,其網址為:
http://blogs.msdn.com/wtchou/archive/2007/08/13/wpf-ajax-path-silverlight.aspx

(三)圖片檔

至於運用圖片檔來顯示中文,例如將 JPG 或 PNG 格式的圖片交由 Image 或 ImageBrush 物件來顯示即可,並沒有什麼特殊之處,唯一的工作是需要事先用影像處理軟體來處理所需的中文字圖片。

中文字型檔

在前面所運用到的幾種字型,相信大家比較熟悉的是 .ttf 字型,對於其他延伸檔名字型檔 odttf 等等,想必會覺得奇怪且陌生,故在此做一統籌摘要講解。可運用在 Silverlight 的中文字型檔可分為三大類,分別是 True Type、True Type Collection 及 OpenType 這三類,而三大類實際儲存成四種延伸檔名,然而其對應用延伸檔明說明如下表:

字型延伸檔名 GlyphsTextBlockPath圖片檔
.ttf 完整的 True Type 或 OpenType 字型(TrueType font outlines)。
.ttc 完整的 True Type 字型集合。
.ttc 完整的 True Type 字型(PostScript font outlines)。
.odttf 完整的 True Type 字型(PostScript font outlines)。
表1 字型檔說明

在此針對以上幾種延伸檔名稍加解說:

  • ttf 延伸檔名

    相信各位對 ttf 字型檔應不陌生才是,因為現在的 Microsoft Windows 作業系統內建就是使用 TrueType 字型;然而若您使用最新的 Windows Vista 作業系統,則系統內建使用的是 OpenType 字型,它是 TrueType 字型的擴充,並且若是為 TrueType outlines 的 OpenType 字型則也是以 .ttf 的格式來命名。


    圖 12 TTF 字型檔

  • ttc 延伸檔名

    .ttc 是在單一的檔案中包含數個 TrueType 字型檔,故稱之為 True Type 字型集合。然而為什麼要刻意將數個 TrueType 字型塞入到同一個檔案之中呢?其中的用意為何,有什麼優點?讓我們先來看一下 Windows 作業系統 Fonts 目錄下的幾個 .ttc 字型集合,到底長什麼樣子,請看下圖。


    圖 13 TTC 字型集合

    請各位特別注意上圖中延伸檔名為 ttc 的字型檔,特別是紅色框框所標示的字型,例如 Simsun.ttc 檔案同時包含了宋体 & 新宋体兩種字體,而在集合之中的多種字型多半是屬於同一種相關字體,而 ttc 字型集合最大的用意在於多種字型之間有相同的 Glyph Sets,如果將它們包含在同一個檔案中就可以共用這些 Glyph Sets,進而能夠節省字型檔案的大小,會比幾種字型分開個別儲存節省磁碟空間,所以這是 ttc 字型檔最大的用意。
  • otf 延伸檔名

    otf 其實也是 TrueType 的一種,只不過它是屬於 OpenType 字型的 PostScript outlines,但是 otf 在 Microsoft Windows 作業系統中並沒有附上這類的字型,故筆者在網路上下載了一個免費的「LikhanNormal.otf」字型檔附在專案程式之中。而在一般情況下,它其實跟 .ttf 的字型檔在使用上不會有什麼明顯的差異,所以並沒有太大的進階學問可以探討。


    圖 14 OTF 字型檔

  • odttf 延伸檔名

    Odttf 的字型檔其英文原文為 Obfuscated TTF,它是屬於XPS規格中所定義的 Embedded Font Obfuscation,odttf 原本設計最大的目的是要防止 XPS 文件中包含完整的字型被盜用或被使用者拿去安裝在使用者電腦,故只嵌入部分的字型。然而碰巧只嵌入部分字型檔的特性,反而成為讓 Silverlight 下載中文字型可以更快速的一個優點。

以上介紹了四種延伸檔名字型的由來,相信各位應該有初步瞭解了。

製作嵌入部分字型的 ODTTF 檔

前一節所介紹的四種延伸檔名字型,只有一種是我們可以製作或介入的,那就是 ODTTF,一來系統並不會替您準備這類字型檔,二來它是需要我們輸入相關的嵌入文字才能製作的。

在 XPS 規格文件中所描述的 ODTTF 的設計是為了達成三個目標:

  • Obfuscated 字型檔是被嵌入在 XPS 文件之中,並且是以一種不能被使用者安裝在 Client 端作業系統的型式來包裝(Package)。
  • Obfuscated 字型檔和參照它們的內容形成一個緊密的結合。因此使用者無法從一個 XPS 文件之中盜用相關 ODTTF 字型到另一個 XP S文件中使用。
  • 最重要的是雖然 Obfuscated 字型檔和參照它們的內容形成一個緊密的結合,但它仍然允許 XPS 文件的合併。

而要製作一個 ODTTF 嵌入部分字型檔方式有兩種,第一個是用 XPS 文件製作工具,第二個是動態呼叫 WPF 的 XpsDocument 等相關 API,由 Service 回傳動態製作出的 ODTTF 字型檔,然而以下僅介紹事先用 NotePad 工具製作 ODTTF 檔的範例。

範例六 以 NotePad 及 XPS Document Writer 製作 ODTTF 嵌入部分字型檔

一個標準的 XPS 文件之中即會包含 ODTTF 檔,故我們只需建立一個 XPS 檔,再擷取其中所包含的 ODTTF 字型檔即可,而本範例將示範以 XPS Document Writer 製作 XPS 檔,並取出 XPS 中的 ODTTF 嵌入部分字型檔,步驟說明如下:

Step 1:下載並安裝 XPS Essentials Pack 軟體
XPS Essentials Pack 是用來瀏覽及製作 XPS 文件的一個小工具,您可以上微軟網站輸入關鍵字「XPS Essentials Pack」查詢,即可找到相關下載的網頁,下載安裝完成後,即會在作業系統產生兩個工具,一是 XPS Viewer,另一個是在印表機會產生一個 Microsoft XPS Document Writer,透過它就可以以列印文件的方式來產生所需的 XPS 檔案。

Step 2:在 NotePad 中列印 XPS 文件
首先在 NotePad 中輸入所需的中文字,例如「春花秋月何時了,往事知多少,小樓昨夜又東風,故國不堪回首月明中,雕蘭玉砌應猶在,只是朱顏改,問君能有幾多愁,恰似一江春水向東流。」然後再以 Microsoft XPS Document Writer 列印儲存成 Chinese.xps 檔,而 XPS 就會包含先前輸入的部分中文字型。


圖 15 以 XPS Document WRITER 列印儲存XPS檔

Step 3:粹取 XPS 文件中的 ODTTF 字型
接著我們要粹取 XPS 文件中的 ODTTF 字型,故請將 Chinese.xps 延伸檔名改為 Chinese.zip 檔,因為 XPS 實際上是以 ZIP 方式來進行包裝的,然後再開啓 Chinese.zip 檔,在其 Document\Resources\Fonts 之中就會有一個 .odttf 檔,主檔名是以 128 位元的 GUID (Globally Unique Identifier) 方式來命名,故其主檔名不可以自行任意變更,否則字型檔便無法作用。

Step 4:ODTTF 交由 Glyphs 或 TextBlock 文字物件使用
最後做好之後,只需在 Glyphs 的 FontUri 指定 ODTTF 檔即可直接套用中文字型,或是 TextBlock 配合 DownLoader 下載 ODTTF 檔之後,直接套用,或者您可以回頭參考第二節中的範例介紹。


圖 16 ODTTF 嵌入部分字型檔

除了可以用 NotePad 配合 Microsoft XPS Document Writer 製作 XPS 檔,若您有 Word 2007 可以直接儲存成 XPS,再抽取其中的 ODTTF 檔,但是您必須另外下載安裝一個叫【2007 Microsoft Office Add-In: Microsoft Save as PDF】的增益集,安裝完成後就可以在 Word 2007 中直接儲存成XPS檔了。


圖 17 Word 直接儲存成XPS格式

免費的中文字型檔

然而雖然我們技術上已克服了中文字顯示的問題,就字型檔無論是完整的 ttf 或部分字型的 odttf 都可能有字型授權的法律問題,因為原本字型的授權是以作業系統為對象,而非可以放在 Web Server 供任意使用者下載使用,故請諸位要特別注意這個問題。

為避免字型版權的考量,也許有的人會想到如果有免費的中文字型不就可以避開授權的法律問題,的確正是如此,至於免費字型目前比較為人熟知的有以下幾個:

註:
關於免費中文字型的比較與描述,請各位參考微軟專家黃忠成專欄中【評估使用免費字型的可能性】小節的比較與說明:http://www.microsoft.com/taiwan/msdn/columns/huang_jhong_cheng/Silverlight_cht_solutions.htm

各種中文字顯示方案之比較

在此針對各種中文字顯示方案做一個摘要比較表。

  Glyphs TextBlock Path 圖片檔
文字或圖型之類型 文字 文字 向量圖形 位元圖形
可被檢索查詢
可被搜尋引擎爬文
需要字型檔配合
支援完整字型檔來源    
支援部分字型檔來源    
Client 端需要下載字型檔
需要Downloader輔助
支援ZIP壓縮字型檔    
表2 各種中文字顯示解決方案比較表

由以上諸多種種特性的比較,您可以視不同的 Silverlight 應用程式的特性,來決定該用什麼方式來處理中文字顯示問題,例如您若只有一個中文 Header 要顯示,用中文字圖片可能是簡單俐落,來得迅速;反之,若您是有一長篇的文章要顯示,甚至還要進行文字屬性的變化,自然是用 TextBlock 或 Glyphs 來處來,而這就是您必須視情況去考量的。

只有注册用户登录后才能发表评论。