Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error using using RenderTargetBitmap in UWP

I'm trying to create a bitmap image, and have the following code:

RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(uielement);

IBuffer pixels = await renderTargetBitmap.GetPixelsAsync();

. . .

var pixelArray = pixels.ToArray();

In order to get a ToArray() extension, I came across this question. So I added:

using System.Runtime.InteropServices.WindowsRuntime; // For ToArray

To my code. However, when I run, I get the following error:

Exception thrown: 'System.ArgumentException' in System.Runtime.WindowsRuntime.dll

Additional information: The specified buffer index is not within the buffer capacity.

When I drill into the details, it says in the Stack Trace:

at >System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.ToArray(IBuffer source, UInt32 sourceIndex, Int32 count) at >System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.ToArray(IBuffer source)

Is this method of extracting a pixel array still applicable to the UWP? If it is, is there any way to get more detail from this error message?

like image 395
Paul Michaels Avatar asked Nov 09 '22 00:11

Paul Michaels


1 Answers

That method of extracting a pixel array is definitely applicable to UWP. As for the error, the decompiled ToArray() goes like this:

public static byte[] ToArray(this IBuffer source)
{
  if (source == null)
    throw new ArgumentNullException("source");
  return WindowsRuntimeBufferExtensions.ToArray(source, 0U, checked ((int) source.Length));
}

In other words, it calls the ToArray overload that takes a start index and a length:

public static byte[] ToArray(this IBuffer source, uint sourceIndex, int count)
{
  if (source == null)
    throw new ArgumentNullException("source");
  if (count < 0)
    throw new ArgumentOutOfRangeException("count");
  if (sourceIndex < 0U)
    throw new ArgumentOutOfRangeException("sourceIndex");
  if (source.Capacity <= sourceIndex)
    throw new ArgumentException(SR.GetString("Argument_BufferIndexExceedsCapacity"));
  if ((long) (source.Capacity - sourceIndex) < (long) count)
    throw new ArgumentException(SR.GetString("Argument_InsufficientSpaceInSourceBuffer"));
  byte[] destination = new byte[count];
  WindowsRuntimeBufferExtensions.CopyTo(source, sourceIndex, destination, 0, count);
  return destination;
}

The line(s) almost certainly causing your problem:

  if (source.Capacity <= sourceIndex)
    throw new ArgumentException(SR.GetString("Argument_BufferIndexExceedsCapacity"));

...and since sourceIndex is necessarily 0, that would mean that source.Capacity is also 0.

I suggest you add some instrumentation to your code to inspect the IBuffer:

RenderTargetBitmap rtb = new RenderTargetBitmap();
await rtb.RenderAsync(element);

IBuffer pixelBuffer = await rtb.GetPixelsAsync();
Debug.WriteLine($"Capacity = {pixelBuffer.Capacity}, Length={pixelBuffer.Length}");
byte[] pixels = pixelBuffer.ToArray();

I think it likely that your problem occurs before the ToArray call. I'm using the exact same sequence in my own UWP app, getting debug output like so:

Capacity = 216720, Length=216720
like image 94
Petter Hesselberg Avatar answered Nov 14 '22 21:11

Petter Hesselberg