Unable to load DLL 'libdl' when using System.Drawing.Common NuGet package on AWS Lambda

19

We have a thumbnail generator lambda function which I'm trying to update to .NET Core 2.0, but I've encountered the following error when using Microsoft's System.Drawing.Common NuGet package:

TypeInitializationException

The type initializer for 'Gdip' threw an exception. at System.Drawing.SafeNativeMethods.Gdip.GdipCreateBitmapFromScan0(Int32 width, Int32 height, Int32 stride, Int32 format, HandleRef scan0, IntPtr& bitmap) at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format) at TestFailExample.Function.FunctionHandler(String input, ILambdaContext context) in C:\work\graphics\TestFailExample\Function.cs:line 25 at lambda_method(Closure , Stream , Stream , LambdaContextInternal )

caused by

DllNotFoundException

Unable to load DLL 'libdl': The specified module or one of its dependencies could not be found.\n (Exception from HRESULT: 0x8007007E) at Interop.Libdl.dlopen(String fileName, Int32 flag) at System.Drawing.SafeNativeMethods.Gdip.LoadNativeLibrary() at System.Drawing.SafeNativeMethods.Gdip..cctor()

I've seen this question, but there was no resolution.

The minimum code to reproduce the issue is this:

public string FunctionHandler(string input, ILambdaContext context)
{
    using (var bmp = new Bitmap(100, 100))
    {
        return bmp.Width.ToString();
    }
}

Simply create a .NET Core 2.0 Lambda function project, add a reference to the System.Drawing.Common NuGet package, and replace the function handler with the above code. Chuck it on AWS and run it to get the error. I've noted that referencing the package doesn't cause a problem until you try to actually use it, but this could be down to compiler optimizations.

I've packaged the MCVE into a project and uploaded it to GitHub here for the sake of simplifying the steps people have to go through to reproduce the issue.

I can see that /lib64/libdl.so.2 exists, but /lib64/libdl.so does not. Since symlinking doesn't seem to be possible (read-only file system), I'm not sure how I can resolve this. I've tried using the LD_LIBRARY_PATH environment variable by creating a folder in /tmp and symlinking the file there as the first thing the function does. Unfortunately, it seems to look here for all libraries so the function doesn't run at all. I've also tried setting LD_LIBRARY_PATH to /var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/tmp and, although I could now run the function again, this still didn't help and I just get the same Gdip error.

I noted that /var/task/lib is already included in the LD_LIBRARY_PATH, so I tried packaging libdl.so and libgdiplus.so with my function, but this also failed, this time stating that entry point GdiplusStartup wasn't found in libdgiplus.so. These files weren't from an Amazon Linux instance, so I've now tried installing Mono and obtaining them from an Amazon Linux instance. This has not helped.

I've tried with the CoreCompat drawing library but this also reports problems pertaining to libgdiplus.so, even if I try and bundle that with the function.

I've tried since on my own Linux instance and can confirm that System.Drawing.Common works.

Is there some clever solution that will allow me to use System.Drawing.Common on AWS Lambda? Is there another way I can fudge my lambda function to have libdl and work?

Update:

Our latest attempt involved using AWS Lambda Layers and carefully extracting all the packages installed by apt within the Docker Amazon Linux image, and then applying those to their own layer. Still we ultimately came down to the "libdl" issue, so we gave up.

A lot of the issues with libraries people suggested are that they didn't render Japanese text correctly, which is important for us. This seems to be an issue which isn't going to get better on AWS Lambda it didn't help, and ultimately it was easier to rewrite our function in Go than continue using C# for this.

Since the libraries mentioned by the answers below are seemingly suitable for general use - and may indeed support Japanese text now - I've chosen to accept the answer that I'm sure will work on AWS Lambda.

c#
aws-lambda
.net-core-2.0
asked on Stack Overflow May 31, 2018 by Llama • edited Jun 27, 2019 by Llama

4 Answers

3

I found a solution for this issue which worked for me:

At first i removed the System.Drawing.Common library from the project, then i installed the library you can find here. It uses the same classes.

using System.Drawing
...
var bmp = new Bitmap(100,100);

At last I installed this other library which contains all the dll's necesary for using drawing libraries on Linux and Lambda as well. By doing this steps the code can be uploaded to AWS without any problem.

answered on Stack Overflow Mar 26, 2019 by Alex HG
3

I had the same issue after uploading my application on Ubuntu 18 server running dotnet core 2.1.500 version. I resolved this issue with this solution https://github.com/dotnet/dotnet-docker/issues/618 using MichaelSimons suggestions.

I ran

#sudo apt-get update
#sudo apt-get install -y --allow-unauthenticated \
        libc6-dev \
        libgdiplus \
        libx11-dev \ 
#sudo rm -rf /var/lib/apt/lists/*

This resolved the issues.

answered on Stack Overflow Apr 9, 2019 by Fidelis Kalu • edited Apr 9, 2019 by Dijkgraaf
0

If one uses centOS, then below command helps.

  • sudo yum install libgdiplus
answered on Stack Overflow Aug 4, 2020 by Rohil Patel
-1

For image processing in .NET Core Lambda I use the SixLabors.ImageSharp

Here is the code I used in my recent AWS re:Invent talk that did a log if image processing:

var imageBuffer = new MemoryStream();

var resizeOptions = new ResizeOptions
{
    Size = new SixLabors.Primitives.Size { Width = this.TileSize, Height = this.TileSize},
    Mode = ResizeMode.Stretch
};
image.Mutate(x => x.Resize(resizeOptions));
image.Save(imageBuffer, new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder());

imageBuffer.Position = 0;
answered on Stack Overflow Dec 5, 2018 by Norm Johanson

User contributions licensed under CC BY-SA 3.0