Share via


Archiviare e recuperare dati dei tratti di Windows Ink

Le app di Windows che supportano Windows Ink possono serializzare e deserializzare i tratti input penna in un file ISF (Ink Serialized Format). Il file ISF è un'immagine GIF con metadati aggiuntivi relativi a tutte le proprietà e i comportamenti del tratto input penna. Le app non abilitate per l'input penna possono visualizzare l'immagine GIF statica, inclusa la trasparenza dello sfondo del canale alfa.

Nota

ISF è la rappresentazione persistente più compatta dell'input penna. Questo formato può essere incorporato in un formato di documento binario, ad esempio un file GIF, o posizionato direttamente negli Appunti.

La specifica ISF (Ink Serialized Format) può essere scaricata dall'Area download Microsoft.

API importanti: InkCanvas, Windows.UI.Input.Inking

Salvare i tratti input penna in un file

In questo esempio viene illustrato come salvare i tratti input penna disegnati in un controllo InkCanvas.

Scaricare questo esempio da Salvare e caricare tratti input penna da un file ISF (Ink Serialized Format)

  1. Innanzitutto, si imposta l'interfaccia utente.

    L'interfaccia utente include i pulsanti "Salva", "Carica" e "Cancella" e l'oggetto InkCanvas.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
            <TextBlock x:Name="Header" 
                       Text="Basic ink store sample" 
                       Style="{ThemeResource HeaderTextBlockStyle}" 
                       Margin="10,0,0,0" />
            <Button x:Name="btnSave" 
                    Content="Save" 
                    Margin="50,0,10,0"/>
            <Button x:Name="btnLoad" 
                    Content="Load" 
                    Margin="50,0,10,0"/>
            <Button x:Name="btnClear" 
                    Content="Clear" 
                    Margin="50,0,10,0"/>
        </StackPanel>
        <Grid Grid.Row="1">
            <InkCanvas x:Name="inkCanvas" />
        </Grid>
    </Grid>
  1. Ora si impostano alcuni comportamenti di input penna di base:

    InkPresenter è configurato per interpretare i dati di input sia dalla penna che dal mouse come tratti input penna (InputDeviceTypes) e vengono dichiarati i listener per gli eventi click sui pulsanti.

public MainPage()
    {
        this.InitializeComponent();

        // Set supported inking device types.
        inkCanvas.InkPresenter.InputDeviceTypes =
            Windows.UI.Core.CoreInputDeviceTypes.Mouse |
            Windows.UI.Core.CoreInputDeviceTypes.Pen;

        // Listen for button click to initiate save.
        btnSave.Click += btnSave_Click;
        // Listen for button click to initiate load.
        btnLoad.Click += btnLoad_Click;
        // Listen for button click to clear ink canvas.
        btnClear.Click += btnClear_Click;
    }
  1. Infine, l'input penna viene salvato nel gestore eventi click del pulsante Salva.

    Un oggetto FileSavePicker consente all'utente di selezionare sia il file che il percorso in cui vengono salvati i dati dell'input penna.

    Dopo aver selezionato un file, si apre un flusso IRandomAccessStream impostato su ReadWrite.

    Viene quindi invocato SaveAsync per serializzare i tratti input penna gestiti da InkStrokeContainer nel flusso.

// Save ink data to a file.
    private async void btnSave_Click(object sender, RoutedEventArgs e)
    {
        // Get all strokes on the InkCanvas.
        IReadOnlyList<InkStroke> currentStrokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();

        // Strokes present on ink canvas.
        if (currentStrokes.Count > 0)
        {
            // Let users choose their ink file using a file picker.
            // Initialize the picker.
            Windows.Storage.Pickers.FileSavePicker savePicker = 
                new Windows.Storage.Pickers.FileSavePicker();
            savePicker.SuggestedStartLocation = 
                Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary;
            savePicker.FileTypeChoices.Add(
                "GIF with embedded ISF", 
                new List<string>() { ".gif" });
            savePicker.DefaultFileExtension = ".gif";
            savePicker.SuggestedFileName = "InkSample";

            // Show the file picker.
            Windows.Storage.StorageFile file = 
                await savePicker.PickSaveFileAsync();
            // When chosen, picker returns a reference to the selected file.
            if (file != null)
            {
                // Prevent updates to the file until updates are 
                // finalized with call to CompleteUpdatesAsync.
                Windows.Storage.CachedFileManager.DeferUpdates(file);
                // Open a file stream for writing.
                IRandomAccessStream stream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
                // Write the ink strokes to the output stream.
                using (IOutputStream outputStream = stream.GetOutputStreamAt(0))
                {
                    await inkCanvas.InkPresenter.StrokeContainer.SaveAsync(outputStream);
                    await outputStream.FlushAsync();
                }
                stream.Dispose();

                // Finalize write so other apps can update file.
                Windows.Storage.Provider.FileUpdateStatus status =
                    await Windows.Storage.CachedFileManager.CompleteUpdatesAsync(file);

                if (status == Windows.Storage.Provider.FileUpdateStatus.Complete)
                {
                    // File saved.
                }
                else
                {
                    // File couldn't be saved.
                }
            }
            // User selects Cancel and picker returns null.
            else
            {
                // Operation cancelled.
            }
        }
    }

