34
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 物件來顯示中文,詳細請參考我的 Bloghttp://blog.csdn.net/Code6421/archive/2007/08/09/1733745.aspx

Silverlight chinese

Embed Size (px)

Citation preview

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 XAML TextBlock Tag

DBCS FontHelper TextBlock : Silverlight ;FontHelper default TextBlock cwkai.zip

FontHelper initialize TextBlock initialize SLFH.js Silverlight ( SilverlightJSApplication1 SilverlightJSApplication2 ) Default.html SilverlightJSApplication1

createSilverlight();

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 //setTextWithFontTextBlock //: // // //PS: setTextWithFont!! this.fh.setTextWithFont(sender.findName("DynamicText"), "","cwfs.zip","cwTeXFangSong"); setTextWithFont(,,,)

setTextWithFont FontFamily FontHelper SilverlightJSApplication1 Default.html SilverlightJSApplication1

createSilverlight(); 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

FontHelper TextBlockRun

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"); //setTextWithFontTextBlock //: // setTextWithFont(,,,) // //PS: setTextWithFont!! this.fh.setTextWithFont(sender.findName("DynamicText"), "","cwfs.zip","cwTeXFangSong"); },

handleMouseLeave: function(sender, eventArgs) { var mouseLeaveAnimation = sender.findName("mouseLeave"); mouseLeaveAnimation.begin(); } }

PS: Silverlight Runtime 1.0 Bug setFontSource

FontHelper Silverlight FireFox

6.98MB 6.95MB ODTTF () ODTTF .NET Framework 3.0 XPS Document Writer Word

XPS XPS ODTTF ODTTF Word TTF ODTTF Windows Windows\Fonts |

Word

.xps .zip .ODTTF

zip partialFonts.zip SilverlightJSApplication1 Sence.xaml Sence.xaml.js Sence.xaml

FontHelper TextBlockRun

Sence.xaml.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"); //setTextWithFontTextBlock //: // setTextWithFont(,,,) // //PS: setTextWithFont!! //this.fh.setTextWithFont(sender.findName("DynamicText"), //"","cwfs.zip","cwTeXFangSong"); this.fh.setTextWithFont(sender.findName("DynamicText"), "","partialFonts.zip","cwTeXFangSong"); },

handleMouseLeave: function(sender, eventArgs) { var mouseLeaveAnimation = sender.findName("mouseLeave"); mouseLeaveAnimation.begin(); } }

FireFox

