Unable to load Splat.IBitmap from MemoryStream

0

I am trying to render layout data to a bitmap in a platform-agnostic manner by returning a Splat.IBitmap and am having trouble outputting the results. My WPF platform code looks like this:

MemoryStream stream = new MemoryStream();
try
{
    RenderTargetBitmap target = new RenderTargetBitmap(1024, 1024, 300, 300, PixelFormats.Default);
    PreviewView preview = new PreviewView();  // this does sizing and placement

    target.Render(preview);

    previewViewModel.Dispose();
    BitmapEncoder encoder = new BmpBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(target));
    encoder.Save(stream);
    stream.Flush();

    IBitmap bitmap = BitmapLoader.Current.Load(stream, 1024, 1024).Result;
    stream.Dispose();

    return bitmap;
}
catch (Exception e)
{
    // TODO: log error
    return null;
}
finally
{
    stream.Dispose();
}

I keep hitting an AggregateException on the BitmapLoader.Current.Load call.The inner exception is a NotSupportedException with the message No imaging component suitable to complete this operation was found. I have not been able to find any relevant documentation to explain what this means or what I'm doing wrong. As a test, I have tried saving the bitmap encoder to a FileStream, which worked fine.

EDIT

It was pointed out that this issue may be a duplicate of this issue. They are certainly related, but in this case I would like to know why saving to the MemoryStream fails to create valid image data where a FileStream works.

EDIT 2

At request, here are the exceptions I see in output:

Exception thrown: 'System.NotSupportedException' in PresentationCore.dll
Exception thrown: 'System.NotSupportedException' in PresentationCore.dll
Exception thrown: 'System.AggregateException' in mscorlib.dll

The inner NotSupportedException of the AggregateException has this message and stacktrace:

No imaging component suitable to complete this operation was found.
at System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri, Stream stream, BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable, Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream, SafeFileHandle& safeFilehandle)
at System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
at System.Windows.Media.Imaging.BitmapImage.FinalizeCreation()
at System.Windows.Media.Imaging.BitmapImage.EndInit()
at Splat.PlatformBitmapLoader.withInit(BitmapImage source, Action`1 block) in y:\\code\\paulcbetts\\splat\\Splat\\Xaml\\Bitmaps.cs:line 80
at Splat.PlatformBitmapLoader.<>c__DisplayClass2.<Load>b__0() in y:\\code\\paulcbetts\\splat\\Splat\\Xaml\\Bitmaps.cs:line 25
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()

While that exceptions inner NotSupportedException only has this message, and no stack trace:

The component cannot be found. (Exception from HRESULT: 0x88982F50)
wpf
cross-platform
reactiveui
rendertargetbitmap
asked on Stack Overflow Apr 17, 2017 by Matt Singer • edited May 23, 2017 by Community

1 Answer

0

This doesn't answer my original question, so I won't accept this as the correct answer, but I found a more correct way to handle what I wanted. I was writing out to a MemoryStream because I thought it was necessary, but all I needed was to take a laid-out view in WPF and get an IBitmap which I could use elsewhere. Turns out making this happen was easier than I was making it out to be:

try
{
    RenderTargetBitmap target = new RenderTargetBitmap(1024, 1024, 300, 300,
        PixelFormats.Default);
    PreviewView preview = new PreviewView();  // this does sizing and placement

    target.Render(preview);

    // HERE IS AN IMPORTANT BIT. This allows me to access the RenderTargetBitmap from 
    // another thread, for example if calling IBitmap.Save() which happens on another
    // in a separate Task
    target.Freeze();

    previewViewModel.Dispose();

    // HERE IS ANOTHER IMPORTANT BIT. There's no need to capture a frame and save to a 
    // Stream through an Encoder. Splat lets you create bitmaps from a native
    // implementation
    IBitmap bitmap = target.FromNative();

    return bitmap;
}
catch (Exception e)
{
    // TODO: log error
    return null;
}
answered on Stack Overflow Apr 29, 2017 by Matt Singer

User contributions licensed under CC BY-SA 3.0