Windows Ink をサポートする Windows アプリは、インク ストロークをシリアル化して、インク シリアル化形式 (ISF) ファイルに逆シリアル化できます。 ISF ファイルは GIF イメージであり、すべてのインク ストロークのプロパティと動作のメタデータが追加されています。 インク対応ではないアプリでは、アルファ チャネルの背景の透明度など、静的 GIF イメージを表示できます。
注
ISF は、インクの最もコンパクトな永続的表現です。 GIF ファイルなどのバイナリ ドキュメント形式で埋め込んだり、クリップボードに直接配置したりできます。
インク シリアル化形式 (ISF) 仕様は、 Microsoft ダウンロード センターからダウンロードできます。
重要な 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 を使用すると、ユーザーはファイルと保存されたインク データを取得する場所の両方を選択できます。
ファイルを選択すると、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 メソッドでは、下位互換性のために次の形式がサポートされています。
フォーマット | 説明 |
---|---|
インクシリアライズドフォーマット | ISF を使用して永続化されるインクを指定します。 これは、インクの最もコンパクトな永続的な表現です。 バイナリ ドキュメント形式で埋め込んだり、クリップボードに直接配置したりできます。 |
Base64InkSerializedFormat | ISF を base64 ストリームとしてエンコードすることによって永続化されるインクを指定します。 この形式は、XML または HTML ファイルでインクを直接エンコードできるように提供されます。 |
ジフ | ファイル内に埋め込まれたメタデータとして ISF を含む GIF ファイルを使用して永続化されるインクを指定します。 これにより、インクが有効になっていないアプリケーションでインクを表示し、インク対応アプリケーションに戻ったときに完全なインクの忠実性を維持できます。 この形式は、HTML ファイル内でインク コンテンツを転送する場合や、インクアプリケーションやインク以外のアプリケーションで使用できる場合に最適です。 |
Base64Gif | base64 でエンコードされた強化 GIF を使用して永続化されるインクを指定します。 この形式は、後で画像に変換するために、インクを XML または HTML ファイルに直接エンコードする場合に提供されます。 これを使用するには、すべてのインク情報を含めるために生成され、拡張スタイルシート言語変換 (XSLT) を介して HTML を生成するために使用される XML 形式で使用できます。 |
インク ストロークをクリップボードにコピーして貼り付ける
ここでは、クリップボードを使用してアプリ間でインク ストロークを転送する方法を示します。
クリップボード機能をサポートするために、組み込みの InkStrokeContainer の切り取りとコピーのコマンドでは、1 つ以上のインク ストロークを選択する必要があります。
この例では、ペン バレル ボタン (またはマウスの右ボタン) で入力が変更されたときにストロークの選択を有効にします。 ストローク選択の実装方法についての完全な例を知るには、「ペンとスタイラスのやり取りのための高度処理用パススルー入力」を参照してください。
このサンプルをダウンロード クリップボードからインク ストロークを保存して読み込む
まず、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) として解釈するように構成されています。 ボタンのクリック イベントのリスナーと、選択機能のポインター イベントとストローク イベントもここで宣言されています。
ストローク選択の実装方法についての完全な例を知るには、「ペンとスタイラスのやり取りのための高度処理用パススルー入力」を参照してください。
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の InkStrokeContainer で 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;
}
}
コピーの場合は、
private void btnCopy_Click(object sender, RoutedEventArgs e)
{
inkCanvas.InkPresenter.StrokeContainer.CopySelectedToClipboard();
}
貼り付けのために、 CanPasteFromClipboard を呼び出して、クリップボードのコンテンツをインク キャンバスに貼り付けられるようにします。
その場合は、PasteFromClipboard を呼び出して、InkPresenter の InkStrokeContainer にクリップボードのインク ストロークを挿入し、インク キャンバスにストロークをレンダリングします。
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.
}
}
関連資料
トピックのサンプル
その他のサンプル
Windows developer