Search code examples
c#.net-6.0blazor-server-sidememorystreamskiasharp

SkiaSharp SKBitmap.Decode() Value cannot be null. (Parameter 'buffer')


I am trying to upload multiple images from a Blazor InputFile component:

<InputFile OnChange="@LoadFiles" multiple accept=".png, .jpg, .jpeg, .gif" />

Once in memory, using SkiaSharp I need to resize them down to a maximum of 1000 pixels wide/high. I created a helper method for this, but it seems to fail on any image that is over approximately 4MB. I have pieced the following logic together from searches plus whatever (rather lacking) Microsoft documentation is available, so my approach may be entirely wrong:

using SkiaSharp;

public static byte[] Resize(byte[] fileContents, int maxWidth, int maxHeight)
{
    using MemoryStream ms = new(fileContents);
    using SKBitmap sourceBitmap = SKBitmap.Decode(ms); // <-- EXCEPTION HERE ON LARGER FILES
                        
    int height = Math.Min(maxHeight, sourceBitmap.Height);
    int width = Math.Min(maxWidth, sourceBitmap.Width);
    var quality = SKFilterQuality.High;

    using SKBitmap scaledBitmap = sourceBitmap.Resize(new SKImageInfo(width, height), quality);
    using SKImage scaledImage = SKImage.FromBitmap(scaledBitmap);
    using SKData data = scaledImage.Encode();

    return data.ToArray();
}

In the Razor component:

foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
{
    // Convert uploaded file into a byte array

    await using var memoryStream = new MemoryStream();
    await file.OpenReadStream(maxFileSizeBytes).CopyToAsync(memoryStream);
    var imageByteArray = memoryStream.ToArray();
    await memoryStream.DisposeAsync();

    // Use byte array to generate a resized image

    var resizedFullSizeBytes = EventFinderShared.Images.ImageDimensionCalculation.Resize(imageByteArray, maxWidthOrHeight, maxWidthOrHeight); // <== Error here
    var resizedThumbnailBytes = EventFinderShared.Images.ImageDimensionCalculation.Resize(imageByteArray, thumbnailWidthOrHeight, thumbnailWidthOrHeight);

    // Further usage removed for brevity...
}

Using the debugger, byte[] fileContents definitely is not null, so I have no idea what's occurring.

System.ArgumentNullException
  HResult=0x80004003
  Message=Value cannot be null. Arg_ParamName_Name
  Source=SkiaSharp
  StackTrace:
   at SkiaSharp.SKManagedStream.OnReadManagedStream(IntPtr buffer, IntPtr size)
   at SkiaSharp.SKAbstractManagedStream.ReadInternal(IntPtr s, Void* context, Void* buffer, IntPtr size)
   at SkiaSharp.SkiaApi.sk_codec_new_from_stream(IntPtr stream, SKCodecResult* result)
   at SkiaSharp.SKCodec.Create(SKStream stream, SKCodecResult& result)
   at SkiaSharp.SKBitmap.Decode(Stream stream)
   at EventFinderShared.Images.ImageDimensionCalculation.Resize(Byte[] fileContents...

Solution

  • The issue was due to a bug in SkiaSharp 2.88.2. Updating to 2.88.3 has solved the problem, although it appears that related issues may still exist.