.NET Core – gdiplus.dll not found in Linux

A few days ago there was an issue raised in my QrCoder project. It was reported that the code would not run under Linux, as the following error message would occur:

Unhandled Exception: System.TypeInitializationException: The type initializer for 'System.Drawing.KnownColors' threw an exception. 
---> System.TypeInitializationException: The type initializer for 'System.Drawing.GDIPlus' threw an exception. 
---> System.DllNotFoundException: Unable to load DLL 'gdiplus.dll': The specified module could not be found.
(Exception from HRESULT: 0x8007007E)
at System.Drawing.GDIPlus.GdiplusStartup(UInt64& token, GdiplusStartupInput& input, 
[...]

However the error message had its origin not in my QrCoder, but in the interplay of the .NET core framework with the GDI Plus library. The .NET Core Framework tries to access “gdiplus.dll” when accessing “System.Drawing.GDIPlus”, which is simply not available on Linux.

First solution approach

First, ensure that GDI+ is installed at all. This can be done with the following shell command:

sudo apt-get install libgdiplus

If libgdiplus is installed, however, another important step is missing …

Link libgdiplus for .NET Core

Because the .NET Core Framework, regardless of the operating system, is looking for the library with the suffix “.dll”, it does not find the lib on Linux, although a valid version of the libgdiplus is installed. To fix this issue we create a symbolic link to the libgdiplus.so file.

cd /usr/lib
sudo ln -s libgdiplus.so gdiplus.dll

After this, the error message should disappear. Now you will be able to use the QrCoder including the .NET Core Framework under Linux.

6 Comments

  1. sudhirsays:

    hi

    I tried your solution on the server where my api is hosted on linux env. but its not working.

    I posted error on github for dotnet core repository.
    https://github.com/dotnet/corefx/issues/31895#issuecomment-415222526

  2. sudhir thankisays:

    I tried your solution, but unfortunately its still not working on ubunto 16.4
    here is my code:
    public static bool CreateThumbnail(int Width, int Height, Stream filePath, string saveFilePath)
    {

    try
    {
    var byteArray = filePath;
    var streamImg = Image.FromStream(byteArray);

    Bitmap sourceImage = new Bitmap(streamImg);
    using (Bitmap objBitmap = new Bitmap(Width, Height))
    {
    objBitmap.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
    using (Graphics objGraphics = Graphics.FromImage(objBitmap))
    {
    // Set the graphic format for better result cropping
    objGraphics.SmoothingMode = SmoothingMode.HighQuality;
    objGraphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
    objGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
    objGraphics.CompositingQuality = CompositingQuality.HighQuality;
    objGraphics.DrawImage(sourceImage, 0, 0, Width, Height);

    // Save the file path, note we use png format to support png file
    objBitmap.Save(saveFilePath);
    }
    }
    }
    catch (Exception ex)
    {
    LogHelper.Log(“Create Thumbnail: ERROR:” + ex.Message + “\n” + ex.StackTrace);
    return false;
    }
    return true;
    }

    and here is the error:
    ERROR:The type initializer for ‘Gdip’ threw an exception.
    at System.Drawing.SafeNativeMethods.Gdip.GdipLoadImageFromDelegate_linux(StreamGetHeaderDelegate getHeader, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes, StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, IntPtr& image)
    at System.Drawing.Image.InitFromStream(Stream stream)
    at System.Drawing.Image.LoadFromStream(Stream stream, Boolean keepAlive)

  3. Carlossays:

    Hi, I’m noob with docker,
    I’d like to know how to run this commands in my docker file?

    I tried doing this, but nothing change:
    FROM microsoft/aspnetcore:2.0 AS base
    WORKDIR /app
    EXPOSE 80

    FROM microsoft/aspnetcore-build:2.0 AS build
    RUN apt-get update
    RUN apt-get install -y libgdiplus
    RUN cd /usr/lib
    RUN sudo ln -s libgdiplus.so gdiplus.dll
    WORKDIR /src
    COPY *.sln ./
    COPY NuGet.config ./
    COPY Core.MyApp.Api/Core.MyApp.Api.csproj Core.MyApp.Api/
    RUN dotnet restore Core.MyApp.Api/Core.MyApp.Api.csproj
    COPY . .
    WORKDIR /src/Core.MyApp.Api
    RUN dotnet build Core.MyApp.Api.csproj -c Release -o /app

    FROM build AS publish
    RUN dotnet publish Core.MyApp.Api.csproj -c Release -o /app

    FROM base AS final
    WORKDIR /app
    COPY –from=publish /app .
    ENTRYPOINT [“dotnet”, “Core.MyApp.dll”]

  4. Thank’s, I did what you said, but I have an issue regarding the color. The QrCode generated with QrCoder is weird under Linux (color not consistent and changes randomly).

    Code:

    var myLogo = new Bitmap(“./Assets/myLogo.png”);
    QRCodeGenerator qrGenerator = new QRCodeGenerator();
    QRCodeData qrCodeData = qrGenerator.CreateQrCode(id.ToString(), QRCodeGenerator.ECCLevel.Q);
    QRCode qrCode = new QRCode(qrCodeData);
    Bitmap qrCodeImage = qrCode.GetGraphic(6, ArgbToColor(“#FF3F729B”), ArgbToColor(“#FFFFFFFF”), myLogo, 17, 8, true);

    // Convert Bitmap to Png
    MemoryStream stream = new MemoryStream();
    qrCodeImage.Save(stream, ImageFormat.Png);
    stream.Flush();
    stream.Seek(0, SeekOrigin.Begin);

    return File(stream, “image/png”);

    • Hi Nordes,

      do the “changing colors” also occur if you use a color from the Color-class? (E.g. Color.Green instead of ArgbToColor(“#FF3F729B”) )

      Do you use the newest version of QRCoder? (Currently it is 1.3.2)

      Kind regards,
      Raffael

  5. jgmangalasays:

    thanks this helped me lot.

Leave a comment

Please be polite. We appreciate that. Your email address will not be published and required fields are marked