Nota

GIF è l'unico formato di file supportato per il salvataggio dei dati input penna. Tuttavia, il metodo LoadAsync (illustrato nella sezione successiva) supporta formati aggiuntivi per la compatibilità con le versioni precedenti.

Caricare tratti input penna da un file

In questo esempio viene illustrato come caricare i tratti input penna da un file ed eseguirne il rendering in un controllo InkCanvas.

Scaricare questo esempio da Salvare e caricare tratti input penna da un file ISF (Ink Serialized Format)

  1. Innanzitutto, si imposta l'interfaccia utente.

    L'interfaccia utente include i pulsanti "Salva", "Carica" e "Cancella" e l'oggetto InkCanvas.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
            <TextBlock x:Name="Header" 
                       Text="Basic ink store sample" 
                       Style="{ThemeResource HeaderTextBlockStyle}" 
                       Margin="10,0,0,0" />
            <Button x:Name="btnSave" 
                    Content="Save" 
                    Margin="50,0,10,0"/>
            <Button x:Name="btnLoad" 
                    Content="Load" 
                    Margin="50,0,10,0"/>
            <Button x:Name="btnClear" 
                    Content="Clear" 
                    Margin="50,0,10,0"/>
        </StackPanel>
        <Grid Grid.Row="1">
            <InkCanvas x:Name="inkCanvas" />
        </Grid>
    </Grid>
  1. Ora si impostano alcuni comportamenti di input penna di base:

    InkPresenter è configurato per interpretare i dati di input sia dalla penna che dal mouse come tratti input penna (InputDeviceTypes) e vengono dichiarati i listener per gli eventi click sui pulsanti.

public MainPage()
    {
        this.InitializeComponent();

        // Set supported inking device types.
        inkCanvas.InkPresenter.InputDeviceTypes =
            Windows.UI.Core.CoreInputDeviceTypes.Mouse |
            Windows.UI.Core.CoreInputDeviceTypes.Pen;

        // Listen for button click to initiate save.
        btnSave.Click += btnSave_Click;
        // Listen for button click to initiate load.
        btnLoad.Click += btnLoad_Click;
        // Listen for button click to clear ink canvas.
        btnClear.Click += btnClear_Click;
    }
  1. Infine, si carica l'input penna nel gestore eventi click del pulsante Carica.

    Un oggetto FileOpenPicker consente all'utente di selezionare sia il file che il percorso da cui recuperare i dati dell'input penna salvati.

    Dopo aver selezionato un file, si apre un flusso IRandomAccessStream impostato su Read.

    Viene quindi chiamato LoadAsync per leggere, deserializzare e caricare i tratti input penna salvati in InkStrokeContainer. Il caricamento dei tratti in InkStrokeContainer fa sì che InkPresenter ne esegua immediatamente il rendering in InkCanvas.

    Nota

    Tutti i tratti esistenti in InkStrokeContainer vengono cancellati prima del caricamento di nuovi tratti.

// Load ink data from a file.
private async void btnLoad_Click(object sender, RoutedEventArgs e)
{
    // Let users choose their ink file using a file picker.
    // Initialize the picker.
    Windows.Storage.Pickers.FileOpenPicker openPicker =
        new Windows.Storage.Pickers.FileOpenPicker();
    openPicker.SuggestedStartLocation =
        Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary;
    openPicker.FileTypeFilter.Add(".gif");
    // Show the file picker.
    Windows.Storage.StorageFile file = await openPicker.PickSingleFileAsync();
    // User selects a file and picker returns a reference to the selected file.
    if (file != null)
    {
        // Open a file stream for reading.
        IRandomAccessStream stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
        // Read from file.
        using (var inputStream = stream.GetInputStreamAt(0))
        {
            await inkCanvas.InkPresenter.StrokeContainer.LoadAsync(inputStream);
        }
        stream.Dispose();
    }
    // User selects Cancel and picker returns null.
    else
    {
        // Operation cancelled.
    }
}

