Captura de tela

O namespace Windows.Graphics.Capture fornece APIs para capturar quadros de uma tela ou de uma janela de aplicativo, para criar fluxos de vídeo ou instantâneos e desenvolver experiências colaborativas e interativas.

Com a captura de tela, os desenvolvedores invocam a interface do usuário do sistema seguro para que os usuários finais escolham a janela de exibição ou aplicativo a ser capturada e uma borda de notificação amarela é desenhada pelo sistema em torno do item capturado ativamente. No caso de várias sessões de captura simultâneas, uma borda amarela é desenhada em torno de cada item que está sendo capturado.

Note

As APIs de captura de tela são compatíveis apenas com dispositivos Windows para área de trabalho e headsets imersivos do Windows Mixed Reality.

Este artigo descreve a captura de uma única imagem da janela de exibição ou aplicativo.

Verificar se há suporte para captura de tela

Antes de tentar capturar, verifique se o dispositivo atual dá suporte à captura de tela. Use o método IsSupported no GraphicsCaptureSession para determinar se a captura de tela está disponível:

// 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;
}

Há vários motivos pelos quais a captura de tela pode não ter suporte, inclusive se o dispositivo não atender aos requisitos de hardware.

Iniciar a interface do usuário do sistema para iniciar a captura de tela

Use a classe GraphicsCapturePicker para invocar a interface do usuário do seletor do sistema. O usuário final usa esta interface para selecionar a tela ou a janela do aplicativo a ser capturada. O seletor retorna um GraphicsCaptureItem usado para criar uma sessão de captura.

Em um aplicativo WinUI 3, você deve inicializar o seletor com o identificador de janela antes de chamar 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);
}

Criar um pool de quadros de captura e uma sessão de captura

Usando o GraphicsCaptureItem, crie um Direct3D11CaptureFramePool com seu dispositivo D3D, um formato de pixel com suporte (DXGI_FORMAT_B8G8R8A8_UNORM), número de quadros desejados (que podem ser qualquer inteiro) e tamanho do quadro. A propriedade Size da classe GraphicsCaptureItem pode ser usada como o tamanho do quadro:

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

Note

Em sistemas com o Windows HD Color habilitado, o formato de pixel do conteúdo não é necessariamente DXGI_FORMAT_B8G8R8A8_UNORM. Para evitar o recorte excessivo de pixels (ou seja, o conteúdo capturado parece desbotado) ao capturar conteúdo HDR, considere usar DXGI_FORMAT_R16G16B16A16_FLOAT em cada componente do pipeline de captura, incluindo o Direct3D11CaptureFramePool e o destino de saída, como CanvasBitmap. Dependendo da necessidade, podem ser necessários processamentos adicionais, como salvar no formato de conteúdo HDR ou mapeamento de tom HDR-to-SDR. Este artigo se concentra na captura de conteúdo de SDR. Para obter mais informações, consulte Como usar o DirectX com exibições de alto intervalo dinâmico e cores avançadas.

Depois que o usuário tiver dado consentimento explicitamente para capturar uma janela do aplicativo ou exibir na interface do usuário do sistema, o GraphicsCaptureItem poderá ser associado a várias sessões de captura. Dessa forma, seu aplicativo pode optar por capturar o mesmo item para várias experiências.

Adquirir quadros de captura

Com o pool de quadros e a sessão de captura criada, chame StartCapture na instância do GraphicsCaptureSession para notificar o sistema para começar a enviar quadros de captura para seu aplicativo.

Para adquirir esses quadros de captura, que são objetos Direct3D11CaptureFrame , use o evento Direct3D11CaptureFramePool.FrameArrived :

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

Recomenda-se evitar executar processamento pesado na thread da interface do usuário em FrameArrived, pois esse evento é disparado sempre que um novo frame fica disponível. Se você optar por ouvir FrameArrived no thread da interface do usuário, lembre-se de quanto trabalho você está fazendo sempre que o evento é acionado.