67KB XPS Font Service ODTTF Word XPS Document Writer ODTTF 100% WPF Path XPS ODTTF .NET Framework 3.0 Font Services GetFontsXPS.aspx ZIP ( SharpZipLib Zip http://www.icsharpcode.net/OpenSource/SharpZipLib/ ) SilverlightJSApplication2 FontServces.cs

using System; using System.ComponentModel; using System.Configuration; using System.Collections; using System.Collections.Generic; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Windows; using System.Globalization; using System.Windows.Media; using System.IO.Packaging; using System.IO; using System.Windows.Xps; using System.Printing; using System.Windows.Xps.Packaging; using System.Text; using System.Reflection; using System.Security.Permissions;

public class FontService { private static Dictionary _fontMapping = new Dictionary();

static FontService() { //(,) _fontMapping.Add("HanWangMingLight", ""); _fontMapping.Add("HanWangMingMedium", ""); _fontMapping.Add("HanWang WeiBeiMedium-Gb5", ""); _fontMapping.Add("HanWang FangSongMedium-Gb5", ""); // _fontMapping.Add("cwTeXHeiBold", "cwTeXHeiBold"); _fontMapping.Add("cwTeXFangSong", "cwTeXFangSong"); _fontMapping.Add("cwTeXKai", "cwTeXKai");

_fontMapping.Add("cwTeXYen", "cwTeXYen"); _fontMapping.Add("cwTeXMing", "cwTeXMing"); }

//create xps. private DrawingVisual CreateDrawingVisualText(string formattedText, string fontName, CultureInfo ci) { // Create an instance of a DrawingVisual. DrawingVisual drawingVisual = new DrawingVisual();

// Retrieve the DrawingContext from the DrawingVisual. DrawingContext drawingContext = drawingVisual.RenderOpen();

// Draw a formatted text string into the DrawingContext. drawingContext.DrawText( new FormattedText(formattedText, ci, FlowDirection.LeftToRight, new Typeface(fontName), 12, Brushes.Black), new Point(200, 116));

// Close the DrawingContext to persist changes to the DrawingVisual. drawingContext.Close(); return drawingVisual; }

private void VisualToXps(string fileName, string formattedText, string fontName, CultureInfo ci) {

Package package = Package.Open(fileName, FileMode.Create); { XpsDocument doc = new XpsDocument(package, CompressionOption.SuperFast); {

XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc); writer.Write(CreateDrawingVisualText(formattedText, fontName, ci)); } doc.Close(); } package.Close(); }

private FileStream BuildFontFont(string formattedText, string fontName, CultureInfo ci) { string key = Guid.NewGuid().ToString(); if (!Directory.Exists(HttpRuntime.AppDomainAppPath + "App_Data\\TempFonts")) Directory.CreateDirectory(HttpRuntime.AppDomainAppPath + "App_Data\\TempFonts"); string basePath = HttpRuntime.AppDomainAppPath + "App_Data\\TempFonts\\"; VisualToXps(basePath + "\\" + key + ".xps", formattedText, fontName, ci); Compression.UnZipClass unZip = new Compression.UnZipClass(); string fileName = unZip.UnZip(basePath + "\\" + key + ".xps", basePath); File.Delete(basePath + "\\" + key + ".xps"); Compression.ZipClass Zip = new Compression.ZipClass(); Zip.ZipFile(fileName, HttpRuntime.AppDomainAppPath + "CachedFonts\\" + key + ".zip", 8, 8192); File.Delete(fileName); return new FileStream(HttpRuntime.AppDomainAppPath + "CachedFonts\\" + key + ".zip", FileMode.Open, FileAccess.Read); }

private void DeleteOutDateFonts() { foreach (string item in Directory.GetFiles( HttpRuntime.AppDomainAppPath + "CachedFonts\\")) { DateTime dt = File.GetCreationTime(item); TimeSpan ts = DateTime.Now - dt; if (ts.Hours > 2) File.Delete(item); }

}

public FontService(Page page) { page.Load += new EventHandler(page_Load); }

void page_Load(object sender, EventArgs e) { Page page = (Page)sender; if (!String.IsNullOrEmpty(page.Request.QueryString["FontName"])) { DeleteOutDateFonts(); string fontName = page.Request.QueryString["FontName"]; string texts = page.Server.UrlDecode(Encoding.Default.GetString( Convert.FromBase64String(page.Request.QueryString["Data"]))); if (_fontMapping.ContainsKey(fontName)) fontName = _fontMapping[fontName]; FileStream fs = BuildFontFont(texts, fontName, CultureInfo.GetCultureInfo("zh-TW")); fs.Close(); page.Response.Clear(); page.Response.Write("CachedFonts/" + Path.GetFileName(fs.Name)); page.Response.End(); } } } DeCompress.cs using System; using System.Text; using System.Collections; using System.IO; using System.Diagnostics; using System.Runtime.Serialization.Formatters.Binary; using System.Web;

using ICSharpCode.SharpZipLib.BZip2; using ICSharpCode.SharpZipLib.Zip;

using ICSharpCode.SharpZipLib.Zip.Compression; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; using ICSharpCode.SharpZipLib.GZip; using ICSharpCode.SharpZipLib.Checksums;

