WMF文件转C# Bitmap出现拉伸失真问题求助(可修改C++/C#两端代码)
WMF文件转C# Bitmap出现拉伸失真问题求助(可修改C++/C#两端代码)
你好,我之前处理过类似的WMF/EMF缩放失真问题,这种拉伸问题几乎肯定是因为你在C#代码里硬编码了固定宽高,没有尊重元文件本身的原生比例和分辨率信息。结合你两边都能修改代码的情况,给你几个可落地的解决方案:
方案1:C#端读取WMF原始尺寸,按比例绘制(改动最小,优先尝试)
WMF是矢量格式,自带物理尺寸和DPI信息,直接硬写width/height会强制扭曲它的原生比例。我们可以先读取WMF的原始参数,计算出匹配的像素尺寸后再绘制:
using (var wmf = new Metafile(path)) { // 获取WMF的原生DPI和物理尺寸(单位:0.01毫米) float nativeDpiX = wmf.HorizontalResolution; float nativeDpiY = wmf.VerticalResolution; // 转换逻辑:1英寸=25.4毫米,将物理尺寸转成匹配原生DPI的像素 int targetWidth = (int)Math.Round(wmf.Width * nativeDpiX / (25.4f * 100f)); int targetHeight = (int)Math.Round(wmf.Height * nativeDpiY / (25.4f * 100f)); using (var bitmap = new Bitmap(targetWidth, targetHeight)) { using (var g = Graphics.FromImage(bitmap)) { // 开启高质量绘制选项,提升最终BMP清晰度 g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; g.Clear(Color.White); // 可选:设置背景色避免透明区域异常 // 按原生比例绘制,无拉伸 g.DrawImage(wmf, new Rectangle(0, 0, targetWidth, targetHeight)); var bmpPath = path.Replace("wmf", "bmp"); bitmap.Save(bmpPath, System.Drawing.Imaging.ImageFormat.Bmp); // 插入Excel时也用计算后的尺寸,避免二次拉伸 chartSheet.Pictures.AddPicture(bitmap, chartSheet.Cells[cell], 0, 0, targetWidth, targetHeight); } } }
方案2:C#端直接使用WMF/EMF,跳过BMP转换(最优解,若场景允许)
如果你的C#场景(比如Excel的Pictures.AddPicture)支持直接插入矢量元文件,完全不用转BMP——矢量图本身不会有拉伸失真问题,还能保持缩放清晰度:
// 直接插入WMF到Excel,使用原生尺寸 var pic = chartSheet.Pictures.AddPicture( filename: path, linkToFile: false, saveWithDocument: true, left: chartSheet.Cells[cell].Left, top: chartSheet.Cells[cell].Top, width: Type.Missing, // 传Type.Missing让Excel自动使用WMF原生宽度 height: Type.Missing // 传Type.Missing让Excel自动使用WMF原生高度 );
方案3:C++端优化元文件生成,保证尺寸信息准确
你当前用CopyMetaFile直接复制元文件,可能原始的hMFDist本身的边界信息不完整。如果生成EMF,建议用增强型元文件API,确保写入准确的边界数据:
// 替换原有的CopyMetaFile逻辑,生成带准确边界的EMF CString distChartMeta = _T("DistChartMeta.emf"); RECT rcBounds = {0}; // 先读取原始元文件的边界信息 METAFILEPICT* mfp = (METAFILEPICT*)GlobalLock(GetMetaFileBitsEx(hMFDist, 0, NULL, 0)); if (mfp != nullptr) { // 提取原始元文件的尺寸作为边界 rcBounds.right = mfp->mfxExt; rcBounds.bottom = mfp->mfyExt; GlobalUnlock(mfp); } else { // 兜底:设置默认边界(如果无法读取原始信息) SetRect(&rcBounds, 0, 0, 1000, 800); } // 创建带准确边界的增强型元文件DC HDC hdcEnh = CreateEnhMetaFile( NULL, _T(temp + distChartMeta), &rcBounds, _T("Your App Name") // 可选:元文件的描述信息 ); if (hdcEnh != nullptr) { // 将原始元文件回放至增强型元文件DC PlayMetaFile(hdcEnh, hMFDist); // 关闭DC并获取增强型元文件句柄 HMETAFILE hMFEnh = CloseEnhMetaFile(hdcEnh); if (hMFEnh != nullptr) { // 保存增强型元文件 CopyEnhMetaFile(hMFEnh, _T(temp + distChartMeta)); DeleteMetaFile(hMFEnh); } }
这样生成的EMF会包含完整的尺寸元数据,C#读取时能正确识别原生比例,不会出现拉伸。
额外排查小技巧
- 用Windows自带的画图打开原始WMF,查看「属性」里的宽高比,对比你C#中硬编码的
width/height比例是否一致——如果比例不同,必然会拉伸。 - 用MetaEdit这类工具打开WMF/EMF,检查它的
METAFILEPICT结构中的mfxExt/mfyExt值,确认尺寸信息是否正确。
如果还有问题,可以补充原始WMF的尺寸属性信息,我再帮你细化方案!




