0

以下は、ウィンドウ内のキャンバスに四角形を描画し、任意のキーが押されたときに CopyFromScreen 関数を使用してアプリのスクリーン ショットを取得する単純なアプリのコードです。ただし、これが呼び出される直前に、canvas.Children.Clear() を呼び出します。結果の画像には長方形が含まれていないことが期待されますが、そうです。関数が呼び出されたときに実際の長方形の画像がキャンバスから削除されていないようですが、しばらくしてからです。

System.Threading.Thread.Sleep(1000); を入れてみました。Clear() 呼び出しの後ですが、四角形はその 1 秒間も画面に表示されたままになります。キーを押す関数が終了した後に明らかに削除されています.CopyFromScreen呼び出しの前に削除する方法はありますか?

これを実行するには、System.Drawing への参照を追加する必要があります。

XAML コード

<Window x:Class="CanvasTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Width="210" Height="240"
        KeyDown="keyPressed">
    <Window.Background>
        <SolidColorBrush Color="White"/>
    </Window.Background>
    <Grid>
        <Canvas Name="canvas"
            HorizontalAlignment="Left" VerticalAlignment="Top">
        </Canvas>
    </Grid>
</Window>

.cs コード

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;

namespace CanvasTest {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();

            Left = 0;
            Top = 0;

            Rectangle rect = new Rectangle {
                Stroke = System.Windows.Media.Brushes.Black,
                StrokeThickness = 1,
                Width = 100,
                Height = 100
            };

            canvas.Children.Add(rect);
            Canvas.SetLeft(rect, 50);
            Canvas.SetTop(rect, 50);
        }

        private void keyPressed(object sender, System.Windows.Input.KeyEventArgs e) {
            System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap((int)Width, (int)Height);

            System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap);

            canvas.Children.Clear();
            graphics.CopyFromScreen(0, 0, 0, 0,
                                    new System.Drawing.Size(bitmap.Width, bitmap.Height),
                                    System.Drawing.CopyPixelOperation.SourceCopy);

            String path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            path += "\\MuckleEwesPic.png";

            bitmap.Save(path, System.Drawing.Imaging.ImageFormat.Png);
        }
    }
}

キャンバスをクリアしてから、この動作を起こさずにスクリーンショットを撮るにはどうすればよいですか? そして、「四角形を追加しないでください」は解決策ではありません。これは、問題が発生している大規模なアプリの最小限の例にすぎません。

ありがとう。

4

1 に答える 1

1

ColinSmith のリンクのようなものを使用します。

static void WaitForRenderPass()
{
  Application.Current.Dispatcher
    .BeginInvoke( DispatcherPriority.ApplicationIdle, new Action( () => {} ) )
    .Wait();
}

レンダー パスを待機するための一種の機能ですが、問題は、そのレンダー パスに必要なものがすべて含まれているかどうかを確認できないことです (私の知る限り)。

実際には、システム負荷/ビデオカードドライバー/...に応じて、複数回呼び出す必要があります。最大 3 回のループで呼び出す必要がある 1 台のマシンがあり、それらの呼び出しのそれぞれが完了するまでに約 2 フレーム @60Hz かかりました。上記の呼び出しは、レンダリング スレッドが実際にアイドル状態であることをすぐに示します。これは、必要なすべての変更がレンダリングされたことを意味し、スクリーン キャプチャに必要なものがすべて含まれていることを意味します。だから私たちは最終的に使用しました

for( int i = 0 ; i < 5 ; ++i )
{
  WaitForRenderPass();
  Thread.Sleep( 10 );
}

醜いハックですが、(まだ)失敗していません。

HighCore のコメントについて: Wpf のみのクラスでも画面をキャプチャできますが、次のようになります。

  • OPが最初にこの質問を開始したのと同じ問題があるため、すぐには何も解決しません(System.Drawingを使用しない場合を除く)
  • キャプチャでメイン ウィンドウのクロムを取得することはできません。
  • CopyScreen よりも著しく遅い
  • 画面にレンダリングされたのとまったく同じピクセルをレンダリングしません
于 2015-04-02T08:05:58.557 に答える