locked
Save image and some InkStrokes to a file.

    Question

  • hi, 

    I have a canvas control, the background is an image, andi draw some InkStrokes on the canvas. I want to save the image and the InkStrokes to a file, but I do not how to do.

    After work some days on it , I find that maybe DirectX can do it , But I am just a new to DirectX.  So is it possible and how to do?

    thanks in advance.

    W


    Tuesday, June 25, 2013 2:55 AM

Answers

  • The inking sample demonstrates saving ink strokes to a file. The hard part is compositing this on an image. You can't capture the image from the screen, so you'll need to draw the strokes on the bitmap rather than just drawing them as separate objects on the canvas. I believe (but I'm on my phone so can't easily check) the C++ simple inking sample draws the strokes with Direct2D, so that should get you most of the way there.
    • Marked as answer by Bin.W Monday, July 01, 2013 7:39 AM
    Tuesday, June 25, 2013 3:05 PM
    Owner

All replies

  • The inking sample demonstrates saving ink strokes to a file. The hard part is compositing this on an image. You can't capture the image from the screen, so you'll need to draw the strokes on the bitmap rather than just drawing them as separate objects on the canvas. I believe (but I'm on my phone so can't easily check) the C++ simple inking sample draws the strokes with Direct2D, so that should get you most of the way there.
    • Marked as answer by Bin.W Monday, July 01, 2013 7:39 AM
    Tuesday, June 25, 2013 3:05 PM
    Owner
  • Heres how I did saved the screen

    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()); layersenabled0 = 0xffffffffffffffff; layersenabled1 = 0xffffffffffffffff; }); } // 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

    Wednesday, June 26, 2013 8:48 PM
  • Hi Rob,

    Just as you say, the c++ simple inking sample draws the stokes with Direct2D. And I get a way to realize the function that composing an image with inkstrokes, then save them to a file. 

    1. Convert inkstroke to geometry as same as the Demo.

    2. Use DX to draw the image and geometry.

    3. Save them to a file.

    Thanks again

    W



    • Edited by Bin.W Friday, June 28, 2013 3:12 AM bad write
    Friday, June 28, 2013 2:36 AM