共用方式為


筆跡序列化範例

此範例示範如何以各種格式序列化和取消序列化筆跡。 應用程式代表表單,其中包含用於輸入名字、姓氏和簽章的欄位。 使用者可能會將此資料儲存為純筆跡序列化格式, (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 物件。