Como alternativa, você pode obter manualmente os quadros com o método Direct3D11CaptureFramePool.TryGetNextFrame até obter todos os quadros de que você precisa.

O objeto Direct3D11CaptureFrame contém as propriedades ContentSize, Surface e SystemRelativeTime. O SystemRelativeTime é o tempo QPC (QueryPerformanceCounter) que pode ser usado para sincronizar outros elementos de mídia.

Processar quadros de captura

Cada quadro do Direct3D11CaptureFramePool é retirado ao se chamar TryGetNextFrame e devolvido de acordo com o tempo de vida do objeto Direct3D11CaptureFrame. Para aplicativos gerenciados, é recomendável usar o método Direct3D11CaptureFrame.Dispose . Direct3D11CaptureFrame implementa IDisposable, portanto, descartar o quadro retorna o buffer para o pool.

Os aplicativos não devem salvar referências a objetos Direct3D11CaptureFrame , nem devem salvar referências à superfície subjacente do Direct3D depois que o quadro tiver sido verificado novamente.

Neste exemplo, cada quadro é convertido em um CanvasBitmap, que faz parte da biblioteca Win2D :

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

A superfície Direct3D subjacente tem sempre o tamanho especificado ao criar (ou recriar) o Direct3D11CaptureFramePool. Se o conteúdo for maior que o quadro, o conteúdo será recortado para o tamanho do quadro. Se o conteúdo for menor que o quadro, o restante do quadro conterá dados indefinidos. É recomendável que os aplicativos copiem um sub-retângulo usando a propriedade ContentSize desse Direct3D11CaptureFrame para evitar a exibição de conteúdo indefinido.

Salvar uma captura de tela

Depois de ter um CanvasBitmap, você poderá salvá-lo como um arquivo de imagem. O exemplo a seguir salva o quadro atual como um arquivo PNG usando um FileSavePicker. Em um aplicativo WinUI 3, você deve inicializar o seletor com o identificador de janela:

// 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);
}

Reagir para capturar o redimensionamento de itens ou dispositivo perdido

Durante o processo de captura, os aplicativos podem desejar alterar aspectos de seu Direct3D11CaptureFramePool. Isso inclui criar um novo dispositivo Direct3D, alterar o tamanho dos buffers de quadro ou até mesmo alterar o número de buffers no pool. Em cada um desses cenários, o método Recreate no objeto Direct3D11CaptureFramePool é a abordagem recomendada.

Quando Recriação é chamada, todos os quadros existentes são descartados. Isso é para impedir a distribuição de quadros cujas superfícies Direct3D subjacentes pertencem a um dispositivo ao qual o aplicativo pode não ter mais acesso. Por esse motivo, pode ser prudente processar todos os frames pendentes antes de chamar Recreate.

Considerações do WinUI 3

Ao migrar o código de captura de tela da UWP para o WinUI 3 (SDK do Aplicativo Windows), tenha em mente as seguintes diferenças:

  • Inicialização do identificador de janela — Seletores como GraphicsCapturePicker e FileSavePicker devem ser inicializados com o identificador de janela usando InitializeWithWindow. Para obter mais informações, consulte Recuperar um identificador de janela (HWND).
  • APIs de Composição no thread da interface do usuário — No WinUI 3, as operações de superfície do CanvasComposition (como desenhar em uma CompositionDrawingSurface) devem ser despachadas para o thread da interface do usuário usando DispatcherQueue.TryEnqueue. A captura de frames e a criação de bitmap podem acontecer na thread em segundo plano do pool de frames, mas a atualização do visual da composição deve acontecer na thread da interface do usuário.
  • Alterações no namespace — Use Microsoft.UI.Composition, Microsoft.UI.Xaml.Hosting e Microsoft.UI.Dispatching em vez de seus equivalentes Windows.UI. O namespace Windows.Graphics.Capture permanece inalterado.

Consulte também