Condividi tramite


Archiviare e recuperare i dati del tratto 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 per tutte le proprietà e i comportamenti del tratto di inchiostro. Le applicazioni non abilitate per l'uso di penna possono visualizzare l'immagine GIF statica, inclusa la trasparenza dello sfondo del canale alfa.

Annotazioni

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

Le specifiche ISF (Formato Ink Serialized) possono essere scaricate dall'Area download Microsoft.

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

Salvare i tratti di inchiostro in un file

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

Scarica questo esempio da Salvataggio e caricamento di tratti di inchiostro da un file nel formato ISF (Ink Serialized Format)

  1. Prima di tutto, impostiamo l'interfaccia utente.

    L'interfaccia utente include i pulsanti "Salva", "Carica" e "Cancella" e 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. Impostiamo quindi alcuni comportamenti di input per penna di base.

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

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, salviamo l'inchiostro nel gestore degli eventi di clic del pulsante Salva.

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

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

    Chiamiamo quindi SaveAsync per serializzare i tratti d'inchiostro 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.
            }
        }
    }

Annotazioni

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

Caricare tratti di inchiostro da un file

Qui viene illustrato come caricare i tratti di penna da un file ed eseguirne il rendering in un controllo InkCanvas.

Scarica questo esempio da Carica e salva tratti di inchiostro in un file ISF (Ink Serialized Format)

  1. Prima di tutto, impostiamo l'interfaccia utente.

    L'interfaccia utente include i pulsanti "Salva", "Carica" e "Cancella" e 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. Impostiamo quindi alcuni comportamenti di input dell'inchiostro di base.

    InkPresenter è configurato per interpretare i dati di input sia dalla penna che dal mouse come tratti di inchiostro (InputDeviceTypes) e sono dichiarati i listener per gli eventi di clic 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, carichiamo l'inchiostro nel gestore eventi clic del pulsante Carica.

    Un FileOpenPicker consente all'utente di selezionare sia il file che la posizione da cui recuperare i dati dell'inchiostro salvati.

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

    Chiamiamo quindi LoadAsync per leggere, de-serializzare, e caricare i tratti di inchiostro salvati in InkStrokeContainer. Il caricamento dei tratti in InkStrokeContainer fa sì che InkPresenter li renda immediatamente su InkCanvas.

    Annotazioni

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

Annotazioni

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

Formato Description
InkSerializedFormat Specifica l'inchiostro che viene mantenuto tramite ISF. Si tratta della rappresentazione persistente più compatta dell'inchiostro digitale. Può essere incorporato all'interno di un formato di documento binario o posizionato direttamente sul clipboard.
Base64InkSerializedFormat Specifica l'inchiostro che viene mantenuto codificando l'ISF come flusso base64. Questo formato viene fornito in modo che l'inchiostro possa essere codificato direttamente in un file XML o HTML.
Gif Specifica l'inchiostro persistente utilizzando un file GIF che contiene ISF come metadata incorporati nel file GIF. Ciò consente di visualizzare l'inchiostro nelle applicazioni non supportate per l'inchiostro e mantenere la fedeltà completa dell'inchiostro quando torna a un'applicazione supportata per l'inchiostro. Questo formato è ideale per trasportare contenuto di inchiostro all'interno di un file HTML e renderlo utilizzabile dalle applicazioni che utilizzano inchiostro e da quelle che non lo fanno.
Base64Gif Specifica l'inchiostro memorizzato utilizzando una GIF codificata in Base64. Questo formato viene fornito quando l'inchiostro deve essere codificato direttamente in un file XML o HTML per una successiva conversione in immagine. Un possibile utilizzo di questo tipo è in un formato XML generato allo scopo di contenere tutte le informazioni sull'inchiostro e usato per generare codice HTML tramite le trasformazioni XSLT (Extensible Stylesheet Language Transformations).

Copiare e incollare tratti di inchiostro utilizzando gli Appunti

Qui dimostriamo come usare gli Appunti per trasferire tratti di inchiostro tra app.

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

Per questo esempio, abilitiamo la selezione del tratto quando l'input viene modificato con il pulsante laterale della penna (o il 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.

Scarica questo esempio da Salva e carica tratti d'inchiostro dagli Appunti

  1. Prima di tutto, impostiamo l'interfaccia utente.

    L'interfaccia utente include i pulsanti "Taglia", "Copia", "Incolla" e "Cancella", insieme a 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. Verranno quindi impostati alcuni comportamenti di input stilo di base.

    InkPresenter è configurato per interpretare i dati di input sia dalla penna che dal mouse come tratti di inchiostro (InputDeviceTypes). I listener per gli eventi di click sui pulsanti, nonché gli eventi di puntatore e movimento per la funzionalità di selezione, vengono dichiarati qui.

    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, implementiamo la funzionalità degli appunti nei gestori degli eventi di click dei pulsanti Taglia, Copia e Incolla.

    Per il taglio, prima chiamiamo CopySelectedToClipboard sull'InkStrokeContainer dell'InkPresenter.

    Chiamiamo quindi DeleteSelected per rimuovere i tratti dall'area di disegno a inchiostro.

    Infine, eliminiamo 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 la copia, chiamiamo semplicemente CopySelectedToClipboard sull'InkStrokeContainer dell'InkPresenter.

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

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

In tal caso, chiamiamo PasteFromClipboard per inserire i tratti di inchiostro dagli Appunti nell'InkStrokeContainer dell'InkPresenter, che quindi esegue il rendering dei tratti sulla tela di disegno per l'inchiostro.

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 argomenti

Altri campioni