
简介这份资源是面向Kylin操作系统用户的LibGdiPlus安装与配置文档适合需要在国产Linux环境下运行依赖Windows GDI库的跨平台应用的开发者与运维人员。文档围绕仓库源修改、依赖库安装、源码下载编译、错误处理及环境变量配置等环节展开帮助读者解决LibGdiPlus在Kylin上编译失败或库文件缺失等常见问题。资源包内共1个docx文件大小约807KB内容以图文步骤形式呈现涵盖libtiff-dev、libjpeg-dev、libgif-dev等依赖的安装命令以及configure、make、make install的完整流程并针对编译异常给出将.libs目录下文件复制到/usr/lib的排错思路。目前已有571人学习下载适合作为Kylin系统下LibGdiPlus部署的实操参考帮助读者快速完成环境搭建与验证。1. Kylin 上装 libgdiplus为什么 .NET 图像处理一到国产系统就翻车在 Kylin Linux Advanced Server V10 (Halberd) 上部署 .NET 应用最容易被忽略、又最容易在验收前夜爆雷的一环就是 libgdiplus 的安装与配置。现象很统一Windows 上跑得好好的报表导出、验证码生成、图片水印、PDF 转图迁到 Kylin 之后直接抛System.Drawing相关异常或者干脆进程崩掉。很多人第一反应是 .NET 运行时不兼容其实根子在 libgdiplus——它是 System.Drawing 在 Linux 上依赖的 GDI 兼容层缺了它所有基于 GDI 的绘图调用都是空中楼阁。这篇笔记面向三类人正在做 .NET 应用国产化迁移的工程师、需要在 Kylin Server V10 上跑图像/报表服务的运维、以及被libgdiplus依赖问题卡住的后端开发。我会把「这是什么、为什么 Kylin 上特别容易出问题、怎么装、参数怎么配、坑在哪」按可复现的顺序讲清楚。Kylin 的软件源和通用发行版有差异直接照搬 Ubuntu 的apt install libgdiplus大概率失败这也是后面要重点处理的点。2. 先搞清楚 libgdiplus 在 Kylin 上到底扮演什么角色2.1 System.Drawing 与 libgdiplus 的依赖关系.NET 在 Windows 上System.Drawing.Common直接调用系统自带的 GDIgdiplus.dll。到了 Linux微软没有重写一套绘图引擎而是让System.Drawing.Common通过 P/Invoke 去调用一个叫 libgdiplus 的本地库这个库由 Mono 项目维护用 C 实现了一套 GDI 的兼容接口底层再对接 Cairo、FreeType、libpng、libjpeg 这些图形库。所以链路的完整形态是你的 C# 代码 → System.Drawing.Common → libgdiplus.so → Cairo/FreeType → 输出位图。任何一环缺失报错信息都不会直接告诉你「libgdiplus 没装」而是抛TypeInitializationException或DllNotFoundException: libgdiplus这就是它被称为黑匣子的原因。Kylin V10 默认不带这个库也不在基础镜像里必须手动补。需要说明的是.NET 6 之后System.Drawing.Common在非 Windows 平台被标记为仅 Windows 支持但通过设置运行时配置开关System.Drawing.EnableUnixSupporttrue仍可在 Linux 使用底层依然依赖 libgdiplus。这是 Kylin 上跑图像服务的现实路径短期内没有更省事的替代。2.2 为什么 Kylin V10 的源里经常找不到它Kylin Linux Advanced Server V10 (Halberd) 基于较新的内核4.x 及以上软件源以自研和信创适配为主第三方图形库的收录策略和 CentOS、Ubuntu 不同。常见情况有三种一是源里根本没有 libgdiplus 包二是只有旧版本和当前 .NET 运行时的 ABI 对不上三是包名不叫 libgdiplus而是带版本后缀或放在 extras 仓库里。判断方法很直接先查再装不要盲装# 查看当前系统版本确认是 Kylin V10 哪个小版本 cat /etc/kylin-release cat /etc/os-release # 在已启用的源里搜索 libgdiplus注意大小写和可能的包名变体 yum search libgdiplus yum list available | grep -i gdiplus # 如果 yum 搜不到用 dnf 再确认一次Kylin V10 通常两者都有 dnf search libgdiplus如果两条搜索命令都返回空说明当前源里确实没有需要走源码编译或引入兼容源这两条路在第 3 章展开。这里先记住一个判断原则能装包就不要编译能编译就不要混源。混源在 Kylin 上引发依赖冲突的概率远高于通用发行版血泪经验。2.3 装之前必须确认的三件事动手之前先花五分钟确认环境能省掉后面大量排查时间。第一确认 .NET 运行时版本不同版本对 libgdiplus 的最低版本要求不同第二确认是否真的需要 System.Drawing如果只是处理图片元数据用 ImageSharp 或 SkiaSharp 可以完全绕开 libgdiplus第三确认有没有 root 或 sudo 权限编译安装涉及写/usr/local/lib和刷新动态链接缓存。# 确认 .NET 运行时和 SDK 版本 dotnet --info # 确认系统架构Kylin V10 有 x86_64 和 aarch64 两种编译参数不同 uname -m # 确认关键图形依赖是否已存在libgdiplus 编译时需要它们 rpm -qa | grep -E cairo|freetype|libpng|libjpeg|glib2|fontconfig如果cairo、freetype这些开发包注意是-devel结尾的缺失编译 libgdiplus 会在 configure 阶段直接失败。这一步的输出建议留存后面排错时对照用。3. 在 Kylin V10 上把 libgdiplus 装起来的三种路径3.1 路径一源内直接安装最省事优先尝试如果 2.2 的搜索命令能命中包直接装即可。Kylin V10 上包名通常是libgdiplus或libgdiplus0装完刷新链接缓存并验证。# 安装 libgdiplus-y 自动确认 sudo yum install -y libgdiplus # 如果提示找不到尝试带版本后缀的包名 sudo yum install -y libgdiplus0 # 刷新动态链接库缓存让新装的 .so 立即生效 sudo ldconfig # 验证库是否被系统识别 ldconfig -p | grep gdiplusldconfig -p能列出libgdiplus.so就说明动态链接器已经认识它了。这一步的关键参数是-p它打印当前缓存中的所有库比find / -name快得多。如果这里没有输出即使 rpm 显示已安装运行时照样找不到问题多半出在库路径没进缓存。装完别急着跑应用先用一个小测试确认 .NET 能真正调用到它避免后面把库问题和代码问题混在一起排查。# 建一个最小测试项目 mkdir -p /tmp/gdiptest cd /tmp/gdiptest dotnet new console -n GdiTest cd GdiTest # 添加 System.Drawing.Common 包 dotnet add package System.Drawing.Common把Program.cs改成下面这样生成一张 100x100 的位图并保存using System.Drawing; using System.Drawing.Imaging; // 创建位图并填充验证 GDI 调用链是否打通 using var bmp new Bitmap(100, 100); using (var g Graphics.FromImage(bmp)) { g.Clear(Color.White); g.DrawString(Kylin, SystemFonts.DefaultFont, Brushes.Black, 10, 40); } bmp.Save(/tmp/gdiptest/out.png, ImageFormat.Png); Console.WriteLine(OK);运行前必须在项目文件或运行时配置里打开 Unix 支持开关否则 .NET 6 会直接拒绝执行# 方式一运行时环境变量推荐不改代码 export DOTNET_SYSTEM_DRAWING_ENABLEUNIXSUPPORT1 dotnet run # 方式二在 .csproj 里写死适合容器镜像 # PropertyGroup # EnableUnixSupporttrue/EnableUnixSupport # /PropertyGroup看到OK且/tmp/gdiptest/out.png生成说明整条链路通了。如果抛DllNotFoundException回到ldconfig -p那步如果抛PlatformNotSupportedException是开关没生效检查环境变量拼写。3.2 路径二源码编译源里没有时的主力方案源里搜不到就只能编译。libgdiplus 的源码由 Mono 项目维护编译依赖 cairo、freetype、libpng、libjpeg、glib2、fontconfig 的开发包。Kylin V10 上先把这些依赖补齐# 安装编译依赖-devel 结尾的是开发头文件缺一不可 sudo yum install -y gcc gcc-c make autoconf automake libtool pkgconfig sudo yum install -y cairo-devel freetype-devel libpng-devel libjpeg-turbo-devel sudo yum install -y glib2-devel fontconfig-devel libtiff-devel libexif-devel依赖装完后获取源码、配置、编译、安装。configure 阶段的参数决定库装到哪、支持哪些格式是整条路径里最需要盯的地方# 获取源码用你手头可信的源码包解压后进入目录 tar -xzf libgdiplus-*.tar.gz cd libgdiplus-* # 生成 configure 脚本 ./autogen.sh # 配置指定安装前缀开启需要的图像格式支持 ./configure \ --prefix/usr/local \ --with-cairoyes \ --with-freetypeyes \ --with-libpngyes \ --with-libjpegyes \ --with-tiffyes \ --with-exifyes # 编译-j 后跟 CPU 核数加快速度 make -j$(nproc) # 安装到 /usr/local sudo make install # 刷新动态链接缓存 sudo ldconfig参数说明--prefix/usr/local把库装到/usr/local/lib这是非包管理器安装的惯例位置不会和系统包冲突--with-*系列控制支持的图像格式如果你的应用只处理 PNG可以关掉 jpeg 和 tiff 减少依赖但报表场景通常需要 jpeg建议全开。make -j$(nproc)里的$(nproc)自动取核数核多的机器编译快很多。编译完成后/usr/local/lib下会出现libgdiplus.so但系统默认的库搜索路径不一定包含它。Kylin V10 上需要显式告诉动态链接器# 写入自定义库路径配置 echo /usr/local/lib | sudo tee /etc/ld.so.conf.d/libgdiplus.conf # 重新生成缓存 sudo ldconfig # 再次验证 ldconfig -p | grep gdiplus如果ldconfig -p还是看不到检查/usr/local/lib下是不是只有libgdiplus.so.0.0.0而没有libgdiplus.so软链缺软链的话手动补一个cd /usr/local/lib sudo ln -sf libgdiplus.so.0.0.0 libgdiplus.so sudo ldconfig3.3 路径三容器镜像里预置适合批量部署如果应用跑在容器里把 libgdiplus 编进基础镜像比每次启动装更稳。Dockerfile 里分两层一层装编译依赖并编译一层只拷贝产物减小最终镜像体积。# 构建阶段编译 libgdiplus FROM kylin-server-v10:latest AS builder RUN yum install -y gcc gcc-c make autoconf automake libtool pkgconfig \ cairo-devel freetype-devel libpng-devel libjpeg-turbo-devel \ glib2-devel fontconfig-devel COPY libgdiplus-src /src WORKDIR /src RUN ./autogen.sh ./configure --prefix/usr/local make -j$(nproc) make install # 运行阶段只带运行时依赖和编译产物 FROM kylin-server-v10:latest RUN yum install -y cairo freetype libpng libjpeg-turbo glib2 fontconfig COPY --frombuilder /usr/local/lib/libgdiplus.so* /usr/local/lib/ RUN echo /usr/local/lib /etc/ld.so.conf.d/libgdiplus.conf ldconfig ENV DOTNET_SYSTEM_DRAWING_ENABLEUNIXSUPPORT1这个写法的关键是运行阶段只装运行时库不带-devel把编译工具链留在构建阶段最终镜像能小几百 MB。ENV那行把 Unix 支持开关固化进镜像避免每次部署漏设环境变量。注意基础镜像 tag 按你实际使用的 Kylin 版本替换不要照抄。4. 配置参数与运行时开关让 .NET 真正用上它4.1 三个必须设对的运行时配置装好库只是第一步.NET 运行时还有几个开关决定它愿不愿意走 libgdiplus。第一个是DOTNET_SYSTEM_DRAWING_ENABLEUNIXSUPPORT.NET 6 必须设为1或true否则直接抛平台不支持。第二个是字体配置Kylin 上如果没装中文字体DrawString画出来的中文全是方框这不是 libgdiplus 的锅是 fontconfig 找不到字体。第三个是临时目录权限libgdiplus 处理某些格式时会写临时文件容器里/tmp不可写会静默失败。# 运行时开关写进 systemd 服务或容器环境变量 export DOTNET_SYSTEM_DRAWING_ENABLEUNIXSUPPORT1 # 确认系统有中文字体没有就装 fc-list :langzh | head # 如果为空安装字体包 sudo yum install -y wqy-zenhei-fonts wqy-microhei-fonts # 刷新字体缓存 fc-cache -fvfc-list :langzh列出所有支持中文的字体输出为空说明字体缺失。fc-cache -fv的-f强制重建、-v显示过程字体装完必须刷缓存否则新字体不生效。4.2 用配置文件替代环境变量的写法生产环境更推荐把开关写进runtimeconfig.json或.csproj避免依赖启动脚本。在.csproj里加ItemGroup !-- 让 System.Drawing.Common 在 Linux 上可用 -- RuntimeHostConfigurationOption IncludeSystem.Drawing.EnableUnixSupport Valuetrue / /ItemGroup这样编译出来的runtimeconfig.json会带上这个开关部署时不用再设环境变量。参数名必须和运行时识别的键完全一致大小写敏感写错一个字母就静默失效这是最容易翻车的地方。4.3 验证配置是否真正生效配置完不要只看应用能不能跑要做一次针对性验证确认走的是 libgdiplus 而不是某个降级路径。最直接的办法是查进程加载了哪些动态库# 启动应用后找到进程 PID ps -ef | grep dotnet # 查看该进程加载的动态库确认 libgdiplus 在列 sudo lsof -p PID | grep gdiplus # 或者用 pmap 看内存映射 pmap PID | grep gdipluslsof -p列出进程打开的所有文件包括动态库能看到libgdiplus.so就说明运行时确实加载了它。如果这里没有即使应用没报错也可能走的是别的路径或者根本没触发绘图逻辑需要构造一个真实的绘图调用再验证。5. 避坑与排查Kylin 上装 libgdiplus 的五个高频翻车点5.1 现象装完库应用仍抛 DllNotFoundException原因库文件在磁盘上但不在动态链接器的搜索路径里或者ldconfig缓存没刷新。Kylin V10 上/usr/local/lib默认不一定在搜索路径内。解决确认/etc/ld.so.conf.d/下有指向库目录的配置文件然后sudo ldconfig再用ldconfig -p | grep gdiplus确认。如果库文件名缺.so软链手动补链后重新ldconfig。5.2 现象抛 PlatformNotSupportedException提示仅支持 Windows原因.NET 6 默认禁用了 Unix 上的 System.Drawing开关没设或设错。解决设DOTNET_SYSTEM_DRAWING_ENABLEUNIXSUPPORT1或在.csproj里加RuntimeHostConfigurationOption。注意环境变量名全大写、下划线分隔写进 systemd 服务时放在Environment行。5.3 现象中文全部渲染成方框或乱码原因系统缺中文字体fontconfig 找不到可用字体libgdiplus 回退到默认字体中文无法显示。解决fc-list :langzh确认字体缺则装wqy-zenhei-fonts装完fc-cache -fv刷缓存。容器镜像里字体要显式 COPY 或安装基础镜像通常不带。5.4 现象编译 libgdiplus 时 configure 报找不到 cairo 或 freetype原因只装了运行时库没装-devel开发包头文件缺失。解决yum install cairo-devel freetype-devel libpng-devel libjpeg-turbo-devel glib2-devel fontconfig-devel装完重新./configure。configure 的报错信息会明确说缺哪个包照着补即可。5.5 现象混用第三方源后 yum 依赖冲突系统包被降级原因为找 libgdiplus 引入了不兼容的第三方源导致 glibc 等基础库被替换。解决Kylin 上尽量只用官方源源里没有就源码编译不要为了省事混源。已经冲突的话yum history查看操作记录用yum history undo回滚别硬扛。6. 进阶把 libgdiplus 依赖收敛成可复现的部署单元装一次不算本事能在多台 Kylin 机器、多个环境里稳定复现才算。我一般会把整个安装过程固化成一个脚本加一份校验清单而不是靠记忆敲命令。脚本负责装依赖、编译、刷缓存校验清单负责在部署后自动确认库、字体、开关三件事都到位。#!/bin/bash # kylin-libgdiplus-setup.sh set -e # 1. 装编译依赖 yum install -y gcc gcc-c make autoconf automake libtool pkgconfig \ cairo-devel freetype-devel libpng-devel libjpeg-turbo-devel \ glib2-devel fontconfig-devel wqy-zenhei-fonts # 2. 编译安装 libgdiplus cd /tmp/libgdiplus-src ./autogen.sh ./configure --prefix/usr/local make -j$(nproc) make install # 3. 配置库路径并刷新缓存 echo /usr/local/lib /etc/ld.so.conf.d/libgdiplus.conf ldconfig # 4. 刷新字体缓存 fc-cache -fv # 5. 自检 ldconfig -p | grep -q gdiplus echo libgdiplus OK || { echo libgdiplus FAIL; exit 1; } fc-list :langzh | grep -q . echo font OK || { echo font FAIL; exit 1; }脚本里set -e让任何一步失败立即退出避免带着半成品继续。自检部分用grep -q静默判断失败就非零退出方便接进 CI 或配置管理工具。这套东西我一般会连同.csproj里的 Unix 支持开关一起提交到仓库新机器拉下来跑一遍脚本就能用比写一堆文档靠谱。一个具体技巧把 libgdiplus 的版本号也纳入自检。不同版本对某些图像格式的支持有差异部署环境版本不一致会导致「这台机器能跑那台不能跑」的玄学问题。在脚本里加一行strings /usr/local/lib/libgdiplus.so | grep -i version | head记录版本出问题时第一时间能对比。最后说个我踩过的坑曾经为了图快在一台机器上手动cp了另一台编译好的libgdiplus.so结果因为两台机器的 cairo 版本不同运行时直接段错误排查了大半天。从那以后我坚持每台机器本地编译或者用统一的基础镜像不再跨机器拷贝二进制。这个习惯帮我省掉了后面无数次「为什么这台行那台不行」的追问。希望帮到你。本文还有配套的精品资源点击获取