.NET Core 目前更新到2.2了,可是直到如今在 .NET Core 自己依然不包括和图片有关的 Image、Bitmap 等类型。对于图片的操做在咱们开发中很常见,好比:生成验证码、二维码等等。在 .NET Core 的早期版本中,有 .NET 社区开发者实现了一些 System.Drawing 的 Image等类型实现的组件,好比 CoreCompat.System.Drawing
、ZKWeb.System.Drawing
等。后来微软官方提供了一个组件 System.Drawing.Common
实现了 System.Drawing 的经常使用类型,以 Nuget 包的方式发布的。今天就围绕它来说一讲这里面的坑。html
在 .NET Core 中能够经过安装
System.Drawing.Common
来使用 Image、Bitmap 等类型。linux
本文将以一个 ASP.NET Core 项目使用 QRCoder
组件来生成一个二维码做为示例。git
dotnet add package QRCoder
QRCoder是一个很是强大的生成二维码的组件,它使用了 System.Drawing.Common
,因此安装它用来作测试。github
ValuesController
,添加以下代码:[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { [HttpGet] public FileResult Get() { QRCodeGenerator.ECCLevel eccLevel = QRCodeGenerator.ECCLevel.L; using (QRCodeGenerator qrGenerator = new QRCodeGenerator()) { using (QRCodeData qrCodeData = qrGenerator.CreateQrCode("Hello .NET Core", eccLevel)) { using (QRCode qrCode = new QRCode(qrCodeData)) { Bitmap bp = qrCode.GetGraphic(20, Color.Black, Color.White,true); return File(Bitmap2Byte(bp), "image/png", "hello-dotnetcore.png"); } } } } public static byte[] Bitmap2Byte(Bitmap bitmap) { using (MemoryStream stream = new MemoryStream()) { bitmap.Save(stream, ImageFormat.Jpeg); byte[] data = new byte[stream.Length]; stream.Seek(0, SeekOrigin.Begin); stream.Read(data, 0, Convert.ToInt32(stream.Length)); return data; } }
上面的代码生成了一个二维码,经过API返回,文件名为 hello-dotnetcore.pngdocker
在 Windows 环境下咱们直接运行,打开浏览器访问 http://localhost:5000/api/values
shell
查看该图片:ubuntu
一切正常windows
Docker(Linux)指:以Linux系统为基础的镜像centos
咱们将代码原封不动的拷贝到 Linux 上运行api
使用curl访问
curl http://localhost:5000/api/values
查看日志输出能够见到报错了
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1] An unhandled exception has occurred while executing the request. System.TypeInitializationException: The type initializer for 'Gdip' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'libgdiplus': The specified module could not be found.
该异常的意思是: 找不到DLL libgdiplus,如何解决?请看下一小节。
System.Drawing.Common
组件提供对GDI+图形功能的访问。它是依赖于GDI+的,那么在Linux上它如何使用GDI+,由于Linux上是没有GDI+的。Mono 团队使用C语言实现了GDI+接口,提供对非Windows系统的GDI+接口访问能力(我的认为是模拟GDI+,与系统图像接口对接),这个就是 libgdiplus
。进而能够推测 System.Drawing.Common
这个组件实现时,对于非Windows系统确定依赖了 ligdiplus
这个组件。若是咱们当前系统不存在这个组件,那么天然会报错,找不到它,安装它便可解决。
libgdiplus github: https://github.com/mono/libgdiplus
#一键命令 sudo curl https://raw.githubusercontent.com/stulzq/awesome-dotnetcore-image/master/install/centos7.sh|sh
或者
yum update yum install libgdiplus-devel -y ln -s /usr/lib64/libgdiplus.so /usr/lib/gdiplus.dll ln -s /usr/lib64/libgdiplus.so /usr/lib64/gdiplus.dll
#一键命令 sudo curl https://raw.githubusercontent.com/stulzq/awesome-dotnetcore-image/master/install/ubuntu.sh|sh
或者
apt-get update apt-get install libgdiplus -y ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll
Dockerfile 加入 RUN 命令,以官方 asp.net core runtime 镜像,以 asp.net core 2.2 做为示例:
FROM microsoft/dotnet:2.2.0-aspnetcore-runtime WORKDIR /app COPY . . RUN apt-get update -y && apt-get install -y libgdiplus && apt-get clean && ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll EXPOSE 80 ENTRYPOINT ["dotnet", "<你的入口程序集>"]
apt-get update 这一步是必不可少的,否则会报找不到 libgdiplus。可是官方镜像里面使用的软件包源又是国外的地址,因此形成咱们使用国内网络很是慢,进而形成总体构建过程很是慢。下面有两个解决方案:
该镜像是基于微软官方镜像打包的,只安装了 libgdiplus
,不添加任何添加剂。
将 Dockerfile 中的 FROM microsoft/dotnet:2.2.0-aspnetcore-runtime
换为 FROM stulzq/dotnet:2.2.0-aspnetcore-runtime-with-image
示例:
FROM stulzq/dotnet:2.2.0-aspnetcore-runtime-with-image WORKDIR /app COPY . . EXPOSE 80 ENTRYPOINT ["dotnet", "<你的入口程序集>"]
此方法请看我之前写的文章:Docker实用技巧之更改软件包源提高构建速度
首先查询下是否有编译好的 libgdiplus,若是没有能够到官方github查看教程,使用源码编译。
这里要说明一下在 .NET Core 下,并不是全部与图片操做有关的都须要安装 libgdiplus,只有你使用的组件依赖于 它提供的GDI+能力(依赖于它)才有必要装它。就好比你要是用 Image、Bitmap 类型,你就得安装 System.Drawing.Common
;或者你用的组件依赖了 System.Drawing.Common
,好比 QRCoder
。
有一些能够用于 .NET Core 的图片处理组件,自身没有依赖于 System.Drawing.Common
,也没有依赖于 GDI+,使用它们是无需注意libgdiplus
这个问题的,好比 ImageSharp
,它使用纯C#实现了一些图片底层操做。
SkiaSharp 一样是能够进行图片操做的组件,在Linux上须要安装libSkiaSharp,SkiaSharp是由mono项目组提供的。我没有深刻研究这个库,有兴趣的同窗能够研究一下。
有些同窗可能遇到使用了命令无效的问题,据我猜想多是包源或者是你自己环境致使安装失败,目前给出的解决办法有两个,一个是clone github源码编译安装,一个是下载离线包安装:https://pkgs.org/download/libgdiplus
本文所诉问题,实际上是个老问题了,网上也都有解决方案,本文是搁置好久(一直处于未编辑完状态)才发布的,这里就算作个总结吧。
本文所用测试代码、shell命令、以及 Dockerfile 都在github: https://github.com/stulzq/dotnetcore-image 若是以为有用欢迎 Star