locked
How can I save image captured from DirectX context without using FileSavePicker?

    Question

  • Hi, everyone, 

    I am trying to save the image captured from DirectX context as png or jpeg, and I don't want to use FileSavePicker because the file name will be the combination of date and time. Do I need to use some stream techniques ? Please advise me, thanks. 



    • Edited by pointeryang Thursday, September 27, 2012 7:27 PM
    Thursday, September 27, 2012 7:27 PM

Answers

  • Here is a file sample with the filepicker, I will let you convert it to not using the filepicker. Note you will need to include shcore.lib or you will get an error.

    void SimpleTextRenderer::blockprintclick2()
    {
    
        
        // Prepare a file picker for customers to input image file name.
        Pickers::FileSavePicker^ savePicker = ref new Pickers::FileSavePicker();
        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;
            }
            
            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:32 AM
  • You might want to check out the ScreenGrab module in the DirectXTex package.
    Monday, October 1, 2012 9:46 PM

All replies

  • Here is a file sample with the filepicker, I will let you convert it to not using the filepicker. Note you will need to include shcore.lib or you will get an error.

    void SimpleTextRenderer::blockprintclick2()
    {
    
        
        // Prepare a file picker for customers to input image file name.
        Pickers::FileSavePicker^ savePicker = ref new Pickers::FileSavePicker();
        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;
            }
            
            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:32 AM
  • Thank, Wright, 

    My code is pretty much like this, I am trying to save the image with the raw stream.

    Saturday, September 29, 2012 12:18 AM
  • You might want to check out the ScreenGrab module in the DirectXTex package.
    Monday, October 1, 2012 9:46 PM