Speichern und Abrufen der Daten zu Windows Ink-Strichen
Windows-Apps, die Windows Ink unterstützen, können Freihandstriche in eine ISF-Datei (Ink Serialized Format) serialisieren und deserialisieren. Die ISF-Datei ist ein GIF-Bild mit zusätzlichen Metadaten für alle Freihandstricheigenschaften und -verhalten. Apps, die nicht freihandfähig sind, können das statische GIF-Bild anzeigen, einschließlich Alphakanal-Hintergrundtransparenz.
Hinweis
ISF ist die kompakteste persistente Freihanddarstellung. Sie kann in ein binärdokumentformat eingebettet werden, z. B. eine GIF-Datei oder direkt in der Zwischenablage.
Die Spezifikation für serialisiertes Freihandformat (Ink Serialized Format, ISF) kann aus dem Microsoft Download Center heruntergeladen werden.
Wichtige APIs: InkCanvas, Windows.UI.Input.Inking
Speichern von Freihandstrichen in einer Datei
Hier wird veranschaulicht, wie Freihandstriche gespeichert werden, die auf einem InkCanvas-Steuerelement gezeichnet werden.
Laden Sie dieses Beispiel aus einer ISF-Datei (Ink Serialized Format) aus "Speichern und Laden von Freihandstrichen" herunter.
Zunächst richten wir die Benutzeroberfläche ein.
Die Benutzeroberfläche enthält die Schaltflächen "Speichern", "Laden" und "Löschen" und "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>
Dann legen wir einige grundlegende Freihandeingabeverhalten fest.
Der InkPresenter ist so konfiguriert, dass Eingabedaten von Stift und Maus als Freihandstriche (InputDeviceTypes) interpretiert werden, und Listener für die Klickereignisse auf den Schaltflächen werden deklariert.
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;
}
Schließlich speichern wir die Freihandeingabe im Click-Ereignishandler der Schaltfläche "Speichern ".
Ein FileSavePicker ermöglicht es dem Benutzer, sowohl die Datei als auch den Speicherort auszuwählen, an dem die Freihanddaten gespeichert werden.
Sobald eine Datei ausgewählt ist, öffnen wir einen IRandomAccessStream-Datenstrom, der auf ReadWrite festgelegt ist.
Anschließend rufen wir SaveAsync auf, um die vom InkStrokeContainer verwalteten Freihandstriche in den Datenstrom zu serialisieren.
// 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.
}
}
}
Hinweis
GIF ist das einzige Dateiformat, das zum Speichern von Freihanddaten unterstützt wird. Die LoadAsync-Methode (im nächsten Abschnitt veranschaulicht) unterstützt jedoch zusätzliche Formate für die Abwärtskompatibilität.
Laden von Freihandstrichen aus einer Datei
Hier zeigen wir, wie Freihandstriche aus einer Datei geladen und in einem InkCanvas-Steuerelement gerendert werden.
Laden Sie dieses Beispiel aus einer ISF-Datei (Ink Serialized Format) aus "Speichern und Laden von Freihandstrichen" herunter.
Zunächst richten wir die Benutzeroberfläche ein.
Die Benutzeroberfläche enthält die Schaltflächen "Speichern", "Laden" und "Löschen" und "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>
Dann legen wir einige grundlegende Freihandeingabeverhalten fest.
Der InkPresenter ist so konfiguriert, dass Eingabedaten von Stift und Maus als Freihandstriche (InputDeviceTypes) interpretiert werden, und Listener für die Klickereignisse auf den Schaltflächen werden deklariert.
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;
}
Schließlich laden wir die Freihandeingabe im Click-Ereignishandler der Schaltfläche "Laden ".
Ein FileOpenPicker ermöglicht es dem Benutzer, sowohl die Datei als auch den Speicherort auszuwählen, an dem die gespeicherten Freihanddaten abgerufen werden sollen.
Sobald eine Datei ausgewählt wurde, öffnen wir einen IRandomAccessStream-Datenstrom, der auf "Lesen" festgelegt ist.
Anschließend rufen wir LoadAsync auf, um die gespeicherten Freihandstriche in den InkStrokeContainer zu lesen, zu de serialisieren und zu laden. Durch das Laden der Striche in den InkStrokeContainer wird der InkPresenter sofort in den InkCanvas gerendert.
Hinweis
Alle vorhandenen Striche im InkStrokeContainer werden gelöscht, bevor neue Striche geladen werden.
// 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.
}
}
Hinweis
GIF ist das einzige Dateiformat, das zum Speichern von Freihanddaten unterstützt wird. Die LoadAsync-Methode unterstützt jedoch die folgenden Formate für die Abwärtskompatibilität.
Format | Beschreibung |
---|---|
InkSerializedFormat | Gibt Freihandeingaben an, die mithilfe von ISF beibehalten werden. Dies ist die kompakteste persistente Darstellung von Freihand. Sie kann in ein binäres Dokumentformat eingebettet oder direkt in die Zwischenablage eingefügt werden. |
Base64InkSerializedFormat | Gibt Freihandeingaben an, die beibehalten werden, indem der ISF als Base64-Datenstrom codiert wird. Dieses Format wird bereitgestellt, sodass Freihandeingaben direkt in einer XML- oder HTML-Datei codiert werden können. |
GIF | Gibt Freihandeingaben an, die mithilfe einer GIF-Datei beibehalten werden, die ISF als in die Datei eingebettete Metadaten enthält. Dadurch können Freihandeingaben in Anwendungen angezeigt werden, die nicht freihandfähig sind, und die volle Freihandtreue beibehalten, wenn sie zu einer freihandfähigen Anwendung zurückkehrt. Dieses Format eignet sich ideal beim Transport von Freihandinhalten in einer HTML-Datei und zur Verwendung durch Freihand- und Freihandanwendungen. |
Base64Gif | Gibt Freihandeingaben an, die mithilfe einer base64-codierten, befestigten GIF-Datei beibehalten werden. Dieses Format wird bereitgestellt, wenn Freihandeingaben direkt in einer XML- oder HTML-Datei codiert werden sollen, um später in ein Bild zu konvertieren. Dies ist in einem XML-Format möglich, das generiert wird, um alle Freihandinformationen zu enthalten und zum Generieren von HTML über XSLT (Extensible Stylesheet Language Transformations) zu verwenden. |
Kopieren und Einfügen von Freihandstrichen mit der Zwischenablage
Hier wird veranschaulicht, wie die Zwischenablage zum Übertragen von Freihandstrichen zwischen Apps verwendet wird.
Zur Unterstützung der Zwischenablagefunktion müssen für den integrierten InkStrokeContainer-Ausschneiden und Kopieren mindestens ein Freihandstrich ausgewählt werden.
In diesem Beispiel aktivieren wir die Strichauswahl, wenn die Eingabe mit einer Zeichenstift-Drucktaste (oder einer rechten Maustaste) geändert wird. Ein vollständiges Beispiel für die Implementierung der Strichauswahl finden Sie unter Pass-Through-Eingabe für die erweiterte Verarbeitung in Zeichen- und Eingabestiftinteraktionen.
Laden Sie dieses Beispiel aus der Zwischenablage zum Speichern und Laden von Freihandstrichen aus der Zwischenablage herunter.
Zunächst richten wir die Benutzeroberfläche ein.
Die Benutzeroberfläche enthält die Schaltflächen "Ausschneiden", "Kopieren", "Einfügen" und "Löschen", zusammen mit dem InkCanvas und einem Auswahlzeichenbereich.
<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>
Dann legen wir einige grundlegende Freihandeingabeverhalten fest.
Der InkPresenter ist so konfiguriert, dass Eingabedaten von Stift und Maus als Freihandstriche (InputDeviceTypes) interpretiert werden. Listener für die Klickereignisse auf den Schaltflächen sowie Zeiger- und Strichereignisse für die Auswahlfunktionalität werden hier ebenfalls deklariert.
Ein vollständiges Beispiel für die Implementierung der Strichauswahl finden Sie unter Pass-Through-Eingabe für die erweiterte Verarbeitung in Zeichen- und Eingabestiftinteraktionen.
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;
}
Nach dem Hinzufügen der Strichauswahlunterstützung implementieren wir die Zwischenablagefunktionalität in den Klickereignishandlern der Schaltflächen "Ausschneiden", "Kopieren" und "Einfügen" .
Zum Ausschneiden rufen wir zuerst CopySelectedToClipboard im InkStrokeContainer des InkPresenter auf.
Anschließend rufen wir DeleteSelected auf, um die Striche aus dem Freihandzeichenbereich zu entfernen.
Schließlich löschen wir alle Auswahlstriche aus dem Auswahlbereich.
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;
}
}
Zum Kopieren rufen wir einfach CopySelectedToClipboard im InkStrokeContainer des InkPresenter auf.
private void btnCopy_Click(object sender, RoutedEventArgs e)
{
inkCanvas.InkPresenter.StrokeContainer.CopySelectedToClipboard();
}
Zum Einfügen rufen wir CanPasteFromClipboard auf, um sicherzustellen, dass der Inhalt in der Zwischenablage in den Freihandbereich eingefügt werden kann.
In diesem Fall rufen wir PasteFromClipboard auf, um die Freihandstriche der Zwischenablage in den InkStrokeContainer des InkPresenter einzufügen, wodurch die Striche dann im Freihandzeichenbereich gerendert werden.
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.
}
}
Verwandte Artikel
Themenbeispiele
- Speichern und Laden von Freihandstrichen aus einer ISF-Datei (Ink Serialized Format)
- Speichern und Laden von Freihandstrichen aus der Zwischenablage
Weitere Beispiele
Windows developer