Skärmdump

Windows. Graphics.Capture-namnområdet innehåller API:er för att hämta bildrutor från ett visnings- eller programfönster för att skapa videoströmmar eller ögonblicksbilder för att skapa samarbetsinriktade och interaktiva upplevelser.

Med skärmdump anropar utvecklare säkert systemgränssnitt för slutanvändare för att välja visnings- eller programfönstret som ska fångas, och en gul meddelandekantlinje ritas av systemet runt det aktivt insamlade objektet. Vid flera samtidiga avbildningssessioner ritas en gul kantlinje runt varje objekt som samlas in.

Note

API:erna för skärmdump stöds bara på Windows stationära enheter och Windows Mixed Reality uppslukande headset.

I den här artikeln beskrivs hur du avbildar en enda bild av visnings- eller programfönstret.

Sök efter stöd för skärmdump

Innan du försöker samla in kontrollerar du om den aktuella enheten stöder skärmdump. Använd metoden IsSupportedGraphicsCaptureSession för att avgöra om skärmdump är tillgänglig:

// Check if screen capture is supported
if (!GraphicsCaptureSession.IsSupported())
{
    // Hide capture UI
    CaptureControlsPanel.Visibility = Visibility.Collapsed;
    PreviewPlaceholderText.Text = "Screen capture isn't supported on this device.";
    UpdateStatus("Screen capture isn't supported on this device.");
    return;
}

Det finns flera orsaker till varför skärmdump kanske inte stöds, inklusive om enheten inte uppfyller maskinvarukraven.

Starta systemgränssnittet för att starta skärmdumpen

Använd klassen GraphicsCapturePicker för att anropa användargränssnittet för systemväljaren. Slutanvändaren använder det här användargränssnittet för att välja visnings- eller programfönstret som ska avbildas. Väljaren returnerar en GraphicsCaptureItem som används för att skapa en avbildningssession.

I en WinUI 3-app måste du initiera väljaren med fönsterhandtaget innan du anropar PickSingleItemAsync:

// Launch picker and start capture
var picker = new GraphicsCapturePicker();
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);
GraphicsCaptureItem item = await picker.PickSingleItemAsync();
if (item != null)
{
    StartCaptureInternal(item);
}

Skapa en bildrutepool och en inspelningssession

Med Hjälp av GraphicsCaptureItem skapar du en Direct3D11CaptureFramePool med din D3D-enhet, ett pixelformat som stöds (DXGI_FORMAT_B8G8R8A8_UNORM), antalet önskade bildrutor (vilket kan vara valfritt heltal) och bildrutestorlek. Egenskapen Storlek för klassen GraphicsCaptureItem kan användas som storlek på din ram:

// Create frame pool and capture session
_framePool = Direct3D11CaptureFramePool.Create(
    _canvasDevice,
    CaptureDirectXPixelFormat.B8G8R8A8UIntNormalized,
    BufferCount,
    item.Size);
_session = _framePool.CreateCaptureSession(item);

Note

På system med Windows HD-färg aktiverat kanske innehållspixelformatet inte nödvändigtvis är DXGI_FORMAT_B8G8R8A8_UNORM. Om du vill undvika pixelöverklotning (dvs. det insamlade innehållet ser ut att spolas ut) när du samlar in HDR-innehåll bör du överväga att använda DXGI_FORMAT_R16G16B16A16_FLOAT för varje komponent i insamlingspipelinen, inklusive Direct3D11CaptureFramePool, målmålet, till exempel CanvasBitmap. Beroende på behovet kan ytterligare bearbetning som att spara till HDR-innehållsformat eller HDR-till-SDR-tonmappning krävas. Den här artikeln fokuserar på SDR-innehållsfångst. Mer information finns i Använda DirectX med skärmar med högt dynamiskt omfång och avancerad färg.

När användaren uttryckligen har gett sitt medgivande till att samla in ett programfönster eller visa det i systemgränssnittet kan GraphicsCaptureItem associeras med flera insamlingssessioner. På så sätt kan ditt program välja att samla in samma objekt för olika upplevelser.

Hämta avbildningsramar

När din rampool och avbildningssession har skapats anropar du StartCapturedin GraphicsCaptureSession-instans för att meddela systemet att börja skicka avbildningsramar till din app.

Om du vill hämta dessa avbildningsramar, som är Direct3D11CaptureFrame-objekt , använder du händelsen Direct3D11CaptureFramePool.FrameArrived :

// Handle frame arrival
_framePool.FrameArrived += OnFrameArrived;

