locked
How can I capture the screen shot rendered by DirectX

    Question

  • Hi, everyone, 

    Nowadays, I am trying to take screen shots from my win 8 app running in DirectX, but I have no idea how to do it, I have searched around the forum and internet, unfortunately, I did not get very useful answers, somebody says frame buffer or render target should work, but I am still confusing in saving the frame buffer data locally once get the correct frame buffer data. If somebody did something similar in DirectX, please advise, thanks. 

    Monday, September 24, 2012 9:51 PM

Answers

  • Are you having trouble getting the data completely or are you able to get it but then don't know how to save it out?

    The DirectX postcard app sample demonstrates how to use WIC to render a Direct2D image to a file. Take a look at the PostcardRenderer::SaveBitmapToStream method and its callers. You can do essentially the same thing from Direct3D by rendering into a DXGISurface and then using CreateSharedBitmap to create an ID2D1Bitmap. See Direct2D and Direct3D Interoperability Overview for more information.

    If you still need more details please let us know what you have already figured out and which parts you need help with.

    --Rob

    • Marked as answer by pointeryang Wednesday, September 26, 2012 12:18 AM
    Tuesday, September 25, 2012 4:17 AM
    Moderator
  • The function in DirectXTex is CaptureTexture which can capture all kinds of Direct3D 11 resources (1D, 2D, 3D, Cubemaps, 1DArray, 2DArray, mipmaps, etc.). You can then use SaveToWICFile, SaveToDDSFile, or SaveToTGAFile to store the captured data. I'm also looking at adding a standalone module to DirectXTK to do the limited case of just capturing a screenshot which can be a lot more streamlined than the 'full' support present in DirectXTex.
    Wednesday, September 26, 2012 10:30 PM

