儲存和擷取 Windows Ink 筆劃資料 \(部分機器翻譯\)
支援 Windows Ink 的 Windows 應用程式可以將筆跡筆畫序列化和反序列化為 Ink 序列化格式 (ISF) 檔案。 ISF 檔案是 GIF 影像,其中包含所有筆墨筆劃屬性和行為的其他元資料。 不支援筆跡的應用程式可以查看靜態 GIF 影像,包括 Alpha 通道背景透明度。+
重要 API: InkCanvas、Windows.UI.Input.Inking
將筆跡筆劃儲存至檔案
在這裡,我們將示範如何儲存 InkCanvas 控制項上繪製的筆墨筆劃。
從筆跡序列化格式 (ISF) 檔案儲存和載入筆跡筆畫下載此範例
首先,我們會設定 UI。
UI 包含儲存、載入和清除按鈕以及 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>
然後,我們會設定一些基本的筆跡輸入行為。
InkPresenter 配置為將來自筆和滑鼠的輸入資料解釋為筆跡筆畫 (InputDeviceTypes),並聲明按鈕上按一下事件的偵聽器。
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;
}
最後,我們將筆跡保存在儲存按鈕的點擊事件處理程序中。
FileSavePicker 可讓使用者同時選取檔案和儲存筆跡資料的位置。
選擇檔案後,我們開啟一個設定為 ReadWrite 的 IRandomAccessStream 流。
然後,我們呼叫 SaveAsync 將 InkStrokeContainer 管理的筆跡筆畫序列化到流中。
// 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.
}
}
}
注意
GIF 是唯一支援儲存筆跡的檔案格式。 不過,LoadAsync 方法 (在下一節所示) 確實支援其他格式以提供回溯相容性。
從檔案載入筆跡筆劃
在這裡,我們將示範如何從檔案載入筆墨筆劃,並在 InkCanvas 控制項上轉譯筆墨筆劃。
從筆跡序列化格式 (ISF) 檔案儲存和載入筆跡筆畫下載此範例
首先,我們會設定 UI。
UI 包含儲存、載入和清除按鈕以及 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>
然後,我們會設定一些基本的筆跡輸入行為。
InkPresenter 配置為將來自筆和滑鼠的輸入資料解釋為筆跡筆畫 (InputDeviceTypes),並聲明按鈕上按一下事件的偵聽器。
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;
}
最後,我們在載入按鈕的點擊事件處理程序中載入筆跡。
FileOpenPicker 可讓使用者從何處選取檔案和位置,以擷取儲存的筆跡資料。
選擇檔案後,我們打開一個設定為 Read 的 IRandomAccessStream 流。
然後,我們呼叫 LoadAsync 來讀取、反序列化保存的筆跡筆畫並將其載入到 InkStrokeContainer 中。 將筆畫載入到 InkStrokeContainer 會導致 InkPresenter 立即將它們轉譯到 InkCanvas。
注意
在載入新的筆劃之前,會清除 InkStrokeContainer 中的所有現有筆劃。
// 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.
}
}
注意
GIF 是唯一支援儲存筆跡的檔案格式。 不過,LoadAsync 方法支援下列格式以提供回溯相容性。
格式 | 描述 |
---|---|
InkSerializedFormat | 指定使用 ISF 保存的筆跡。 這是筆跡最精簡的持續性表示法。 它可以內嵌在二進位檔格式內,或直接放在剪貼簿上。 |
Base64InkSerializedFormat | 指定將 ISF 編碼為 base64 流來保留的筆跡。 提供此格式是為了使筆跡可以直接編碼在 XML 或 HTML 檔案中。 |
Gif | 指定透過使用包含 ISF 作為嵌入在檔案中的元資料的 GIF 檔案來保留的筆跡。 這使得可以在未啟用筆跡的應用程式中查看筆跡,並在返回啟用筆跡的應用程式時保持其完整的筆跡保真度。 當在 HTML 檔案中傳輸筆跡內容並使其可供筆跡和非筆跡應用程式使用時,此格式非常理想。 |
Base64Gif | 指定使用 Base64 編碼的強化 GIF 保留的筆跡。 當筆跡要直接在 XML 或 HTML 檔案中編碼,以便稍後轉換成影像時,會提供此格式。 其可能的用途是產生 XML 格式以包含所有筆跡訊息,並用於透過可擴展樣式表語言轉換 (XSLT) 產生 HTML。 |
使用剪貼簿複製並貼上筆跡筆劃
在這裡,我們示範如何使用剪貼簿在應用程式之間傳輸筆跡筆畫。
為了支援剪貼簿功能,內建 InkStrokeContainer 剪下和複製指令需要選擇一個或多個筆跡筆畫。
在此範例中,當使用筆筒按鈕 (或滑鼠右鍵) 修改輸入時,我們啟用筆畫選擇。 有關如何實現筆畫選擇的完整範例,請參閱筆和手寫筆互動中的高級處理的直通輸入。
從剪貼簿儲存並載入筆跡筆畫下載此範例
首先,我們會設定 UI。
UI 包括「剪下」、「複製」、「貼上」和「清除」按鈕,以及 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="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>
然後,我們會設定一些基本的筆跡輸入行為。
InkPresenter 配置為將來自筆和滑鼠的輸入資料解釋為筆跡筆畫 (InputDeviceTypes)。 這裡也會宣告按鈕上 Click 事件的接聽程式,以及選取功能的指標和筆劃事件。
有關如何實現筆畫選擇的完整範例,請參閱筆和手寫筆互動中的高級處理的直通輸入。
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;
}
最後,在新增筆畫選擇支援之後,我們在剪下、複製和貼上按鈕的點擊事件處理程序中實現了剪貼簿功能。
對於剪切,我們首先在 InkPresenter 的 InkPresenter 上呼叫 CopySelectedToClipboard。
然後,我們會呼叫 DeleteSelected,以從筆跡畫布中移除筆劃。
最後,我們會從選取畫布中刪除所有選取專案筆劃。
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;
}
}
對於複製,我們只需在 InkPresenter 的 InkStrokeContainer 上呼叫 CopySelectedToClipboard 即可。
private void btnCopy_Click(object sender, RoutedEventArgs e)
{
inkCanvas.InkPresenter.StrokeContainer.CopySelectedToClipboard();
}
為了貼上,我們呼叫 CanPasteFromClipboard 以確保剪貼簿上的內容可以貼到筆跡畫布上。
如果是這樣,我們呼叫 PasteFromClipboard 將剪貼簿筆跡筆畫插入到 InkPresenter 的 InkStrokeContainer 中,然後 InkPresenter 將筆畫轉譯到筆跡畫布。
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.
}
}
相關文章
主題範例
其他範例