.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