I am developing an AWS Lambda function project using C# Dot NET Core. What I am doing now is I am resizing the image when an image file is uploaded to s3. This is my project structure.
I have three projects in the single solution. AwsLambda.Domain project is the Dot NET Framework project and AwsLambda is the Dot NET Core project. The Aws Lambda project has the dependency on the AwsLambda.Domain project. Basically, in the AwsLambda.Domain project, I created a new class called ImageHelper.cs which is responsible for resizing the image using features from the Dot NET Framework.
This is my ImageHelper.cs class under AwsLambda.Doamin project.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace AwsS3Lambda.Domain
{
public class ImageHelper
{
public string CreateThumbImage(string sourcePath, string destPath, int width, int height)
{
Image imgOriginal = Image.FromFile(sourcePath);
Image imgActual = Scale(imgOriginal, width, height);
imgActual.Save(destPath);
imgActual.Dispose();
return destPath;
}
private Image Scale(Image imgPhoto, int width, int height)
{
float sourceWidth = imgPhoto.Width;
float sourceHeight = imgPhoto.Height;
float destHeight = 0;
float destWidth = 0;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
// force resize, might distort image
if(width != 0 && height != 0)
{
destWidth = width;
destHeight = height;
}
// change size proportially depending on width or height
else if(height != 0)
{
destWidth = (float)(height * sourceWidth) / sourceHeight;
destHeight = height;
}
else
{
destWidth = width;
destHeight = (float)(sourceHeight * width / sourceWidth);
}
Bitmap bmPhoto = new Bitmap((int)destWidth, (int)destHeight,
PixelFormat.Format32bppPArgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,
new Rectangle(destX, destY, (int)destWidth, (int)destHeight),
new Rectangle(sourceX, sourceY, (int)sourceWidth, (int)sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
}
}
This is my lambda function class that is using ImageHelper.cs class to resize the uploaded image.
public class Function
{
public static string IAM_KEY { get { return "xxx"; } }
public static string IAM_SECRET { get { return "xxx"; } }
public static string TEMP_IMG_FILE_PATH { get { return @"../../tmp/temp_img.jpeg"; } }
public static string TEMP_RESIZED_IMG_PATH { get { return @"../../tmp/resized_img.jpeg"; } }
private IAmazonS3 S3Client { get; set; }
private ImageHelper imageHelper { get; set; }
public Function()
{
S3Client = new AmazonS3Client();
imageHelper = new ImageHelper();
}
public Function(IAmazonS3 s3Client)
{
this.S3Client = s3Client;
this.imageHelper = new ImageHelper();
}
public async Task<string> FunctionHandler(S3Event evnt, ILambdaContext context)
{
var s3Event = evnt.Records?[0].S3;
if(s3Event == null)
{
return null;
}
try
{
if(s3Event.Object.Key.ToLower().Contains("thumb"))
{
//Console.WriteLine("The image is already a thumb file");
return "The file is aready a thumb image file";
}
string[] pathSegments = s3Event.Object.Key.Split('/');
string eventCode = pathSegments[0];
string userEmail = pathSegments[1];
string filename = pathSegments[2];
string extension = Path.GetExtension(filename); //.jpeg with "dot"
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
using(var objectResponse = await this.S3Client.GetObjectAsync(s3Event.Bucket.Name, s3Event.Object.Key))
{
using(Stream responseStream = objectResponse.ResponseStream)
{
this.saveFile(responseStream, Function.TEMP_IMG_FILE_PATH);
imageHelper.CreateThumbImage(Function.TEMP_IMG_FILE_PATH, Function.TEMP_RESIZED_IMG_PATH, 200, 200);
///This code is throwing error
await this.S3Client.PutObjectAsync(new Amazon.S3.Model.PutObjectRequest
{
BucketName = s3Event.Bucket.Name,
Key = fileNameWithoutExtension + ".thumb" + extension,
FilePath = Function.TEMP_RESIZED_IMG_PATH
});
}
}
return "Thumbnail version of the image has been created";
}
catch(Exception e)
{
context.Logger.LogLine($"Error getting object {s3Event.Object.Key} from bucket {s3Event.Bucket.Name}. Make sure they exist and your bucket is in the same region as this function.");
context.Logger.LogLine(e.Message);
context.Logger.LogLine(e.StackTrace);
throw;
}
}
private void saveFile(Stream stream, string path)
{
using(var fileStream = File.Create(path))
{
//stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(fileStream);
}
}
}
When I test the function in the console, it gave me this error regarding to the Image resizing features implemented under AwsLambda.Domain project (Dot NET Framework).
{
"errorType": "AggregateException",
"errorMessage": "One or more errors occurred. (Could not load type 'System.Drawing.Image' from assembly 'System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.)",
"stackTrace": [
"at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)",
"at lambda_method(Closure , Stream , Stream , LambdaContextInternal )"
],
"cause": {
"errorType": "TypeLoadException",
"errorMessage": "Could not load type 'System.Drawing.Image' from assembly 'System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.",
"stackTrace": [
"at AwsS3Lambda.Domain.ImageHelper.CreateThumbImage(String sourcePath, String destPath, Int32 width, Int32 height)",
"at AwsS3Lambda.Function.<FunctionHandler>d__18.MoveNext() in C:\\Users\\Acer\\Documents\\Visual Studio 2017\\Projects\\AwsS3Lambda\\AwsS3Lambda\\Function.cs:line 106"
]
},
"causes": [
{
"errorType": "TypeLoadException",
"errorMessage": "Could not load type 'System.Drawing.Image' from assembly 'System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.",
"stackTrace": [
"at AwsS3Lambda.Domain.ImageHelper.CreateThumbImage(String sourcePath, String destPath, Int32 width, Int32 height)",
"at AwsS3Lambda.Function.<FunctionHandler>d__18.MoveNext() in C:\\Users\\Acer\\Documents\\Visual Studio 2017\\Projects\\AwsS3Lambda\\AwsS3Lambda\\Function.cs:line 106"
]
}
]
}
Why is that throwing that error. The image resizing class code is working when I used it in the ASP.NET MVC project. It just does not work for this AWS Lambda function project. What is missing in my project? What would be the other way around to resize the uploaded image in AWS Lambda function project which is based on Dot NET Core?