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
相关产品推荐
相关产品推荐

