Answered by:
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
- Edited by nigelwright7557 Friday, September 28, 2012 1:33 AM
- Proposed as answer by nigelwright7557 Friday, September 28, 2012 1:35 AM
- Marked as answer by Jesse JiangModerator Wednesday, October 3, 2012 2:12 AM
Friday, September 28, 2012 1:32 AM -
You might want to check out the ScreenGrab module in the DirectXTex package.
- Marked as answer by Jesse JiangModerator Wednesday, October 3, 2012 2:12 AM
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
- Edited by nigelwright7557 Friday, September 28, 2012 1:33 AM
- Proposed as answer by nigelwright7557 Friday, September 28, 2012 1:35 AM
- Marked as answer by Jesse JiangModerator Wednesday, October 3, 2012 2:12 AM
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.
- Marked as answer by Jesse JiangModerator Wednesday, October 3, 2012 2:12 AM
Monday, October 1, 2012 9:46 PM