Silverlight 完全中文解決方案

  • 7188
  • 0

摘要:Silverlight 完全中文解決方案

Silverlight 完全中文解決方案

作者:黃忠成

問題的起源
如你所知,Silverlight 具備相當完善的 2D 向量繪圖及動畫能力,而且擁有了通往 RIA 世界最重要的完整程式架構支援,但是一旦想將其應用在實務的網頁開發上時,你馬上會陷入到 Silverlight 目前無法顯示中文的窘境之中!!事實上,Silverlight 在顯示中文上並沒有問題,只是其 Runtime 並未內建中文字型,導致所有的中文字都會因缺乏字型的緣故而顯示成一個個的小方框,解決這個問題的方案也不是沒有,本文就一一細數目前在 Silverligh 上顯示中文的解決方案。

解法一:下載字型或是 ODTTF(XPS)
雖然 Silverlight Runtime 中未內建中文字型,不過倒是提供了字型下載的功能,Silverlight Runtime 支援 TTF 及 ODTTF(XPS) 等兩種字型,我們可以使用 Downloader 物件來下載包含字型的 ZIP 檔案,然後以 setFontSource 函式將字型指定給 TextBlock,如此便能顯示中文字了,詳細的做法可以參考 Silverlight SDK 的說明文件。但如你所知的,字型本身有著授權的問題,你不能下載未經授權的字型到客戶端,這意味著除非微軟同意,否則我們不能在網站上提供如 Windows 之細明體、標楷體等字型下載,當然!轉成 XPS 後所粹取出的 ODTTF 也是受到同樣限制的。

解法二:Path
微 軟的周旺暾先生提出了下載字型外的另一種解法,那就是使用 Path 物件,他提出了兩種使用 Path 物件來顯示中文的方法,一是使用 Blend 將中文直接轉成 Path,這個方法的確可行,但只適用於靜態字之顯示。二是於網站伺服器上安裝 .NET Framework 3.0,利用 WPF API 動態將指定文字轉成 Path 後回傳給客戶端,此法可適用於靜態或是動態之文字顯示,詳細請參考旺暾兄之 Blog:http://blogs.msdn.com/wtchou/

解法三:圖型
圖形解法是我於前幾個月所提出的解法,簡單 的說就是在伺服器端將文字輸出成圖形,回傳至客戶端指定給 Image 物件來顯示中文,詳細請參考我的 Blog:http://blog.csdn.net/Code6421/archive/2007/08/09/1733745.aspx

為何不在 Runtime 內嵌中文字型?
老 實說,除了下載字型外,使用 Path 或是圖形都只能算暫解燃眉之急的解法,畢竟 TextBlock 控件才是 Silverlight 用來顯示文字的主要控件,以 Path 來說,雖然支援換行上不是問題,但是若要兩行顏色或是字體不同,那就傷腦筋了!圖形也有著同樣的問題,如何算出輸出文字後圖形的大小,頁面上又該如何調配 都是問題,即使能夠克服,也必須花上不少時間!總歸一句話,只要 Silverlight Runtime 內嵌中文字型,一切的問題都迎刃而解,但這樣一來,Silverlight Runtime 就不可能低於 2MB,畢竟中文字博大精深,每個字型檔少說都要 8~9MB,就算用 ZIP 壓縮後也要 4~5MB,更不用談要支援繁簡兩種字型了,若再將其它語系算進去的話,那這個 Runtime 可以說是大怪物一隻了,別忘了!Silverlight Runtime 是要能夠執行於所有語系之系統上的!因此,Silverlight Runtime 內嵌中文字型的方式在實務上是不可行的,那又該如何是好呢?我認為應該循視情況下載字型的方向走,當觀看一個繁體中文的 Silverlight 網頁時,若使用者的 Silverlight Runtime 未下載所需要的字型,那麼就提示該使用者並自動由某一網站下載字型,這個某一網站可以是開發者的,也可以是微軟的,不過!這個假設建立在一個前題之下,那 就是下載字型的動作必須是合法的。

評估使用免費字型的可能性
好了!你現在應該由抱怨微軟不在 Silverlight Runtime 內嵌中文字型慢慢轉成抱怨微軟不在推出 Silverlight Runtime 時開放某些中文字型的授權了,事實上!就我所得到的消息,微軟目前正在研擬修改字型授權,未來各位可能可以將某些特定字型放在 Silverlight 網站上供人下載或是由微軟網站下載而不觸法,但是處理這件事需要一些時間,誰也說不準得花上多久。在這之前,除了使用 Path 或圖形外,我們也可以朝向找尋完全免費授權之免費字型的方向前進,目前筆者能找到的、並確定能使用在 Silverlgiht 的免費中文字型如下:

王漢宗老師:http://briian.com/?p=290
吳老師:ftp://cle.linux.org.tw/pub2/fonts/cwttf/center
文鼎捐贈給自由軟體界的四套字: http://cle.linux.org.tw/fonts/Arphic/
PS:內含兩套簡體字。
雖 然王漢宗老師所提供的字型較多且完整,但因為與文鼎有一些法律上的糾紛待處理,所以若你是要用於商業網站上,還是建議使用吳老師或是文鼎所提供的字型,另 外!請特別注意一點,Silverlight 的 FontFamily 必須使用英文名稱,以文鼎 PL 中楷來說,FontFamily 必須設定為【AR PL KaitiM Big5】。

