Condividi tramite


Esempio di serializzazione dell'inchiostro digitale

In questo esempio viene illustrato come serializzare e deserializzare l'inchiostro in vari formati. L'applicazione rappresenta un modulo con campi per l'immissione del nome, del cognome e della firma. L'utente può salvare questi dati come Pure Ink Serialized Format (ISF), Extensible Markup Language (XML) utilizzando l'ISF codificato in Base64, o come HTML, che fa riferimento all'inchiostro in un'immagine GIF (Graphics Interchange Format) codificata in Base64. L'applicazione consente inoltre all'utente di aprire i file salvati come formati XML e ISF. Il formato ISF usa proprietà estese per archiviare il nome e il cognome, mentre i formati XML e HTML archiviano queste informazioni negli attributi personalizzati.

Questo esempio non supporta il caricamento dal formato HTML, perché HTML non è adatto per l'archiviazione di dati strutturati. Poiché i dati sono separati in nome, firma e così via, è necessario un formato che mantiene questa separazione, ad esempio XML o un altro tipo di formato di database.

HTML è molto utile in un ambiente in cui la formattazione è importante, ad esempio in un documento di elaborazione delle parole. Il codice HTML salvato da questo esempio usa GIF fortificate. Queste GIF includono ISF incorporati, il che mantiene la massima fedeltà dell'inchiostro. Un'applicazione di elaborazione testi può salvare un documento contenente più tipi di dati, come immagini, tabelle, testo formattato e inchiostro salvati in un formato HTML. Questo codice HTML verrebbe visualizzato nei browser che non riconoscono l'inchiostro digitale. Tuttavia, quando viene caricato all'interno di un'applicazione abilitata alla penna, la massima fedeltà dell'inchiostro originale è disponibile e può essere reso, modificato o utilizzato per il riconoscimento.

In questo esempio vengono usate le funzionalità seguenti:

Raccolta dell'inchiostro

Per prima cosa, fare riferimento all'API Tablet PC, installata con Windows Vista e Windows XP Tablet PC Edition Software Development Kit (SDK).

using Microsoft.Ink;

Il costruttore crea e abilita un InkCollector, ic, per il modulo.

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

Salvataggio di un file

Il metodo SaveAsMenu_Click gestisce la finestra di dialogo Salva con nome, crea un flusso di file in cui salvare i dati dell'inchiostro e chiama il metodo salva corrispondente alla scelta dell'utente.

Salvataggio in un file ISF

Nel metodo SaveISF, i valori del nome e del cognome vengono aggiunti alla proprietà ExtendedProperties dell'oggetto InkCollector nella proprietà Ink, prima che l'inchiostro venga serializzato e scritto nel file. Dopo che l'inchiostro è stato serializzato, i valori del nome e del cognome vengono rimossi dalla proprietà ExtendedProperties dell'oggetto Inchiostro.

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

Salvataggio in un file XML

Nel metodo SaveXML viene utilizzato un oggetto XmlTextWriter per creare e scrivere in un documento XML. Utilizzando il metodo Save dell'oggetto Ink, l'input penna viene prima convertito in una matrice di byte in formato Ink Serialized base64, e quindi la matrice di byte viene convertita in una stringa da scrivere nel file XML. Anche i dati di testo del modulo vengono scritti nel file 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);

Salvataggio in un file HTML

Il metodo SaveHTML utilizza il rettangolo di delimitazione dell'insieme Strokes per verificare la presenza di una firma. Se la firma esiste, viene convertita nel formato GIF fortificato usando il metodo Save dell'oggetto inchiostro e scritta in un file. Viene quindi fatto riferimento alla GIF nel file 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);
    }

Caricamento di un file

Il metodo OpenMenu_Click gestisce la finestra di dialogo Apri, apre il file e chiama il metodo di caricamento che corrisponde alla scelta dell'utente.

Caricamento di un file ISF

Il metodo LoadISF legge il file creato in precedenza e converte la matrice Byte in input penna con il metodo Load dell'oggetto input penna. Il collettore di inchiostro è temporaneamente disabilitato per assegnargli l'oggetto Ink. Il metodo LoadISF controlla quindi la proprietà ExtendedProperties dell'oggetto Ink per le stringhe di nome e cognome.

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

Caricamento di un file XML

Il metodo LoadXML carica un file XML creato in precedenza, recupera i dati dal nodo Ink e converte i dati nel nodo in inchiostro usando il metodo Load dell'oggetto Ink. Il InkCollector è temporaneamente disabilitato per assegnare l'oggetto Ink. La casella della firma viene invalidata e le informazioni sul nome e il cognome vengono recuperate dal 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;
}

Chiusura del modulo

Il metodo Dispose del formulario elimina l'oggetto InkCollector.