.NET Core AWS Lambda函数无法使用图像处理库的问题排查
你遇到的核心问题是AWS Lambda的Linux运行环境缺少图形处理库的系统级依赖——不管是CoreCompat.System.Drawing还是SkiaSharp,报错根源都是找不到对应的原生库。下面分两种情况给出解决方案,优先推荐更适配跨平台场景的SkiaSharp方案:
一、优先方案:使用SkiaSharp(无额外系统依赖)
SkiaSharp本身是跨平台设计的,但你遇到的libSkiaSharp找不到问题,大概率是没安装针对Linux的原生资产包,或是发布时被自动剪裁掉了。按以下步骤修复:
1. 安装正确的NuGet包
在项目中安装两个关键包:
dotnet add package SkiaSharp dotnet add package SkiaSharp.NativeAssets.Linux
SkiaSharp.NativeAssets.Linux会自动包含Linux环境所需的libSkiaSharp.so原生库,无需手动安装系统依赖。
2. 调整项目发布配置
打开你的.csproj文件,添加以下配置,防止发布时剪裁掉原生库(.NET 6+默认启用剪裁功能,会误删原生文件):
<PropertyGroup> <!-- 禁用剪裁,保留原生库文件 --> <PublishTrimmed>false</PublishTrimmed> <!-- 禁用ReadyToRun,避免原生库兼容问题 --> <PublishReadyToRun>false</PublishReadyToRun> </PropertyGroup>
3. 完整的SkiaSharp图片缩放示例代码
替换你之前的代码,用SkiaSharp处理S3图片的完整流程:
using SkiaSharp; using Amazon.S3; using Amazon.S3.Model; using Amazon.Lambda.S3Events; public async Task FunctionHandler(S3Event s3Event, ILambdaContext context) { var s3Client = new AmazonS3Client(); foreach (var record in s3Event.Records) { var sourceBucket = record.S3.Bucket.Name; var sourceKey = record.S3.Object.Key; // 跳过已缩放的图片,避免循环处理 if (sourceKey.StartsWith("resized/")) continue; // 从S3获取原始图片 using var getResponse = await s3Client.GetObjectAsync(sourceBucket, sourceKey); using var inputStream = getResponse.ResponseStream; // 解码图片 using var originalBitmap = SKBitmap.Decode(inputStream); // 计算缩放尺寸(保持宽高比) const int targetWidth = 100; var targetHeight = (int)((float)originalBitmap.Height / originalBitmap.Width * targetWidth); // 缩放图片(高画质过滤) using var scaledBitmap = originalBitmap.Resize( new SKImageInfo(targetWidth, targetHeight), SKFilterQuality.High ); // 编码为JPEG(可根据需求改为PNG) using var scaledImage = SKImage.FromBitmap(scaledBitmap); using var outputStream = new MemoryStream(); scaledImage.Encode(SKEncodedImageFormat.Jpeg, 80).SaveTo(outputStream); outputStream.Position = 0; // 上传缩放后的图片到S3 var putRequest = new PutObjectRequest { BucketName = sourceBucket, Key = $"resized/{sourceKey}", InputStream = outputStream, ContentType = "image/jpeg" }; await s3Client.PutObjectAsync(putRequest); context.Logger.LogInformation($"已完成图片缩放:{sourceKey} -> resized/{sourceKey}"); } }
4. 部署注意事项
执行dotnet publish -c Release发布项目,将bin/Release/netX.X/publish目录下的所有文件打包成Zip,上传到Lambda即可。Lambda的Linux运行时会自动加载runtimes/linux-x64/native下的libSkiaSharp.so。
二、兼容方案:修复CoreCompat.System.Drawing(不推荐)
CoreCompat.System.Drawing依赖Windows的GDI+,在Linux环境下需要安装libgdiplus系统库。你可以通过以下两种方式解决:
方式1:使用Docker镜像部署Lambda
创建Dockerfile,在镜像中预装libgdiplus:
# 使用Lambda官方.NET运行时镜像 FROM public.ecr.aws/lambda/dotnet:6 # 安装libgdiplus依赖 RUN yum install -y libgdiplus # 复制发布后的项目文件到Lambda任务目录 COPY bin/Release/net6.0/publish/ ${LAMBDA_TASK_ROOT} # 指定Lambda入口函数 CMD ["AwsS3Lambda::AwsS3Lambda.Function::FunctionHandler"]
构建镜像并推送到ECR,再用这个镜像创建Lambda函数即可。
方式2:创建自定义Lambda层
- 在本地Linux环境(或WSL)中安装
libgdiplus:yum install -y libgdiplus - 找到
libgdiplus.so的路径(通常是/usr/lib64/libgdiplus.so),将其复制到lib/目录下 - 将
lib/目录打包成Zip,上传为Lambda层 - 在你的Lambda函数中添加这个层,运行时就能找到依赖库了
总结
SkiaSharp是更适合Lambda跨平台环境的选择,无需额外配置系统依赖,只需正确安装NuGet包和调整发布配置即可。CoreCompat.System.Drawing因依赖GDI+,需要额外处理系统依赖,维护成本更高,不推荐在Lambda中使用。
内容的提问来源于stack exchange,提问作者Wai Yan Hein