Vi rekommenderar att du undviker hårt arbete med användargränssnittstråden för FrameArrived, eftersom den här händelsen utlöses varje gång en ny ram är tillgänglig. Om du väljer att lyssna på FrameArrived i användargränssnittstråden bör du tänka på hur mycket arbete du utför varje gång händelsen utlöses.

Du kan också manuellt hämta ramar med direct3D11CaptureFramePool.TryGetNextFrame-metoden tills du får alla ramar som du behöver.

objektet Direct3D11CaptureFrame innehåller egenskaperna ContentSize, Surface och SystemRelativeTime. SystemRelativeTime är QPC-tid (QueryPerformanceCounter) som kan användas för att synkronisera andra medieelement.

Bildrutor för processinspelning

Varje bildruta från Direct3D11CaptureFramePool checkas ut när du anropar TryGetNextFrame och checkas in igen enligt livslängden för Direct3D11CaptureFrame-objektet . För hanterade program rekommenderar vi att du använder metoden Direct3D11CaptureFrame.Dispose . Direct3D11CaptureFrame implementerar IDisposable, så om du tar bort ramen returneras bufferten till poolen.

Program bör inte spara referenser till Direct3D11CaptureFrame-objekt , och de bör inte heller spara referenser till den underliggande Direct3D-ytan när ramen har checkats in igen.

I det här exemplet konverteras varje bildruta till en CanvasBitmap, som är en del av Win2D-biblioteket :

// Convert frame to Win2D bitmap and display
CanvasBitmap canvasBitmap = CanvasBitmap.CreateFromDirect3D11Surface(
    _canvasDevice,
    frame.Surface);

Den underliggande Direct3D-ytan är alltid den storlek som anges när du skapar (eller återskapar) Direct3D11CaptureFramePool. Om innehållet är större än ramen klipps innehållet till ramens storlek. Om innehållet är mindre än ramen innehåller resten av ramen odefinierade data. Vi rekommenderar att program kopierar ut en delrekta med egenskapen ContentSize för Direct3D11CaptureFrame för att undvika att visa odefinierat innehåll.

Spara en skärmbild

När du har en CanvasBitmap kan du spara den som en bildfil. I följande exempel sparas den aktuella bildrutan som en PNG-fil med hjälp av en FileSavePicker. I en WinUI 3-app måste du initialisera väljarkontrollen med fönsterhandtaget:

// Save screenshot
var savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
savePicker.SuggestedFileName = "screen-capture";
savePicker.FileTypeChoices.Add("PNG image", new List<string> { ".png" });
WinRT.Interop.InitializeWithWindow.Initialize(savePicker, _hwnd);
StorageFile? file = await savePicker.PickSaveFileAsync();
if (file is not null)
{
    using var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite);
    await frameToSave.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
}

Hantera storleksändring av inspelningsobjekt eller enhetsbortfall

Under insamlingsprocessen kan program vilja ändra aspekter av sin Direct3D11CaptureFramePool. Detta inkluderar att tillhandahålla en ny Direct3D-enhet, ändra storleken på rambuffertar eller till och med ändra antalet buffertar i poolen. I vart och ett av dessa scenarier är metoden Återskapa i Direct3D11CaptureFramePool-objektet den rekommenderade metoden.

När Återskapa anropas ignoreras alla befintliga bildrutor. Detta för att förhindra att bildrutor delas ut vars underliggande Direct3D-ytor tillhör en enhet som programmet kanske inte längre har åtkomst till. Därför kan det vara klokt att bearbeta alla väntande ramar innan du anropar Recreate.

Överväganden för WinUI 3

När du migrerar skärmdumpskod från UWP till WinUI 3 (Windows App SDK) bör du ha följande skillnader i åtanke:

  • Initiering av fönsterhandtag – väljare som GraphicsCapturePicker och FileSavePicker måste initieras med fönsterhandtaget med hjälp av InitializeWithWindow. Mer information finns i Hämta ett fönsterhandtag (HWND).
  • Kompositions-API:er på användargränssnittstråden – I WinUI 3 måste ytåtgärder för CanvasComposition (till exempel att rita på en CompositionDrawingSurface) köas till användargränssnittstråden med DispatcherQueue.TryEnqueue. Insamling av bildrutor och skapande av bitmappar kan ske på framepoolens bakgrundstråd, men uppdateringen av kompositionsvisualen måste ske på UI-tråden.
  • Namespace-ändringar – Använd Microsoft.UI.Composition, Microsoft.UI.Xaml.Hosting och Microsoft.UI.Dispatching i stället för deras Windows.UI motsvarigheter. Namnområdet Windows.Graphics.Capture förblir oförändrat.

Se även