Partilhar via


Exemplo de serialização de tinta

Este exemplo demonstra como serializar e desserializar tinta em vários formatos. O aplicativo representa um formulário com campos para inserir nome, sobrenome e assinatura. O usuário pode salvar esses dados como ISF (formato serializado de tinta pura), XML (Extensible Markup Language) usando ISF codificado em base64 ou HTML, que faz referência à tinta em uma imagem GIF (Graphics Interchange Format) fortificada codificada em base64. O aplicativo também permite que o usuário abra arquivos que foram salvos como formatos XML e ISF. O formato ISF usa propriedades estendidas para armazenar o nome e o sobrenome, enquanto os formatos XML e HTML armazenam essas informações em atributos personalizados.

Este exemplo não suporta o carregamento a partir do formato HTML, porque o HTML não é adequado para armazenar dados estruturados. Como os dados são separados em nome, assinatura e assim por diante, é necessário um formato que preserve essa separação, como XML ou outro tipo de formato de banco de dados.

HTML é muito útil em um ambiente em que a formatação é importante, como em um documento de processamento de texto. O HTML salvo por este exemplo usa GIFs fortificados. Esses GIFs têm ISF embutido neles, o que preserva a fidelidade total da tinta. Um aplicativo de processamento de texto pode salvar um documento contendo vários tipos de dados, como imagens, tabelas, texto formatado e tinta persistente em um formato HTML. Esse HTML seria renderizado em navegadores que não reconhecem tinta. No entanto, quando carregada numa aplicação compatível com tinta, a fidelidade total da tinta original fica disponível e pode ser renderizada, editada ou usada para reconhecimento.

Os seguintes recursos são usados neste exemplo:

Recolha de tinta

Primeiro, consulte a API do Tablet PC, que é instalada com o Windows Vista e o Windows XP Tablet PC Edition Software Development Kit (SDK).

using Microsoft.Ink;

O construtor cria e habilita um InkCollector, ic, para o formulário.

ic = new InkCollector(Signature.Handle);
ic.Enabled = true;

Guardar um ficheiro

O método SaveAsMenu_Click manipula a caixa de diálogo Salvar como, cria um fluxo de arquivo no qual salvar os dados de tinta e chama o método de salvamento que corresponde à escolha do usuário.

Salvando em um arquivo ISF

No método SaveISF, os valores de nome e sobrenome são adicionados à propriedade ExtendedProperties da propriedade Ink do objeto InkCollector, antes que a tinta seja serializada e gravada no arquivo. Depois que a tinta é serializada, os valores de nome e sobrenome são removidos da propriedade ExtendedProperties do objeto 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);

Salvando em um arquivo XML

No método SaveXML, um objeto XmlTextWriter é usado para criar e gravar num documento XML. Usando o método InkSave do objeto, a tinta é primeiramente convertida numa matriz de bytes no formato Ink Serialized, codificada em base64, e, em seguida, essa matriz de bytes é transformada em string para ser gravada no ficheiro XML. Os dados de texto do formulário também são gravados no arquivo 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);

Salvando em um arquivo HTML

O método SaveHTML usa a caixa delimitadora da coleção Strokes para testar a presença de uma assinatura. Se a assinatura existir, ela será convertida para o formato GIF fortificado usando o método Save do objeto de tinta e gravada em um arquivo. O GIF é então referenciado no arquivo 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 representation of the ink
        fortifiedGif = ic.Ink.Save(PersistenceFormat.Gif);

        // Write and close the gif file
        gifFile.Write(fortifiedGif, 0, fortifiedGif.Length);
    }

Carregando um arquivo

O método OpenMenu_Click manipula a caixa de diálogo Abrir, abre o arquivo e chama o método de carregamento que corresponde à escolha do usuário.

Carregando um arquivo ISF

O método LoadISF lê o ficheiro criado anteriormente e converte a matriz de bytes em tinta com o método InkLoad do objeto. O coletor de tinta está temporariamente desativado para atribuir o objeto Ink a ele. Em seguida, o método LoadISF verifica a propriedade ExtendedProperties do objeto Ink para as cadeias de caracteres de nome e sobrenome.

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;
}

Carregando um arquivo XML

O método LoadXML carrega um ficheiro XML previamente criado, extrai dados do nó de Ink e transforma esses dados em tinta utilizando o método Load do objeto Ink. O InkCollector está temporariamente desativado para atribuir o objeto Ink a ele. A caixa de assinatura é invalidada e as informações de nome e sobrenome são recuperadas do documento 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;
}

Fechando o formulário

O método Dispose do formulário descarta o objeto InkCollector.