Windows Server 2008 R2 中的手寫辨識
Windows Server 2008 R2 支援伺服器端手寫辨識。 伺服器端辨識可讓伺服器從網頁上的手寫筆輸入辨識內容。 這在網路上的使用者將會指定使用自訂字典解譯的詞彙時特別有用。 例如,如果您有一個醫療應用程式會查詢伺服器資料庫以取得病患名稱,則這些名稱可能會新增至另一個資料庫,而該資料庫會在從手寫 Silverlight 表單執行搜尋時進行交叉參考。
設定伺服器以進行Server-Side辨識
應遵循下列步驟來設定伺服器端辨識。
- 安裝筆跡和手寫服務
- 安裝 Web Server (IIS) 和應用程式伺服器的支援
- 啟用桌面體驗角色
- 啟動平板電腦輸入服務
安裝筆跡和手寫服務
若要安裝 Ink 和 Handwriting 服務,請按一下 [快速啟動] 匣中的伺服器管理員圖示,以開啟伺服器管理員。 從 [ 功能] 功能表中,按一下 [ 新增功能]。 請確定您選取 [ 筆跡和手寫服務 ] 核取方塊。 下圖顯示已選取[筆跡和手寫服務] 的 [選取功能] 對話方塊。
已選取筆跡和手寫服務核取方塊的 [選取功能] 對話方塊
Web Server (IIS) 和應用程式伺服器的安裝支援
如同您在第一個步驟中所做的一樣開啟伺服器管理員。 接下來,您必須新增 Web 服務器 (IIS) 和應用程式伺服器角色。 從 [ 角色] 功能表中,按一下 [ 新增角色]。 [新增角色] 精靈隨即出現。 按一下 [下一步] 。 確定已選取 [應用程式伺服器 ] 和 [ Web 服務器] (IIS) 。 下圖顯示 [ 選取伺服器角色 ] 對話方塊,其中已選取 [Web 服務器 (IIS) 和 應用程式伺服器 角色]。
選取伺服器角色對話方塊,並選取 web 伺服器 (iis) 和應用程式伺服器角色
當您選取 [應用程式伺服器] 時,系統會要求您安裝 ASP.NET 架構。 按一下 [ 新增必要功能 ] 按鈕。 按一下 [ 下一步]之後,您會看到概觀對話方塊;按一下 [下一步]。 [ 選取角色服務 ] 對話方塊現在應該可供使用。 確定已選取 [Web 服務器 (IIS) ]。 下圖顯示 [ 選取角色服務 ] 對話方塊,其中已啟用 Web Server (IIS) 。
選取已啟用 web 伺服器 (iis) 的角色服務對話方塊
按一下 [下一步] 。 [概觀] 對話方塊隨即出現;再次按 [下一步 ]。 您現在會看到網頁伺服器 (IIS) 角色選項的頁面。 按一下 [下一步] 。 在下一個頁面上,[ 安裝 ] 按鈕將會變成作用中。 按一下 [安裝 ],您將安裝 Web Server (IIS) 和應用程式伺服器的支援。
啟用桌面體驗角色
若要啟用桌面體驗,請按一下 [開始],按一下 [系統管理工具],然後按一下[伺服器管理員]。 選取 [新增服務 ],然後選取 桌面體驗 服務。 下圖顯示已安裝桌面體驗專案的 [ 選取功能 ] 對話方塊。
已選取桌面體驗服務的 [選取功能] 對話方塊
按 [下一步] 安裝桌面體驗。
啟動平板電腦服務
安裝桌面體驗服務之後,平板電腦輸入服務會出現在 [ 服務 ] 功能表中。 若要存取 [服務 ] 功能表,請按一下 [ 開始],按一下 [ 系統管理工具],然後按一下 [ 服務]。 若要啟動服務,請以滑鼠右鍵按一下 [平板電腦輸入服務 ],然後按一下 [ 啟動]。 下圖顯示已啟動平板電腦輸入服務的 [服務 ] 功能表。
已啟動平板電腦輸入服務的服務功能表
使用 Silverlight 執行Server-Side辨識
本節說明如何建立使用 Silverlight 來擷取手寫輸入的 Web 應用程式。 使用下列步驟在 Visual Studio 2008 中設計辨識器。
- 安裝及更新 Visual Studio 2008 以新增 Silverlight 的支援。
- 在 Visual Studio 2008 中建立新的 Silverlight 專案。
- 將必要的服務參考新增至您的專案。
- 建立 Silverlight WCF 服務以進行筆跡辨識。
- 將服務參考新增至您的用戶端專案。
- 將 InkCollector 類別新增至 InkRecognition 專案。
- 從用戶端設定中移除安全傳輸指示詞
安裝及更新 Visual Studio 2008 以新增 Silverlight 支援
開始之前,您必須在 Windows Server 2008 R2 伺服器上執行下列步驟。
- 安裝 Visual Studio 2008。
- 安裝 Microsoft Visual Studio 2008 Service Pack 1。
- 安裝 Microsoft Silverlight 5 SDK。
安裝這些應用程式和更新之後,您就可以開始建立伺服器端辨識 Web 應用程式。
在 Visual Studio 2008 中建立新的 Silverlight Web 專案
從 [檔案] 功能表,按一下 [新增專案]。 從 Visual C# 專案清單中選取 Silverlight 應用程式範本。 將專案命名為 InkRecognition,然後按一下 [ 確定]。 下圖顯示已選取並命名為 InkRecognition 的 C# Silverlight 專案。
已選取 c# silverlight 專案,名稱為 inkrecognition
按一下 [ 確定] 之後,對話方塊會提示您將 Silverlight 應用程式新增至專案。 選取 [將新的 ASP.NET Web 專案新增至方案以裝載 Silverlight ,然後按一下 [ 確定]。 下圖顯示如何在按一下 [ 確定] 之前設定範例專案。
對話方塊,提示將 silverlight 應用程式新增至專案
將必要的服務參考新增至您的專案
現在,您已將一般 Silverlight 用戶端專案 (InkRecognition) ,並將 Web 專案 (InkRecognition.Web) 在您的方案中設定。 專案會開啟,並開啟 Page.xaml 和 Default.aspx。 關閉這些視窗,然後以滑鼠右鍵按一下 InkRecognition 專案中的 references 資料夾,然後選取 [ 新增參考],將 System.Runtime.Serialization 和 System.ServiceModel 參考新增至 InkRecognition 專案。 下圖顯示已選取必要參考的對話方塊。
已選取 system.runtime.serialization 和 system.servicemodel 的 [新增參考] 對話方塊
接下來,您必須將 System.ServiceModel 和 Microsoft.Ink 參考新增至 InkRecognition.Web 專案。 Microsoft.Ink 參考預設不會出現在 .NET 參考中,因此請在 Windows 資料夾中搜尋Microsoft.Ink.dll。 找到 DLL 之後,請將元件新增至專案參考:選取 [ 流覽 ] 索引標籤、變更包含Microsoft.Ink.dll的資料夾、選取 [Microsoft.Ink.dll],然後按一下 [ 確定]。 下圖顯示 Windows 檔案總管中已新增所有參考元件的專案方案。
Windows 檔案總管中已新增所有參考元件的 inkrecognition 專案
建立適用于筆跡辨識的 Silverlight WCF 服務
接下來,您會將用於筆跡辨識的 WCF 服務新增至專案。 以滑鼠右鍵按一下 InkRecognition.Web 專案,按一下 [ 新增],然後按一下 [ 新增專案]。 選取 WCF Silverlight 服務範本,將名稱變更為 InkRecogitionService,然後按一下 [ 新增]。 下圖顯示 [ 新增專案 ] 對話方塊,其中已選取 Silverlight WCF 服務並命名。
已選取 silverlight wcf 服務並命名為 [新增專案] 對話方塊
新增 WCF Silverlight 服務之後,InkRecognitionService.cs 後置的服務程式代碼將會開啟。 以下列程式碼取代服務程式代碼。
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Text;
using Microsoft.Ink;
namespace InkRecognition.Web
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class InkRecognitionService
{
[OperationContract]
public string[] Recognize(int[][] packets)
{
// Deserialize ink.
Ink ink = new Ink();
Tablet tablet = new Tablets().DefaultTablet;
TabletPropertyDescriptionCollection desc = new TabletPropertyDescriptionCollection();
desc.Add(new TabletPropertyDescription(PacketProperty.X, tablet.GetPropertyMetrics(PacketProperty.X)));
desc.Add(new TabletPropertyDescription(PacketProperty.Y, tablet.GetPropertyMetrics(PacketProperty.Y)));
int numOfStrokes = packets.GetUpperBound(0) + 1;
for (int i = 0; i < numOfStrokes; i++)
{
ink.CreateStroke(packets[i], desc);
}
// Recognize ink.
RecognitionStatus recoStatus;
RecognizerContext recoContext = new RecognizerContext();
recoContext.RecognitionFlags = RecognitionModes.LineMode | RecognitionModes.TopInkBreaksOnly;
recoContext.Strokes = ink.Strokes;
RecognitionResult recoResult = recoContext.Recognize(out recoStatus);
RecognitionAlternates alternates = recoResult.GetAlternatesFromSelection();
string[] results = new string[alternates.Count];
for (int i = 0; i < alternates.Count; i++)
{
results[i] = alternates[i].ToString();
}
// Send results to client.
return results;
}
}
}
將服務參考新增至您的用戶端專案
既然您有適用于 InkRecognition 的 Silverlight WCF 服務,您將會從用戶端應用程式取用服務。 以滑鼠右鍵按一下 InkRecognition 專案,然後選取 [ 新增服務參考]。 從出現的 [ 新增服務參考] 對話方塊中,選取 [ 探索 ] 以從目前的解決方案探索服務。 InkRecognitionService 會出現在 [服務] 窗格中。 按兩下 [服務] 窗格中的 InkRecognitionService,將命名空間變更為 InkRecognitionServiceReference,然後按一下 [ 確定]。 下圖顯示已選取 InkRecognitionService 且命名空間已變更的 [新增服務參考 ] 對話方塊。
已選取 inkrecognitionservice 且命名空間已變更的 [新增服務參考] 對話方塊
將 InkCollector 類別新增至 InkRecognition 專案
以滑鼠右鍵按一下 InkRecognition 專案,按一下 [ 新增],然後按一下 [ 新增專案]。 從 [Visual C#] 功能表中,選取 [C# 類別]。 將類別命名為 InkCollector。 下圖顯示已選取並命名 C# 類別的對話方塊。
已選取並命名 c# 類別的新增專案對話方塊
新增 InkCollector 類別之後,類別定義將會開啟。 以下列程式碼取代 Ink Collector 中的程式碼。
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace InkRecognition
{
public class InkCollector : IDisposable
{
public InkCollector(InkPresenter presenter)
{
_presenter = presenter;
_presenter.Cursor = Cursors.Stylus;
_presenter.MouseLeftButtonDown += new MouseButtonEventHandler(_presenter_MouseLeftButtonDown);
_presenter.MouseMove += new MouseEventHandler(_presenter_MouseMove);
_presenter.MouseLeftButtonUp += new MouseButtonEventHandler(_presenter_MouseLeftButtonUp);
}
void _presenter_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_presenter.CaptureMouse();
if (!e.StylusDevice.Inverted)
{
_presenter.Cursor = Cursors.Stylus;
_stroke = new Stroke(e.StylusDevice.GetStylusPoints(_presenter));
_stroke.DrawingAttributes = _drawingAttributes;
_presenter.Strokes.Add(_stroke);
}
else
{
_presenter.Cursor = Cursors.Eraser;
_erasePoints = e.StylusDevice.GetStylusPoints(_presenter);
}
}
void _presenter_MouseMove(object sender, MouseEventArgs e)
{
if (!e.StylusDevice.Inverted)
{
_presenter.Cursor = Cursors.Stylus;
}
else
{
_presenter.Cursor = Cursors.Eraser;
}
if (_stroke != null)
{
_stroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(_presenter));
}
else if (_erasePoints != null)
{
_erasePoints.Add(e.StylusDevice.GetStylusPoints(_presenter));
StrokeCollection hitStrokes = _presenter.Strokes.HitTest(_erasePoints);
if (hitStrokes.Count > 0)
{
foreach (Stroke hitStroke in hitStrokes)
{
_presenter.Strokes.Remove(hitStroke);
}
}
}
}
void _presenter_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_presenter.ReleaseMouseCapture();
if (_stroke != null)
{
_stroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(_presenter));
}
_stroke = null;
_erasePoints = null;
}
public DrawingAttributes DefaultDrawingAttributes
{
get { return _drawingAttributes; }
set { _drawingAttributes = value; }
}
public void Dispose()
{
_presenter.MouseLeftButtonDown -= new MouseButtonEventHandler(_presenter_MouseLeftButtonDown);
_presenter.MouseMove -= new MouseEventHandler(_presenter_MouseMove);
_presenter.MouseLeftButtonUp -= new MouseButtonEventHandler(_presenter_MouseLeftButtonUp);
_presenter = null;
}
private InkPresenter _presenter = null;
private Stroke _stroke = null;
private StylusPointCollection _erasePoints = null;
private DrawingAttributes _drawingAttributes = new DrawingAttributes();
}
}
更新預設頁面的 XAML,並新增手寫辨識的程式碼後置
既然您已擁有收集筆跡的類別,您必須使用下列 XAML 更新 page.xaml 中的 XAML。 下列程式碼會將黃色漸層新增至輸入區域、InkCanvas 控制項,以及將觸發辨識的按鈕。
<UserControl x:Class="InkRecognition.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Margin="5" Grid.Row="0" BorderThickness="4" BorderBrush="Black" CornerRadius="5" Height="200">
<Grid>
<InkPresenter x:Name="inkCanvas">
<InkPresenter.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0" Color="Yellow"/>
<GradientStop Offset="1" Color="LightYellow"/>
</LinearGradientBrush>
</InkPresenter.Background>
</InkPresenter>
<Button Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="10" Content="Recognize" Click="RecoButton_Click"/>
</Grid>
</Border>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="28" Text="Result: "/>
<ComboBox x:Name="results" Grid.Column="1" FontSize="28"/>
</Grid>
</Grid>
</UserControl>
以下列程式碼取代 Page.xaml.cs 頁面後置程式碼,以新增 [辨識 ] 按鈕的事件處理常式。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using InkRecognition.InkRecognitionServiceReference;
namespace InkRecognition
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
inkCol = new InkCollector(inkCanvas);
recoClient = new InkRecognitionServiceClient();
recoClient.RecognizeCompleted += new EventHandler<RecognizeCompletedEventArgs>(recoClient_RecognizeCompleted);
}
private void RecoButton_Click(object sender, RoutedEventArgs e)
{
// Serialize the ink into an array on ints.
ObservableCollection<ObservableCollection<int>> packets = new ObservableCollection<ObservableCollection<int>>();
double pixelToHimetricMultiplier = 2540d / 96d;
foreach (Stroke stroke in inkCanvas.Strokes)
{
packets.Add(new ObservableCollection<int>());
int index = inkCanvas.Strokes.IndexOf(stroke);
for (int i = 0; i < stroke.StylusPoints.Count; i += 2)
{
packets[index].Add(Convert.ToInt32(stroke.StylusPoints[i].X * pixelToHimetricMultiplier));
packets[index].Add(Convert.ToInt32(stroke.StylusPoints[i].Y * pixelToHimetricMultiplier));
}
}
// Call the Web service.
recoClient.RecognizeAsync(packets);
}
void recoClient_RecognizeCompleted(object sender, RecognizeCompletedEventArgs e)
{
// We have received results from the server, now display them.
results.ItemsSource = e.Result;
UpdateLayout();
results.SelectedIndex = 0;
inkCanvas.Strokes.Clear();
}
private InkRecognitionServiceClient recoClient = null;
private InkCollector inkCol = null;
}
}
從用戶端組態移除安全傳輸指示詞
您必須先從服務設定中移除所有安全傳輸選項,才能取用 WCF 服務,因為 Silverlight 2.0 WCF 服務目前不支援安全傳輸。 從 InkRecognition 專案,更新 ServiceReferences.ClientConfig 中的安全性設定。 從變更安全性 XML
<security mode="None">
<transport>
<extendedProtectionPolicy policyEnforcement="WhenSupported" />
</transport>
</security>
to
<security mode="None"/>
現在,您的應用程式應該執行。 下圖顯示應用程式在 awebpage 內的外觀,以及輸入到辨識方塊中的一些手寫。
awebpage 內的應用程式,其中已輸入一些手寫到辨識方塊中
下圖顯示 [ 結果 ] 下拉式清單中的辨識文字。
應用程式在 awebpage 內,在結果下拉式清單中具有辨識的文字