po całym dniu testów wpadłem z tym kodem, który przechwytuje bieżącego ekranu przy użyciu DirectX (SlimDX) i zapisuje go do pliku:Saving Surface do bitmap i optymalizacji DirectX przechwytywania ekranu w C#
Device d;
public DxScreenCapture()
{
PresentParameters present_params = new PresentParameters();
present_params.Windowed = true;
present_params.SwapEffect = SwapEffect.Discard;
d = new Device(new Direct3D(), 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.SoftwareVertexProcessing, present_params);
}
public Surface CaptureScreen()
{
Surface s = Surface.CreateOffscreenPlain(d, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, Format.A8R8G8B8, Pool.Scratch);
d.GetFrontBufferData(0, s);
return s;
}
potem wykonaj następujące czynności:
DxScreenCapture sc = new DxScreenCapture();
..code tutaj
private void button1_Click(object sender, EventArgs e)
{
Stopwatch stopwatch = new Stopwatch();
// Begin timing
stopwatch.Start();
Surface s = sc.CaptureScreen();
Surface.ToFile(s, @"c:\temp\test.png", ImageFileFormat.Png);
s.Dispose();
stopwatch.Stop();
textBox1.Text = ("Elapsed:" + stopwatch.Elapsed.TotalMilliseconds);
}
wyniki:
0. kiedy nie zapisuję powierzchni: śr. upłynął czas: 80-90ms
1. kiedy również zapiszę plik Surface to BMP: format: ImageFileFormat.Bmp, śr. czas trwania: 120ms, rozmiar pliku: 7mb
2. Kiedy również zapiszę plik Surface to PNG: format: ImageFileFormat.Png, śr. Upływający czas: 800ms, rozmiar pliku: 300 KB
Pytania są:
1. Czy to możliwe, aby zoptymalizować bieżące przechwytywanie obrazu? Zgodnie z tym artykułem - przechwytywanie ekranu DirectX powinno być szybsze niż GDI. Dla mnie GDI zwykle zajmuje 20 ms, aby uzyskać "Bitmapę", podczas gdy uzyskanie "Surfare" za pomocą DX (bez zapisywania) zajmuje 80 ms.
http://www.codeproject.com/Articles/274461/Very-fast-screen-capture-using-DirectX-in-Csharp
2a. Jak szybciej zapisać format powierzchni Surface na PNG? Kiedy zachowuję powierzchnię do pliku BMP 7mb, zajmuje to prawie 6 razy mniej czasu niż wtedy, gdy zapisuję tę samą powierzchnię na pliku PNG 300kb.
2b. Czy można zapisać Surface bezpośrednio w Bitmapie, więc nie muszę tworzyć plików tymczasowych?
Nie muszę więc wykonywać następujących czynności: Powierzchnia -> plik obrazu; plik obrazu otwarty -> bitmap;, ale zamiast tego: Powierzchnia -> mapa bitowa
to wszystko na teraz. Chętnie przyjmę wszelkie wskazówki, dzięki!
Edit:
Wystarczy rozwiązać 2b wykonując:
Bitmap bitmap = new Bitmap(SlimDX.Direct3D9.Surface.ToStream(s, SlimDX.Direct3D9.ImageFileFormat.Bmp));
Edit2:
Surface.ToFile(s, @"C:\temp\test.bmp", ImageFileFormat.Bmp);
Bitmap bitmap = new Bitmap(@"C:\temp\test.bmp");
jest szybszy niż:
Bitmap bitmap = new Bitmap(SlimDX.Direct3D9.Surface.ToStream(s, SlimDX.Direct3D9.ImageFileFormat.Bmp));
przez 100 ms !!!Tak, nie mogłem uwierzyć własnym oczom;) Nie podoba mi się pomysł tworzenia plików tymczasowych, ale 50% wzrost wydajności (100-200 ms zamiast 200-300 +) jest bardzo dobrą rzeczą.
Myślę, że png może kompresować szybciej niż 800 ms. Spróbuj, czy jest to szybsze, jeśli po raz pierwszy napiszesz do memorystream. –