Поделиться через


Пример сериализации рукописного ввода

В этом примере демонстрируется сериализация и десериализация рукописного ввода в различных форматах. Приложение представляет форму с полями для ввода имени, фамилии и подписи. Пользователь может сохранить эти данные в виде сериализованного формата рукописного ввода (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 .