System.Drawing.Image.FromStream在不同操作系统下返回图片分辨率存在差异
关于EnhMetaFile在不同Windows系统下栅格化尺寸不一致的解决方案
问题根因
- 你使用的
EnhMetaFileBits获取的是增强元文件(EMF)矢量数据,本身无固定像素尺寸,Image.FromStream读取时会自动采用当前系统的默认DPI完成矢量到位图的转换,不同系统的DPI配置差异会直接导致输出位图尺寸不同 - Windows Server 2012R2默认对未显式声明DPI感知的程序开启DPI虚拟化,且基础显示驱动默认输出DPI远低于Windows 10专业版的完整驱动配置,因此会得到低分辨率小尺寸位图
- 若程序运行在Server的非交互式服务会话中,GDI+默认会采用最低标准的DPI配置做栅格化,和登录用户的显示配置无关
最优解决方案
无需修改系统配置,手动指定目标DPI完成EMF栅格化,完全屏蔽系统差异,示例代码如下:
using System.Drawing; using System.Drawing.Imaging; byte[] bits = page.EnhMetaFileBits; using (var ms = new MemoryStream(bits)) using (var metafile = new Metafile(ms)) { // 按需设置目标DPI,此处用你Windows 10环境的600DPI为例 const int TargetDpi = 600; // 基于EMF原始物理尺寸计算目标像素宽高 float widthInInch = metafile.Width / metafile.HorizontalResolution; float heightInInch = metafile.Height / metafile.VerticalResolution; int targetPixelWidth = (int)Math.Round(widthInInch * TargetDpi); int targetPixelHeight = (int)Math.Round(heightInInch * TargetDpi); // 手动创建指定分辨率的位图并绘制EMF内容 using (var targetBitmap = new Bitmap(targetPixelWidth, targetPixelHeight)) { targetBitmap.SetResolution(TargetDpi, TargetDpi); using (var graphics = Graphics.FromImage(targetBitmap)) { graphics.Clear(Color.White); graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; graphics.DrawImage(metafile, new Rectangle(0, 0, targetPixelWidth, targetPixelHeight)); } // 后续直接使用targetBitmap即可,不受系统配置影响 } }
系统配置修改方案(不推荐)
如果要兼容原有代码不做修改,可调整对应系统配置:
- 安装完整的显卡驱动,避免使用Windows Server默认的基本显示驱动
- 打开控制面板→显示,将缩放比例调整至和Windows 10一致的级别,调整后重启系统生效
- 给程序添加高DPI感知声明,在项目的app.manifest文件中取消DPI感知相关配置的注释,避免系统触发DPI虚拟化
- 若程序运行在服务中,此方案无效,必须使用手动栅格化的方案
内容的提问来源于stack exchange,提问作者Ter Ser
相关产品推荐
相关产品推荐

