Пример сериализации рукописного ввода
В этом примере демонстрируется сериализация и десериализация рукописного ввода в различных форматах. Приложение представляет форму с полями для ввода имени, фамилии и подписи. Пользователь может сохранить эти данные в виде сериализованного формата рукописного ввода (ISF), языка расширяемой разметки (XML) с помощью ISF в кодировке Base64 или HTML, который ссылается на рукописный фрагмент в формате GIF в кодировке Base64. Приложение также позволяет пользователю открывать файлы, сохраненные в форматах XML и ISF. Формат ISF использует расширенные свойства для хранения имени и фамилии, в то время как форматы XML и HTML хранят эти сведения в пользовательских атрибутах.
Этот пример не поддерживает загрузку из формата HTML, так как HTML не подходит для хранения структурированных данных. Так как данные разделены на имя, сигнатуру и т. д., требуется формат, сохраняющий это разделение, например XML или другой формат базы данных.
HTML очень полезен в среде, в которой форматирование важно, например в текстовом документе. Html-код, сохраненный в этом примере, использует обогащенные GIF-файлы. Эти GIF-файлы имеют встроенные в них ISF, что сохраняет полную точность рукописного ввода. Текстовое приложение может сохранять документ, содержащий несколько типов данных, таких как изображения, таблицы, форматированный текст и рукописный ввод, сохраненный в формате HTML. Этот HTML-код будет отображаться в браузерах, которые не распознают рукописный ввод. Однако при загрузке в приложение с поддержкой рукописного ввода доступна полная точность исходного рукописного ввода и может быть отрисовано, отредактировано или использовано для распознавания.
В этом примере используются следующие функции:
Сбор рукописных данных
Сначала сослаться на API планшетного компьютера, который устанавливается вместе с пакетом SDK для Windows Vista и Windows XP Tablet PC Edition.
using Microsoft.Ink;
Конструктор создает и включает InkCollector для ic
формы.
ic = new InkCollector(Signature.Handle);
ic.Enabled = true;
Сохранение файла
Метод SaveAsMenu_Click
обрабатывает диалоговое окно Сохранить как, создает файловый поток, в котором сохраняются данные рукописного ввода, и вызывает метод сохранения, соответствующий выбору пользователя.
Сохранение в ISF-файл
В методе SaveISF
значения имени и фамилии добавляются в свойство ExtendedProperties свойства InkCollector InkCollector перед сериализацией рукописного ввода и записью в файл. После сериализации рукописного ввода значения имени и фамилии удаляются из свойства ExtendedProperties объекта Ink .
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-документ. С помощью метода Save объекта Ink рукописный ввод сначала преобразуется в массив байтов в кодировке Base64 в формате Ink Serialized Format, а затем массив байтов преобразуется в строку для записи в 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 для проверки наличия сигнатуры. Если сигнатура существует, она преобразуется в формат GIF с помощью метода Save объекта рукописного ввода и записывается в файл. Затем ссылка на 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
считывает ранее созданный файл и преобразует массив Byte в рукописный ввод с помощью метода Load объекта Ink. Сборщик рукописного ввода временно отключен, чтобы назначить ему объект Ink. Затем LoadISF
метод проверяет свойство ExtendedProperties объекта Ink на наличие строк имени и фамилии.
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 и преобразует данные на узле в рукописный ввод с помощью метода Load объекта Ink.
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 .