しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Bing Maps コントロールの地図をキャプチャする

Bing Maps コントロールを利用すると Wndows ストアアプリでも簡単に地図を表示することができます

f:id:matatabi_ux:20140308212810p:plain

表示される地図をキャプチャして画像ファイルにする場合、下記のようにすれば保存できます

private async void Button_Click(object sender, RoutedEventArgs e)
{
    var bitmap = new RenderTargetBitmap();
    await bitmap.RenderAsync(this.mapView, (int)this.mapView.ActualWidth, (int)this.mapView.ActualHeight);
    var data = await bitmap.GetPixelsAsync();

    var file = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("tmp.png", CreationCollisionOption.GenerateUniqueName);
    using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);

        encoder.SetPixelData(
            BitmapPixelFormat.Bgra8,
            BitmapAlphaMode.Straight,
            (uint)bitmap.PixelWidth,
            (uint)bitmap.PixelHeight,
            DisplayInformation.GetForCurrentView().LogicalDpi,
            DisplayInformation.GetForCurrentView().LogicalDpi,
            data.ToArray());

        await encoder.FlushAsync();
    }
}

・・・ただし、表示位置を移動した直後や航空写真に変えた直後ににキャプチャするとレンダリングが追い付かなくて歯抜け地図画像になってしまうことが;

f:id:matatabi_ux:20140308213035p:plain

ウェイトをおくにしても PC のスペックや場所、地図情報のキャッシュ状態によって必要な待ち時間がまちまちでどの程度待ち時間を設定すればよいのかわかりません;

いろいろ試行錯誤した結果、完璧ではないですが Bing Maps コントロールが内部で利用しているキャッシュファイルの更新日時を参照する以下のような方法に行きつきました

/// <summary>
/// index.ext ファイルの最終更新日時
/// </summary>
private DateTimeOffset mapExtFileModified = DateTimeOffset.MinValue;

/// <summary>
/// マップコントロールのレンダリングを待機する
/// </summary>
/// <returns>Task</returns>
private async Task WaitMapRender()
{
    this.mapExtFileModified = DateTimeOffset.Now;

    // 最大約10秒まで Bing Maps のキャッシュ更新を監視する
    for (int i = 0; i < 50; i++)
    {
        await Task.Delay(50);
        if (this.mapExtFileModified.CompareTo(await this.GetMapExtFileModified()) < 0)
        {
            break;
        }
        await Task.Delay(150);
    }
}

/// <summary>
/// Bing Maps のキャッシュファイル(index.ext)更新日時を取得する
/// </summary>
/// <returns>index.ext の更新日時</returns>
private async Task<DateTimeOffset> GetMapExtFileModified()
{
    try
    {
        var extFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(@"ms-appdata:///temp/Bing.Maps/Cache/QuadKey/index.ext", UriKind.Absolute));
        var property = await extFile.GetBasicPropertiesAsync();
        return property.DateModified;
    }
    catch (Exception)
    {
        return DateTimeOffset.MinValue;
    }
}

この方法でやったら少しは改善されたような気がします

f:id:matatabi_ux:20140308213525p:plain