You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor InputFile上传大图片时SkiaSharp SKBitmap.Decode报空参数异常

解决方案

1. 修复核心解码错误

当前报错的直接原因是Resize方法中MemoryStream的读取位置问题:创建MemoryStream后,其默认Position处于字节数组末尾,SkiaSharp从该位置读取无法获取有效数据,导致解码失败。以下两种方式可快速修复:

方式一:直接解码字节数组(更简洁)

using SkiaSharp;

public static byte[] Resize(byte[] fileContents, int maxWidth, int maxHeight)
{
    using SKBitmap sourceBitmap = SKBitmap.Decode(fileContents); 
    if (sourceBitmap == null)
    {
        throw new InvalidOperationException("无法解码图片文件");
    }

    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();
}

方式二:重置MemoryStream读取位置

using SkiaSharp;

public static byte[] Resize(byte[] fileContents, int maxWidth, int maxHeight)
{
    using MemoryStream ms = new(fileContents);
    ms.Position = 0; // 关键:将流位置重置到起始处
    using SKBitmap sourceBitmap = SKBitmap.Decode(ms); 
    if (sourceBitmap == null)
    {
        throw new InvalidOperationException("无法解码图片文件");
    }

    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();
}

2. 优化大文件内存占用

避免将上传文件先转为字节数组,直接使用InputFile返回的Stream处理,减少大文件的内存消耗:

修改Razor组件调用代码

foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
{
    await using var fileStream = file.OpenReadStream(maxFileSizeBytes);
    
    var resizedFullSizeBytes = EventFinderShared.Images.ImageDimensionCalculation.Resize(fileStream, maxWidthOrHeight, maxWidthOrHeight);
    var resizedThumbnailBytes = EventFinderShared.Images.ImageDimensionCalculation.Resize(fileStream, thumbnailWidthOrHeight, thumbnailWidthOrHeight);

    // 后续代码省略...
}

新增支持Stream的Resize重载

public static byte[] Resize(Stream fileStream, int maxWidth, int maxHeight)
{
    if (fileStream.CanSeek)
    {
        fileStream.Position = 0;
    }

    using SKBitmap sourceBitmap = SKBitmap.Decode(fileStream);
    if (sourceBitmap == null)
    {
        throw new InvalidOperationException("无法解码图片文件");
    }

    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();
}

3. 超大图片进阶处理(避免内存溢出)

针对几十MB级的超大图片,直接解码完整SKBitmap可能引发内存不足,改用SKCodec渐进式处理:

public static byte[] ResizeLargeImage(Stream fileStream, int maxWidth, int maxHeight)
{
    if (fileStream.CanSeek)
    {
        fileStream.Position = 0;
    }

    using var codec = SKCodec.Create(fileStream);
    if (codec == null)
    {
        throw new InvalidOperationException("无法创建图片解码器");
    }

    var sourceInfo = codec.Info;
    float scale = Math.Min((float)maxWidth / sourceInfo.Width, (float)maxHeight / sourceInfo.Height);
    if (scale > 1) scale = 1; // 不放大图片

    var scaledInfo = new SKImageInfo(
        (int)(sourceInfo.Width * scale),
        (int)(sourceInfo.Height * scale),
        sourceInfo.ColorType,
        sourceInfo.AlphaType);

    using var scaledBitmap = new SKBitmap(scaledInfo);
    var result = codec.GetPixels(scaledInfo, scaledBitmap.GetPixels());
    if (result != SKCodecResult.Success)
    {
        throw new InvalidOperationException($"图片解码失败:{result}");
    }

    using SKImage scaledImage = SKImage.FromBitmap(scaledBitmap);
    using SKData data = scaledImage.Encode();

    return data.ToArray();
}

4. 配套配置检查

  • 确认maxFileSizeBytes值足够大(例如设置为10 * 1024 * 1024即10MB),避免因流读取不完整导致解码失败。
  • 若使用Blazor Server模式,需调整请求大小限制,在Program.cs中添加:
builder.Services.Configure<FormOptions>(options =>
{
    options.MultipartBodyLengthLimit = 10 * 1024 * 1024; // 10MB
});

内容的提问来源于stack exchange,提问作者EvilDr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 07:45:38