1

I am developing c# lambda functions using Visual Studio 2017, the AWS Toolkit for VS2017 and the AWS Lambda Project .Net Core 2.0 template. I have successfully developed and deployed a few functions. I developed a function that uses Aspose.Net version 18.5. The function executes as expected when tested on my Windows machine. However, when deployed on AWS Lambda, I receive this stack trace:

One or more errors occurred. (The type initializer for 'Gdip' threw an exception.): AggregateException
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at lambda_method(Closure , Stream , Stream , LambdaContextInternal )

at System.Drawing.SafeNativeMethods.Gdip.GdipCreateMatrix2(Single m11, Single m12, Single m21, Single m22, Single dx, Single dy, IntPtr& matrix)
at \u0006   .\u0002(Single \u0002, Single \u0003, Single \u0005, Single , Single \u0006, Single \u000e, \u000e    \u000f)
at    .\u0002(\u0005    \u0002, \u000f ​  \u0003, \u000e    \u0005, Single , Single \u0006, Boolean \u000e, Int32 \u000f, Boolean \u0002 , Double& \u0003 , Double& \u0005 , \u0002 ​ &  )
at    ..ctor(\u000f ​  \u0002, \u0005    \u0003, \u000f ​  \u0005)
at \u0002   .\u000f     \u0002(\u000f ​  \u0002, \u0005    \u0003, \u000f ​  \u0005,    & )
at \u0006   .\u0002(   & \u0002)
at Aspose.Pdf.Devices.ImageDevice.\u0002(Page \u0002)
at Aspose.Pdf.Devices.PngDevice.Process(Page page, Stream output)
at CreateImagesFromPDF.Function.<FunctionHandler>d__10.MoveNext() in C:\Users\Thomas\source\repos\CreateImagesFromPDF\CreateImagesFromPDF\Function.cs:line 156
Unable to load DLL 'libdl': The specified module or one of its dependencies could not be found.
(Exception from HRESULT: 0x8007007E): DllNotFoundException
at Interop.Libdl.dlopen(String fileName, Int32 flag)
at System.Drawing.SafeNativeMethods.Gdip.LoadNativeLibrary()
at System.Drawing.SafeNativeMethods.Gdip..cctor()

The key message here appears to be "Unable to load DLL 'libdl'. Researching the problem I found that Aspose is dependant on System.Drawing.Common which is dependant on libdl.dll on Windows and libdl.so on Linux (where Lambda executes). Apparently, in some distros of Linux, this library is libdl.so.2. If this were a regular app, not a Lambda function, the answer appears to be to create a symbolic link from libdl.so.2 to libdl.so. Unfortunately, I don't believe that is available to me with Lambda. If I were creating my Lambda package on Linux, I would include libdl.so.2 renamed to libdl.so in the package. But, I am creating the package using the AWS Toolkit and don't know how I can add that library to it. Any help I can get with this problem would be appreciated.

Here is my source code:

using (GetObjectResponse response = await S3Client.GetObjectAsync(request))
{
    using (Stream responseStream = response.ResponseStream)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            responseStream.CopyTo(ms);

            using (Document doc = new Document(ms))
            {
                for (int i = 0; i < doc.Pages.Count; i++)
                {
                    string outFile = fileName + "_" + (i + 1).ToString() + ".png";
                    string tmpFile = "/tmp/" + outFile;
                    Page page = doc.Pages[i + 1];

                    using (FileStream imageStream = new FileStream(tmpFile, FileMode.Create))
                    {
                        PngDevice pngDevice;
                        pngDevice = new PngDevice(Convert.ToInt32((double)page.Rect.Width * 4.17), Convert.ToInt32((double)page.Rect.Height * 4.17));
                        pngDevice.Process(page, imageStream);
                        imageStream.Close();

                        var putRequest = new PutObjectRequest
                        {
                            BucketName = s3Event.Bucket.Name,
                            Key = newFolder + outFile,
                            ContentType = "image/png",
                            FilePath = tmpFile
                        };

                        PutObjectResponse resp = await S3Client.PutObjectAsync(putRequest);

                        File.Delete(tmpFile);

                    }
                }
            }
        }
    }
}

The code is failing on the line "pngDevice.Process(page, imageStream);".

tomc
  • 83
  • 1
  • 1
  • 6
  • just curious -- have you tried creating a symlink at runtime? Looks like .NET Core doesn't have a symlink API, but you could shell out and invoke `ln -s` ... I haven't tested this myself, but thought I'd toss out the idea. –  May 25 '18 at 06:37
  • 1
    Trevor, that was an excellent idea. I added code to shell out and perform the link. Unfortunately, I was hit with "ln: failed to create symbolic link '/lib64/libdll.so': Read-only file system". So, I guess the symbolic link idea is out. – tomc May 25 '18 at 12:25
  • I was unable to work through this issue using Aspose. I solved my problem by using Ghostscript instead. However, the default ghostscript version on AWS Linux would not work. I found compiled binaries for Ghostscript version 9.20 here: [link](https://github.com/sina-masnadi/lambda-ghostscript). I included the GS binary in my deployment package and it did the job. – tomc Jun 16 '18 at 17:37
  • @tomc Could you go into further detail into how you got Ghostscript to work with .Net Core? I am unsure on how to use it. Facing the same error you had. – Avinash Prabhakar Oct 11 '18 at 05:09
  • Yes. I compiled the Ghostscript program as in the link (mentioned above) on a linux vm. Then, I copied the binary to my Visual Studio project on my PC and in the Copy to Output Directory property for the gs binary, I selected Copy if newer. Then in my code I ran the bash shell as an external process with the following command line: "gs -dNOPAUSE -dBATCH -r300 -sDEVICE=png16m -sOutputFile='" + tmpFile + "' " + pageFile;" where pageFile is the file with a single pdf page in it and tmpFile is the name of the output file to generate (something.png). Hope this helps. – tomc Oct 11 '18 at 15:57
  • Sorry, I misspoke. I did not compile the binaries, I simply copied the gs binary from the link I mentioned above to my project. The only binary required is the gs binary. – tomc Oct 11 '18 at 16:03

0 Answers0