當字型、授權不是問題時
OK,現在字型及授權都不是問題了,問題在於你 還是得寫下一些 JavaScript 程式碼,使用 Downloader 物件來下載需要的字型,並設定給 TextBlock,這雖然不難,但就是有點繁瑣,基於前次開發 Silverlight DataBindings 技術的經驗,我設計了一組 JavaScript Library 來協助各位更容易的在 Silverlight 上顯示中文。

方便的 JavaScript Library : FontHelper
FontHelper 提供了 Font Bindings 技術,讓你可以直接於 XAM L之 TextBlock 的 Tag 中指定要使用何種字型,如下例:





【DBCS】 是 FontHelper 辨識該 TextBlock 是否需要下載字型的關鍵字,【:】號之後的是字型壓縮檔的檔名,此檔案必須放在 Silverlight 網站下,以本例來說是放在網站的根目錄下,【;】後的是修飾字,FontHelper 支援使用者指定一個 default 字型,以本例來說,接下來的 TextBlock 只要以下例方式宣告,就可直接使用 cwkai.zip 的字型。





當 呼叫了 FontHelper 物件的 initialize 函式後,其將會搜尋頁面上的 TextBlock 控件,並一一為其下載需要的字型,那麼何時呼叫 initialize 函式呢?在這之前你得先引用 SLFH.js 到你的 Silverlight 網頁中 (此檔可於範例檔中的 SilverlightJSApplication1 或是 SilverlightJSApplication2 等目錄中找到),如下例:

Default.html





















然後在 handleLoad 事件中建立 FontHelper 並呼叫 initialize 函式,如下例:



.xaml.js




handleLoad: function(plugIn, userContext, rootElement)


{


this.plugIn = plugIn;


this.button = rootElement.children.getItem(0);


//建立Font Helper 物件


this.fh = new SilverlightHelper.FontHelper(rootElement);


//呼叫initialize函式,掃描Page 上所有的TextBlock控件,並自動下載字型


this.fh.initialize();;


}




這是靜態字型的使用方式,倘若我想在 JavaScript 中直接使用其它字型呢?FontHelper 提供了 setTextWithFont 函式能幫你達到這個需求。



.xaml.js




//呼叫setTextWithFont來設定TextBlock的字型及文字


//參數:


// setTextWithFont(







Default.html.js




function createSilverlight()


{


var scene = new SilverlightJSApplication1.Scene();


Silverlight.createObjectEx({


source: 'Scene.sxaml',


parentElement: document.getElementById('SilverlightPlugInHost'),


id: 'SilverlightPlugIn',


properties: {


width: '400',


height: '400',


background:'#ffffffff',


isWindowless: 'false',


version: '0.8'


},


events: {


onError: null,


onLoad: Silverlight.createDelegate(scene, scene.handleLoad)


},


context: null


});


}



if (!window.Silverlight)


window.Silverlight = {};



Silverlight.createDelegate = function(instance, method) {


return function() {


return method.apply(instance, arguments);


}


}




Scene.xaml








Storyboard.TargetName="highlightEllipse"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" />



Storyboard.TargetName="highlightEllipse"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" />



Storyboard.TargetName="highlightEllipse"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" />



Storyboard.TargetName="highlightEllipse"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" />





Width="120" Height="44" Stroke="#46000000">








Canvas.Left="17" Canvas.Top="12" Foreground="#FFEFEFEF" Text="我是中文"
FontFamily="cwTeXKai" FontSize="24" Tag="DBCS:cwkai.zip;default" />

FontSize="26" Text="格式化中文測試" Tag="DBCS:default">


FontHelper 完全支援 TextBlock的Run指令



斜體目前仍無法處理



粗體字也無法處理




Canvas.Top="280"
FontFamily="cwTeXKai"
FontSize="42"
Tag="DBCS:default">
漸層中文字
















Fill="#00FFFFFF" Name="highlightEllipse" Canvas.Left="3" Canvas.Top="3"/>




Scene.xml.js


if (!window.SilverlightJSApplication1)
window.SilverlightJSApplication1 = {};


SilverlightJSApplication1.Scene = function()
{
}

SilverlightJSApplication1.Scene.prototype =
{
handleLoad: function(plugIn, userContext, rootElement)
{
this.plugIn = plugIn;
this.button = rootElement.children.getItem(0);

this.button.addEventListener("MouseEnter",
Silverlight.createDelegate(this, this.handleMouseEnter));
this.button.addEventListener("MouseLeftButtonDown",
Silverlight.createDelegate(this, this.handleMouseDown));
this.button.addEventListener("MouseLeftButtonUp",
Silverlight.createDelegate(this, this.handleMouseUp));
this.button.addEventListener("MouseLeave",
Silverlight.createDelegate(this, this.handleMouseLeave));

//建立Font Helper 物件
this.fh = new SilverlightHelper.FontHelper(rootElement);
//呼叫initialize函式,掃描Page 上所有的TextBlock控件,並自動下載字型
this.fh.initialize();;
},

// Sample event handlers
handleMouseEnter: function(sender, eventArgs)
{
// The following code shows how to find an element by name and call a method on it.
var mouseEnterAnimation = sender.findName("mouseEnter");
mouseEnterAnimation.begin();
},

handleMouseDown: function(sender, eventArgs)
{
var mouseDownAnimation = sender.findName("mouseDown");
mouseDownAnimation.begin();
},

handleMouseUp: function(sender, eventArgs)
{
var mouseUpAnimation = sender.findName("mouseUp");
mouseUpAnimation.begin();

// Put clicked logic here
alert("clicked");
//呼叫setTextWithFont來設定TextBlock的字型及文字
//參數:
// setTextWithFont(