次の方法で共有


Windows Ink のストローク データを格納および取得することができます

Windows Ink をサポートする Windows アプリは、インク ストロークをシリアル化して、インク シリアル化形式 (ISF) ファイルに逆シリアル化できます。 ISF ファイルは GIF イメージであり、すべてのインク ストロークのプロパティと動作のメタデータが追加されています。 インク対応ではないアプリでは、アルファ チャネルの背景の透明度など、静的 GIF イメージを表示できます。

ISF は、インクの最もコンパクトな永続的表現です。 GIF ファイルなどのバイナリ ドキュメント形式で埋め込んだり、クリップボードに直接配置したりできます。

インク シリアル化形式 (ISF) 仕様は、 Microsoft ダウンロード センターからダウンロードできます。

重要な API: InkCanvasWindows.UI.Input.Inking

インク ストロークをファイルに保存する

ここでは、 InkCanvas コントロールに描画されたインク ストロークを保存する方法を示します。

インク シリアル化形式(ISF)ファイルからインク ストロークを保存および読み込みこのサンプルをダウンロードします

  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="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. 次に、基本的なインク入力動作をいくつか設定します。

    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;
    }
  1. 最後に、[保存] ボタンのクリック イベント ハンドラーにインクを 保存 します。

    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)ファイルからインク ストロークを保存および読み込みこのサンプルをダウンロードします

  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="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. 次に、基本的なインク入力動作をいくつか設定します。

    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;
    }
  1. 最後に、[読み込み] ボタンのクリック イベント ハンドラーにインクを読み込みます。

    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 つ以上のインク ストロークを選択する必要があります。

この例では、ペン バレル ボタン (またはマウスの右ボタン) で入力が変更されたときにストロークの選択を有効にします。 ストローク選択の実装方法についての完全な例を知るには、「ペンとスタイラスのやり取りのための高度処理用パススルー入力」を参照してください。

このサンプルをダウンロード クリップボードからインク ストロークを保存して読み込む

  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>
  1. 次に、基本的なインク入力動作をいくつか設定します。

    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;
    }
  1. 最後に、ストローク選択のサポートを追加した後、 切り取りコピー貼り付け ボタンのクリック イベント ハンドラーにクリップボード機能を実装します。

    切り取りの場合は、最初に InkPresenterInkStrokeContainer で 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;
        }
    }

コピーの場合は、InkPresenterInkStrokeContainer で CopySelectedToClipboard 呼び出すだけです。

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

貼り付けのために、 CanPasteFromClipboard を呼び出して、クリップボードのコンテンツをインク キャンバスに貼り付けられるようにします。

その場合は、PasteFromClipboard を呼び出して、InkPresenterInkStrokeContainer にクリップボードのインク ストロークを挿入し、インク キャンバスにストロークをレンダリングします。

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

トピックのサンプル

その他のサンプル