Nota

GIF è l'unico formato di file supportato per il salvataggio dei dati input penna. Tuttavia, il metodo LoadAsync supporta i formati seguenti per la compatibilità con le versioni precedenti.

Formato Descrizione
InkSerializedFormat Specifica l'input penna persistente tramite ISF. Questa è la rappresentazione persistente più compatta dell'input penna. Questo formato può essere incorporato all'interno di un formato di documento binario o posizionato direttamente negli Appunti.
Base64InkSerializedFormat Specifica l'input penna persistente codificando l'ISF come flusso base64. Questo formato viene fornito in modo che l'input penna possa essere codificato direttamente in un file XML o HTML.
GIF Specifica l'input penna persistente usando un file GIF che contiene ISF come metadati incorporati all'interno del file. Ciò consente di visualizzare l'input penna nelle applicazioni non abilitate per l'input penna e mantenere la massima fedeltà dell'input penna quando torna a un'applicazione abilitata per l'input penna. Questo formato è ideale quando si trasporta contenuto input penna all'interno di un file HTML e per renderlo utilizzabile dalle applicazioni input penna e non input penna.
Base64Gif Specifica l'input penna persistente usando una GIF fortificata con codifica Base64. Questo formato viene fornito quando l'input penna deve essere codificato direttamente in un file XML o HTML per una conversione successiva in un'immagine. Un possibile utilizzo di questo tipo è in un formato XML generato per contenere tutte le informazioni sull'input penna e usato per generare codice HTML tramite le trasformazioni XSLT (Extensible Stylesheet Language Transformations).

Copiare e incollare tratti input penna con gli Appunti

In questo esempio viene illustrato come usare gli Appunti per trasferire tratti input penna tra app.

Per supportare la funzionalità degli Appunti, i comandi integrati taglia e copia di InkStrokeContainer richiedono la selezione di uno o più tratti input penna.

Per questo esempio viene abilitata la selezione del tratto nel momento in cui l'input viene modificato con un pulsante della penna (o pulsante destro del mouse). Per un esempio completo di come implementare la selezione del tratto, vedere Input pass-through per l'elaborazione avanzata nelle Interazioni con penna e stilo.

Scaricare questo esempio da Salvare e caricare tratti input penna dagli Appunti

  1. Innanzitutto, si imposta l'interfaccia utente.

    L'interfaccia utente include i pulsanti "Taglia", "Copia", "Incolla" e "Cancella", insieme a un oggetto InkCanvas e a un'area di disegno di selezione.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Row="0">
            <TextBlock x:Name="tbHeader" 
                       Text="Basic ink store sample" 
                       Style="{ThemeResource HeaderTextBlockStyle}" 
                       Margin="10,0,0,0" />
            <Button x:Name="btnCut" 
                    Content="Cut" 
                    Margin="20,0,10,0"/>
            <Button x:Name="btnCopy" 
                    Content="Copy" 
                    Margin="20,0,10,0"/>
            <Button x:Name="btnPaste" 
                    Content="Paste" 
                    Margin="20,0,10,0"/>
            <Button x:Name="btnClear" 
                    Content="Clear" 
                    Margin="20,0,10,0"/>
        </StackPanel>
        <Grid x:Name="gridCanvas" Grid.Row="1">
            <!-- Canvas for displaying selection UI. -->
            <Canvas x:Name="selectionCanvas"/>
            <!-- Inking area -->
            <InkCanvas x:Name="inkCanvas"/>
        </Grid>
    </Grid>
  1. Ora si impostano alcuni comportamenti di input penna di base:

    InkPresenter viene configurato per interpretare i dati di input da penna e mouse come tratti input penna (InputDeviceTypes). Qui vengono dichiarati i listener per gli eventi click sui pulsanti, nonché gli eventi di puntatore e tratto per la funzionalità di selezione.

    Per un esempio completo di come implementare la selezione del tratto, vedere Input pass-through per l'elaborazione avanzata nelle Interazioni con penna e stilo.