All replies

  • Are you having trouble getting the data completely or are you able to get it but then don't know how to save it out?

    The DirectX postcard app sample demonstrates how to use WIC to render a Direct2D image to a file. Take a look at the PostcardRenderer::SaveBitmapToStream method and its callers. You can do essentially the same thing from Direct3D by rendering into a DXGISurface and then using CreateSharedBitmap to create an ID2D1Bitmap. See Direct2D and Direct3D Interoperability Overview for more information.

    If you still need more details please let us know what you have already figured out and which parts you need help with.

    --Rob

    • Marked as answer by pointeryang Wednesday, September 26, 2012 12:18 AM
    Tuesday, September 25, 2012 4:17 AM
    Moderator
  • You might want to look at the code in DirectXTex which includes a 'capture texture' function.

    Tuesday, September 25, 2012 8:07 PM
  • Thanks Rob. This is helpful, I will try this approach and tell you what happens. 

    • Edited by pointeryang Tuesday, September 25, 2012 9:53 PM
    Tuesday, September 25, 2012 9:18 PM
  • Hi, Chuck, 

    You mean a function named ..CaptureTexture.., because I couldn't find it. Or, you mean some functions do texture capturing, if so, please tell me what are the functions or you can just tell me what the files are, I can figure it out by myself. Thanks.

    Tuesday, September 25, 2012 9:50 PM
  • The function in DirectXTex is CaptureTexture which can capture all kinds of Direct3D 11 resources (1D, 2D, 3D, Cubemaps, 1DArray, 2DArray, mipmaps, etc.). You can then use SaveToWICFile, SaveToDDSFile, or SaveToTGAFile to store the captured data. I'm also looking at adding a standalone module to DirectXTK to do the limited case of just capturing a screenshot which can be a lot more streamlined than the 'full' support present in DirectXTex.
    Wednesday, September 26, 2012 10:30 PM
  • Sounds good, Thanks Chuck
    Thursday, September 27, 2012 7:07 PM
  • Try this code. You must include shcore.lib or it wont work.

    void SimpleTextRenderer::blockprintclick2()
    {
    
        // Set state to Saving to block another copy of this function being called before saving completes.
       
    
        // Prepare a file picker for customers to input image file name.
        Pickers::FileSavePicker^ savePicker = ref new Pickers::FileSavePicker();
    //    auto pngExtensions = ref new Platform::Collections::Vector<Platform::String^>();
    //    pngExtensions->Append(".png");
    //    savePicker->FileTypeChoices->Insert("PNG file", pngExtensions);
    //    auto jpgExtensions = ref new Platform::Collections::Vector<Platform::String^>();
    //    jpgExtensions->Append(".jpg");
    //    savePicker->FileTypeChoices->Insert("JPEG file", jpgExtensions);
        auto bmpExtensions = ref new Platform::Collections::Vector<Platform::String^>();
        bmpExtensions->Append(".bmp");
        savePicker->FileTypeChoices->Insert("BMP file", bmpExtensions);
        savePicker->DefaultFileExtension = ".bmp";
        savePicker->SuggestedFileName = "SaveScreen";
        savePicker->SuggestedStartLocation = Pickers::PickerLocationId::PicturesLibrary;
    
        std::shared_ptr<GUID> wicFormat = std::make_shared<GUID>(GUID_ContainerFormatPng);
    
        create_task(savePicker->PickSaveFileAsync()).then([=](StorageFile^ file)
        {
            if (file == nullptr)
            {
                // If user clicks "Cancel", reset the saving state, then cancel the current task.
                
                cancel_current_task();
            }
    
           String^  m_imageFileName = file->Name;
            if (file->FileType == ".bmp")
            {
                *wicFormat = GUID_ContainerFormatBmp;
            }
            else if (file->FileType == ".jpg")
            {
                *wicFormat = GUID_ContainerFormatJpeg;
            }
            return file->OpenAsync(FileAccessMode::ReadWrite);
    
        }).then([=](Streams::IRandomAccessStream^ randomAccessStream)
        {
            // Convert the RandomAccessStream to an IStream.
            ComPtr<IStream> stream;
    
    	        DX::ThrowIfFailed(
    			CreateStreamOverRandomAccessStream(randomAccessStream, IID_PPV_ARGS(&stream))
                );
    	
    
    
    
            // Render the screen contents to an off-screen bitmap and then save that bitmap to a file.
            ComPtr<ID2D1Bitmap1> targetBitmap;
            D2D1_SIZE_U pixelSize = m_d2dContext->GetPixelSize();
    
            DX::ThrowIfFailed(
                m_d2dContext->CreateBitmap(
                    pixelSize,
                    nullptr,
                    pixelSize.width * 4,    // pitch = width * size of pixel (4 bytes for B8G8R8A8)
                    D2D1::BitmapProperties1(
                        D2D1_BITMAP_OPTIONS_TARGET,
                        D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)
                        ),
                    &targetBitmap
                    )
                );
    
            m_d2dContext->SetTarget(targetBitmap.Get());
            PrintRender();
            m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());
    
            SaveBitmapToStream(targetBitmap, m_wicFactory, m_d2dContext, *wicFormat, stream.Get());
    
    
    
    
    
    
        });
    }
    
    // Save render target bitmap to a stream using WIC.
    void SaveBitmapToStream(
        _In_ ComPtr<ID2D1Bitmap1> d2dBitmap,
        _In_ ComPtr<IWICImagingFactory2> wicFactory2,
        _In_ ComPtr<ID2D1DeviceContext> d2dContext,
        _In_ REFGUID wicFormat,
        _In_ IStream* stream
        )
    {
        // Create and initialize WIC Bitmap Encoder.
        ComPtr<IWICBitmapEncoder> wicBitmapEncoder;
        DX::ThrowIfFailed(
            wicFactory2->CreateEncoder(
                wicFormat,
                nullptr,    // No preferred codec vendor.
                &wicBitmapEncoder
                )
            );
    
        DX::ThrowIfFailed(
            wicBitmapEncoder->Initialize(
                stream,
                WICBitmapEncoderNoCache
                )
            );
    
        // Create and initialize WIC Frame Encoder.
        ComPtr<IWICBitmapFrameEncode> wicFrameEncode;
        DX::ThrowIfFailed(
            wicBitmapEncoder->CreateNewFrame(
                &wicFrameEncode,
                nullptr     // No encoder options.
                )
            );
    
        DX::ThrowIfFailed(
            wicFrameEncode->Initialize(nullptr)
            );
    
        // Retrieve D2D Device.
        ComPtr<ID2D1Device> d2dDevice;
        d2dContext->GetDevice(&d2dDevice);
    
        // Create IWICImageEncoder.
        ComPtr<IWICImageEncoder> imageEncoder;
        DX::ThrowIfFailed(
            wicFactory2->CreateImageEncoder(
                d2dDevice.Get(),
                &imageEncoder
                )
            );
    
        DX::ThrowIfFailed(
            imageEncoder->WriteFrame(
                d2dBitmap.Get(),
                wicFrameEncode.Get(),
                nullptr     // Use default WICImageParameter options.
                )
            );
    
        DX::ThrowIfFailed(
            wicFrameEncode->Commit()
            );
    
        DX::ThrowIfFailed(
            wicBitmapEncoder->Commit()
            );
    
        // Flush all memory buffers to the next-level storage object.
        DX::ThrowIfFailed(
            stream->Commit(STGC_DEFAULT)
            );
    }


    n.Wright


    Friday, September 28, 2012 1:36 AM
  • I recently added a ScreenGrab module to the DirectXTex package. It's intended for exactly this kind of usage.

    We'll be integrating it into the DirectXTK library soon.

    Sunday, September 30, 2012 7:27 PM
  • That's cool! Thanks.
    Monday, October 1, 2012 5:03 AM