DrawingCore exception in azure function c# .net

半世苍凉 提交于 2021-02-11 13:55:39

问题


Unhandled Exception: System.MemberAccessException:

Object is busy and cannot state allow this operation [GDI+ status: ObjectBusy]
       at System.DrawingCore.GDIPlus.CheckStatus(Status status)
       at System.DrawingCore.Image.Dispose(Boolean disposing)
       at System.DrawingCore.Image.Finalize()

This error occurs once in a while for following code. I am using sautinsoft library and imageFormat is of System.DrawingCore.Imaging.

  using (Stream fs = pdfFile.OpenReadStream())
      {
        await Task.Run(() => _pdfFocus.OpenPdf(fs));
        if (_pdfFocus.PageCount > 0)
          {
            _pdfFocus.ImageOptions.ImageFormat = imageFormat;
            _pdfFocus.ImageOptions.Dpi = 100;
            _pdfFocus.ImageOptions.JpegQuality = 90;
            for (int i = 1; i <= _pdfFocus.PageCount; i++)
              {
                 await Task.Run(() => pdfPagesAsImageFileList.Add(_pdfFocus.ToImage(i)));
              }
            }
         Task.WaitAll();
       }

回答1:


Like Marc said the azure has sandbox limitations, and mostly .net package to convert pdf to image need GDI and this is not supported. For now I only find one package to iplement it with .net. You could try with GhostScript and Magick.NET-Q16-AnyCPU to implement it.

After installing the Ghostscript, you will get the gsdll32.dll file in the bin folder. The below is my test code, copy the 02.pdf and gsdll32.dll to the kudu wwwroot folder.

using System.Net.Http;
using ImageMagick;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;

namespace FunctionApp6
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static void Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log,ExecutionContext context)
        {
            log.Info("C# HTTP trigger function processed a request.");

            MagickNET.SetGhostscriptDirectory(context.FunctionAppDirectory);
            log.Info(context.FunctionAppDirectory);
            MagickReadSettings settings = new MagickReadSettings();
            // Settings the density to 300 dpi will create an image with a better quality
            settings.Density = new Density(300, 300);

            using (MagickImageCollection images = new MagickImageCollection())
            {
                log.Info(context.FunctionAppDirectory + "\\02.pdf");
                // Add all the pages of the pdf file to the collection
                images.Read(context.FunctionAppDirectory+"\\02.pdf", settings);

                int page = 1;
                foreach (MagickImage image in images)
                {
                    log.Info(context.FunctionAppDirectory + "\\outpng" + page + ".png");
                    // Write page to file that contains the page number
                    image.Write(context.FunctionAppDirectory + "\\outpng" + page + ".png");
                    // Writing to a specific format works the same as for a single image
                    //image.Format = MagickFormat.Ptif;
                    //image.Write(SampleFiles.OutputDirectory + "Snakeware.Page" + page + ".tif");
                    page++;
                }
            }

            log.Info("convert finish");
        }
    }
}

And here is the result pic in azure.




回答2:


Azure Functions runs inside a secure environment, aka a sandbox. There are quite some limitations to this sandbox, all of them are described here: https://github.com/projectkudu/kudu/wiki/Azure-Web-App-sandbox

In your specific case you are limited because the process does not have access to GDI32 as is mentioned on the page linked above:

For the sake of radical attack surface area reduction, the sandbox prevents almost all of the Win32k.sys APIs from being called, which practically means that most of User32/GDI32 system calls are blocked. For most applications this is not an issue since most Azure Web Apps do not require access to Windows UI functionality (they are web applications after all).

There are multiple libraries used to convert HTML to PDF. Many Windows/.NET specific versions leverage IE APIs and therefore leverage User32/GDI32 extensively. These APIs are largely blocked in the sandbox (regardless of plan) and therefore these frameworks do not work in the sandbox.

There are some frameworks that do not leverage User32/GDI32 extensively (wkhtmltopdf, for example) and we are working on enabling these in Basic+ the same way we enabled SQL Reporting.

You probably need to find an alternative way to create PDF files or move the compute outside of Azure Functions.



来源:https://stackoverflow.com/questions/59469801/drawingcore-exception-in-azure-function-c-sharp-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!