public MainPage()
    {
        this.InitializeComponent();

        // Set supported inking device types.
        inkCanvas.InkPresenter.InputDeviceTypes =
            Windows.UI.Core.CoreInputDeviceTypes.Mouse |
            Windows.UI.Core.CoreInputDeviceTypes.Pen;

        // Listen for button click to cut ink strokes.
        btnCut.Click += btnCut_Click;
        // Listen for button click to copy ink strokes.
        btnCopy.Click += btnCopy_Click;
        // Listen for button click to paste ink strokes.
        btnPaste.Click += btnPaste_Click;
        // Listen for button click to clear ink canvas.
        btnClear.Click += btnClear_Click;

        // By default, the InkPresenter processes input modified by 
        // a secondary affordance (pen barrel button, right mouse 
        // button, or similar) as ink.
        // To pass through modified input to the app for custom processing 
        // on the app UI thread instead of the background ink thread, set 
        // InputProcessingConfiguration.RightDragAction to LeaveUnprocessed.
        inkCanvas.InkPresenter.InputProcessingConfiguration.RightDragAction =
            InkInputRightDragAction.LeaveUnprocessed;

        // Listen for unprocessed pointer events from modified input.
        // The input is used to provide selection functionality.
        inkCanvas.InkPresenter.UnprocessedInput.PointerPressed +=
            UnprocessedInput_PointerPressed;
        inkCanvas.InkPresenter.UnprocessedInput.PointerMoved +=
            UnprocessedInput_PointerMoved;
        inkCanvas.InkPresenter.UnprocessedInput.PointerReleased +=
            UnprocessedInput_PointerReleased;

        // Listen for new ink or erase strokes to clean up selection UI.
        inkCanvas.InkPresenter.StrokeInput.StrokeStarted +=
            StrokeInput_StrokeStarted;
        inkCanvas.InkPresenter.StrokesErased +=
            InkPresenter_StrokesErased;
    }
  1. Infine, dopo aver aggiunto il supporto per la selezione dei tratti, si implementa la funzionalità Appunti nei gestori eventi click dei pulsanti Taglia, Copia e Incolla.

    Per l'operazione Taglia, chiamiamo prima CopySelectedToClipboard sull'oggetto InkStrokeContainer di InkPresenter.

    Si chiama quindi DeleteSelected per rimuovere i tratti dall'area di disegno input penna.

    Infine, si eliminano tutti i tratti di selezione dall'area di disegno di selezione.

private void btnCut_Click(object sender, RoutedEventArgs e)
    {
        inkCanvas.InkPresenter.StrokeContainer.CopySelectedToClipboard();
        inkCanvas.InkPresenter.StrokeContainer.DeleteSelected();
        ClearSelection();
    }
// Clean up selection UI.
    private void ClearSelection()
    {
        var strokes = inkCanvas.InkPresenter.StrokeContainer.GetStrokes();
        foreach (var stroke in strokes)
        {
            stroke.Selected = false;
        }
        ClearDrawnBoundingRect();
    }

    private void ClearDrawnBoundingRect()
    {
        if (selectionCanvas.Children.Any())
        {
            selectionCanvas.Children.Clear();
            boundingRect = Rect.Empty;
        }
    }

Per l'operazione Copia, chiamiamo semplicemente CopySelectedToClipboard sull'oggetto InkStrokeContainer di InkPresenter.

private void btnCopy_Click(object sender, RoutedEventArgs e)
    {
        inkCanvas.InkPresenter.StrokeContainer.CopySelectedToClipboard();
    }

Per l'operazione Incolla, chiamiamo CanPasteFromClipboard per assicurarsi che il contenuto negli Appunti possa essere incollato nell'area di disegno input penna.

Se la verifica è positiva, chiamiamo PasteFromClipboard per inserire i tratti input penna contenuti negli Appunti nell'oggetto InkStrokeContainer di InkPresenter, che quindi esegue il rendering dei tratti nell'area di disegno input penna.

private void btnPaste_Click(object sender, RoutedEventArgs e)
    {
        if (inkCanvas.InkPresenter.StrokeContainer.CanPasteFromClipboard())
        {
            inkCanvas.InkPresenter.StrokeContainer.PasteFromClipboard(
                new Point(0, 0));
        }
        else
        {
            // Cannot paste from clipboard.
        }
    }

Esempi di argomento

Altri esempi