namespace Compression { public class UnZipClass { public string UnZip(string fileName,string basePath) { string name = string.Empty; using (FileStream inputStream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { ZipInputStream s = new ZipInputStream(inputStream);

ZipEntry theEntry; while ((theEntry = s.GetNextEntry()) != null) { string directoryName = Path.GetDirectoryName(theEntry.Name); if (directoryName == "Resources") { if (!Directory.Exists( HttpRuntime.AppDomainAppPath + "App_Data\\TempFonts")) Directory.CreateDirectory( HttpRuntime.AppDomainAppPath + "App_Data\\TempFonts"); FileStream fs = File.Create(basePath+"\\"+ Path.GetFileName(theEntry.Name)); name = fs.Name; int size = 2048; byte[] data = new byte[2048]; while (true) { size = s.Read(data, 0, data.Length); if (size > 0) fs.Write(data, 0, size);

else break; } fs.Close(); break; } } s.Close(); } return name; } }

public class ZipClass { public void ZipFile(string FileToZip, string ZipedFile, int CompressionLevel, int BlockSize) { FastZip fz = new FastZip(); fz.CreateZip(ZipedFile, Path.GetDirectoryName(FileToZip), false, Path.GetFileName(FileToZip)); } } } GetFontsXPS.aspx.cs using System; using System.ComponentModel; using System.Configuration; using System.Collections; using System.Collections.Generic; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Windows;

using System.Globalization; using System.Windows.Media; using System.IO.Packaging; using System.IO; using System.Windows.Xps; using System.Printing; using System.Windows.Xps.Packaging; using System.Text; using System.Reflection; using System.Security.Permissions;

public partial class GetFontsXPS : System.Web.UI.Page { private FontService _fontServices = null;

public GetFontsXPS() { _fontServices = new FontService(this); } }

Font Services ASP.NET FontName Data XPS ODTTF JavaScript Data JavaScript Base64 FontHelper FontHelper XPS Font Service FontHelper XPS Font ServiceSilverlightJSApplication2 XPS Font Service Scene.xaml

FontHelper TextBlockRun

Secne.xaml.js if (!window.SilverlightJSApplication1) window.SilverlightJSApplication1 = {};

SilverlightJSApplication1.Scene = function()

{ }

SilverlightJSApplication1.Scene.prototype = { handleLoad: function(plugIn, userContext, rootElement) { this.plugIn = plugIn; this.rootElement = rootElement; 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)); var fh = new SilverlightHelper.FontHelper(rootElement); 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(); var fh = new SilverlightHelper.FontHelper(this.rootElement); var input = document.getElementById("DyanmicInput"); if(input && input.value && input.value != '')

fh.setTextWithXPS(sender.findName("DynamicText"),input.value, "GetFontsXPS.aspx?FontName=cwTeXFangSong","cwTeXFangSong"); else fh.setTextWithXPS(sender.findName("DynamicText"), "JavaScript","GetFontsXPS.aspx?FontName=cwTeXFangSong","cwTeXFangSong"); },

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

// Put clicked logic here alert("clicked"); },

handleMouseLeave: function(sender, eventArgs) { var mouseLeaveAnimation = sender.findName("mouseLeave"); mouseLeaveAnimation.begin(); } }

FontHelper setTextWithFont setTextWithXPS handleMouseDown: function(sender, eventArgs) { var mouseDownAnimation = sender.findName("mouseDown"); mouseDownAnimation.begin(); var fh = new SilverlightHelper.FontHelper(this.rootElement); var input = document.getElementById("DyanmicInput"); if(input && input.value && input.value != '') fh.setTextWithXPS(sender.findName("DynamicText"),input.value, "GetFontsXPS.aspx?FontName=cwTeXFangSong","cwTeXFangSong"); else fh.setTextWithXPS(sender.findName("DynamicText"), "JavaScript", "GetFontsXPS.aspx?FontName=cwTeXFangSong","cwTeXFangSong"); }

()

PS: Windows XPS Font Services

Silverlight Silverlight XPS Font Services Font Helper Library Developer Notes 1 Font Binding Helper Download/Network Error

TextBlock TAG Windows (Use XPS) 2 Font Binding Helper Font Services 100 Font Binding Helper Font Servcies (Downloader URL ) 3 Cross-Domain Font Services(GetFontsXPS.aspxFontServcies.cs) Silverlight 4 Font Servcies App_Data\TempFonts CachedFonts Silverlight IIS ( Windows 2003 IIS_WPG ) 5 () SilverlightJSApplication1 .zip XPS Font Service Windows 6 7 Visual Studio 2005 Silverlight XAML Designer Scene.xaml backup_xaml.txt 8 http://code6421.myweb.hinet.net /SLFH_Samples.zip (19MB)