locked
How to save a BitmapImage as a file in file storage Windows 8 C# RRS feed

  • Question

  • Hi,

    My program basically at the moment displays a screenshot which is taken through the share button in the charms bar. So far i have a BitmapImage which i can display on the screen, but i need to save this BitmapImage as Bitmap file, png, jpg or jpeg so my editor in my app can open it and put it in a storagefile(which will be used to CropBitmap.GetCroppedBitmapAsync)

    I have been looking for days(why isnt it as simple like developing for desktop) for a solution to either turn this BitmapImage and put it in a storage file or to save the BitmapImage as a .bmp, png or jpeg.

    Any Help will be appreciated,

    Thanks

    If it helps, this is my code that makes the screenshot a Bitmap Image

    IRandomAccessStreamWithContentType bitmapStream = await this.sharedBitmapStreamRef.OpenReadAsync();
                        BitmapImage bitmapImage = new BitmapImage();
                        bitmapImage.SetSource(bitmapStream);
                        sourceImage.Source = bitmapImage;
                        screenshot = bitmapImage;

    Edit:

    I have viewed this thread that seemed to have the solution but WriteableBitmap is not taking the BitmapImage as parameter

    http://social.msdn.microsoft.com/Forums/windowsapps/en-US/40b76a69-4f94-4622-b928-5f31c7cfb98b/saving-bitmapimage-to-file?forum=winappswithcsharp


    Sunday, January 19, 2014 2:18 PM

Answers

  • Your linked thread was from the Developer Preview and is quite out of date. You cannot create a WritableBitmap from a BitmapImage without going back to its original source. In your case, you can replace the BitmapImage you stream into with a WritableBitmap and call WritableBitmap.SetSource(bitmapStream) to load it.

    Once there, you can use the WritableBitmap the same as you use the BitmapImage plus you can use a BitmapEncoder to encode the pixels to a png, &c.

    See the How to crop bitmap in a Windows Store app (C#) for code.

    • Marked as answer by Anne Jing Tuesday, January 28, 2014 2:12 AM
    Monday, January 20, 2014 2:43 PM
    Moderator

All replies

  • Hi,

    You can convert your bitmap image with WinRT XAML Toolkit extensions WriteableBitmapFromBitmapImageExtension.

    Then save it with WriteableBitmapSaveExtensions.

    Hope this can help you.

    Let me know if you have any troubles with toolkit.


    Sunday, January 19, 2014 4:19 PM
  • Here is my code in c++.

    Hopefully you can convert it to c#

    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

    Sunday, January 19, 2014 4:44 PM
  • Your linked thread was from the Developer Preview and is quite out of date. You cannot create a WritableBitmap from a BitmapImage without going back to its original source. In your case, you can replace the BitmapImage you stream into with a WritableBitmap and call WritableBitmap.SetSource(bitmapStream) to load it.

    Once there, you can use the WritableBitmap the same as you use the BitmapImage plus you can use a BitmapEncoder to encode the pixels to a png, &c.

    See the How to crop bitmap in a Windows Store app (C#) for code.

    • Marked as answer by Anne Jing Tuesday, January 28, 2014 2:12 AM
    Monday, January 20, 2014 2:43 PM
    Moderator