筆跡序列化範例
此範例示範如何以各種格式序列化和取消序列化筆跡。 應用程式代表表單,其中包含用於輸入名字、姓氏和簽章的欄位。 使用者可能會將此資料儲存為純筆跡序列化格式, (ISF) 、可延伸標記語言 (XML) 使用 base64 編碼的 ISF 或 HTML 來參考 base64 編碼的強化圖形交換格式 (GIF) 影像中的筆跡。 應用程式也可讓使用者開啟儲存為 XML 和 ISF 格式的檔案。 ISF 格式會使用擴充屬性來儲存名字和姓氏,而 XML 和 HTML 格式會將此資訊儲存在自訂屬性中。
此範例不支援從 HTML 格式載入,因為 HTML 不適合儲存結構化資料。 由於資料會分成名稱、簽章等等,因此需要保留此分隔的格式,例如 XML 或其他種類的資料庫格式。
HTML 在格式設定很重要的環境中非常有用,例如在文字處理檔中。 此範例所儲存的 HTML 會使用強化的 GIF。 這些 GIF 內嵌 ISF,可保留筆跡的完整逼真度。 文字處理應用程式可以儲存包含多種資料類型的檔,例如影像、表格、格式化的文字,以及以 HTML 格式保存的筆跡。 此 HTML 會在無法辨識筆跡的瀏覽器中呈現。 不過,載入至啟用筆跡的應用程式時,原始筆跡的完整逼真度可供使用,並可轉譯、編輯或用於辨識。
此範例會使用下列功能:
收集筆墨
首先,參考隨 Windows Vista 和 Windows XP Tablet PC Edition Software Development Kit (SDK) 一起安裝的平板電腦 API。
using Microsoft.Ink;
建構函式會建立並啟用表單的 InkCollectoric
。
ic = new InkCollector(Signature.Handle);
ic.Enabled = true;
儲存檔案
方法 SaveAsMenu_Click
會處理 [另存新檔] 對話方塊、建立用來儲存筆跡資料的檔案資料流程,並呼叫對應至使用者選擇的 save 方法。
儲存至 ISF 檔案
在 方法中 SaveISF
,第一個和姓氏值會新增至InkCollector物件Ink屬性的ExtendedProperties屬性,然後筆跡才會序列化並寫入檔案。 在筆跡序列化之後,會從 Ink 物件的 ExtendedProperties 屬性中移除名字和姓氏值。
byte[] isf;
// This is the ink object which is serialized
ExtendedProperties inkProperties = ic.Ink.ExtendedProperties;
// Store the name fields in the ink object
// These fields roundtrip through the ISF format
// Ignore empty fields since strictly empty strings
// cannot be stored in ExtendedProperties.
if (FirstNameBox.Text.Length > 0)
{
inkProperties.Add(FirstName, FirstNameBox.Text);
}
if (LastNameBox.Text.Length > 0)
{
inkProperties.Add(LastName, LastNameBox.Text);
}
// Perform the serialization
isf = ic.Ink.Save(PersistenceFormat.InkSerializedFormat);
// If the first and last names were added as extended
// properties to the ink, remove them - these properties
// are only used for the save and there is no need to
// keep them around on the ink object.
if (inkProperties.DoesPropertyExist(FirstName))
{
inkProperties.Remove(FirstName);
}
if (inkProperties.DoesPropertyExist(LastName))
{
inkProperties.Remove(LastName);
}
// Write the ISF to the stream
s.Write(isf,0,isf.Length);
儲存至 XML 檔案
在 方法中 SaveXML
, 會使用 XmlTextWriter 物件來建立和寫入 XML 檔。 使用 Ink 物件的 Save 方法,筆跡會先轉換成 base64 編碼的筆跡序列化格式位元組陣列,然後將位元組陣列轉換成要寫出 XML 檔案的字串。 表單中的文字資料也會寫出至 XML 檔案。
// Get the base64 encoded ISF
base64ISF_bytes = ic.Ink.Save(PersistenceFormat.Base64InkSerializedFormat);
// Convert it to a String
base64ISF_string = utf8.GetString(base64ISF_bytes);
// Write the ISF containing node to the XML
xwriter.WriteElementString("Ink", base64ISF_string);
// Write the text data from the form
// Note that the names are stored as XML fields, rather
// than custom properties, so that these properties can
// be most easily accessible if the XML is saved in a database.
xwriter.WriteElementString("FirstName",FirstNameBox.Text);
xwriter.WriteElementString("LastName",LastNameBox.Text);
儲存至 HTML 檔案
SaveHTML 方法會使用 Strokes 集合的周框方塊來測試簽章是否存在。 如果簽章存在,則會使用筆跡物件的 Save 方法轉換成強化 GIF 格式,並寫入檔案。 GIF 接著會在 HTML 檔案中參考。
if (ic.Ink.Strokes.GetBoundingBox().IsEmpty)
{
MessageBox.Show("Unable to save empty ink in HTML persistence format.");
}
else
{
FileStream gifFile;
byte[] fortifiedGif = null;
...
// Create a directory to store the fortified GIF which also contains ISF
// and open the file for writing
Directory.CreateDirectory(nameBase + "_files");
using (FileStream gifFile = File.OpenWrite(nameBase + "_files\\signature.gif"))
{
// Generate the fortified GIF represenation of the ink
fortifiedGif = ic.Ink.Save(PersistenceFormat.Gif);
// Write and close the gif file
gifFile.Write(fortifiedGif, 0, fortifiedGif.Length);
}
載入檔案
方法 OpenMenu_Click
會處理 [開啟] 對話方塊、開啟檔案,並呼叫對應至使用者選擇的載入方法。
載入 ISF 檔案
方法 LoadISF
會讀取先前建立的檔案,並使用 Ink 物件的Load方法將 Byte 陣列轉換成筆跡。 已暫時停用筆跡收集器,以將 Ink 物件指派給它。 然後,方法 LoadISF
會檢查 Ink 物件的 ExtendedProperties 屬性中是否有第一個和姓氏字串。
Ink loadedInk = new Ink();
byte[] isfBytes = new byte[s.Length];
// read in the ISF
s.Read(isfBytes, 0, (int) s.Length);
// load the ink into a new ink object
// After an ink object has been "dirtied" it can never load ink again
loadedInk.Load(isfBytes);
// temporarily disable the ink collector and swap ink objects
ic.Enabled = false;
ic.Ink = loadedInk;
ic.Enabled = true;
// Repaint the inkable region
Signature.Invalidate();
ExtendedProperties inkProperties = ic.Ink.ExtendedProperties;
// Get the raw data out of this stroke's extended
// properties list, using the previously defined
// Guid as a key to the extended property.
// Since the save method stored the first and last
// name information as extended properties, this
// information can be remove now that the load is complete.
if (inkProperties.DoesPropertyExist(FirstName))
{
FirstNameBox.Text = (String) inkProperties[FirstName].Data;
inkProperties.Remove(FirstName);
}
else
{
FirstNameBox.Text = String.Empty;
}
if (inkProperties.DoesPropertyExist(LastName))
{
LastNameBox.Text = (String) inkProperties[LastName].Data;
inkProperties.Remove(LastName);
}
else
{
LastNameBox.Text = String.Empty;
}
載入 XML 檔案
方法 LoadXML
會載入先前建立的 XML 檔案、從 Ink 節點擷取資料,並使用 Ink 物件的Load方法,將節點中的資料轉換成筆跡。
InkCollector會暫時停用,以將 Ink 物件指派給它。 簽章方塊會失效,而且會從 XML 檔擷取名字和姓氏資訊。
// This object encodes our byte data to a UTF8 string
UTF8Encoding utf8 = new UTF8Encoding();
XmlDocument xd = new XmlDocument();
XmlNodeList nodes;
Ink loadedInk = new Ink();
// Load the XML data into a DOM
xd.Load(s);
// Get the data in the ink node
nodes = xd.GetElementsByTagName("Ink");
// load the ink into a new ink object
// After an ink object has been "dirtied" it can never load ink again
if (0 != nodes.Count)
loadedInk.Load(utf8.GetBytes(nodes[0].InnerXml));
// temporarily disable the ink collector and swap ink objects
ic.Enabled = false;
ic.Ink = loadedInk;
ic.Enabled = true;
// Repaint the inkable region
Signature.Invalidate();
// Get the data in the FirstName node
nodes = xd.GetElementsByTagName("FirstName");
if (0 != nodes.Count)
{
FirstNameBox.Text = nodes[0].InnerXml;
}
else
{
FirstNameBox.Text = String.Empty;
}
// Get the data in the LastName node
nodes = xd.GetElementsByTagName("LastName");
if (0 != nodes.Count)
{
LastNameBox.Text = nodes[0].InnerXml;
}
else
{
LastNameBox.Text = String.Empty;
}
關閉表單
表單的 Dispose 方法會處置 InkCollector 物件。