【问题标题】:Graphics.DrawImage on High DPI 150%+ Only Draws Portion of the Image高 DPI 150%+ 上的 Graphics.DrawImage 仅绘制图像的一部分
【发布时间】:2019-10-18 18:45:13
【问题描述】:

此问题发生在使用 175% 缩放或更高目标的 .Net 4.7.2 的 Windows 10 Creators Update 或更高版本上。此外,我们在 Program.cs 文件中调用 SetProcessDPIAware。

如果我们不这样称呼,那么字体在高 DPI 上看起来很糟糕,尤其是在 300% 时。

static class Program
{
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern bool SetProcessDPIAware();

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        //if (Environment.OSVersion.Version.Major >= 6)
        SetProcessDPIAware();

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

重要步骤 我们还进入高级缩放设置并关闭功能“让窗口尝试修复应用程序,使其不模糊”......因为我们有用户将其关闭。 Image of the Windows Setting

在下面的应用程序中,我们有 3 个 PictureBox 控件。 最左边的 PictureBox 是来源,他的图像是一个以 96 dpi 创建的 PNG 文件。

用户单击中间 PictureBox 上方的按钮将源图像复制到 Metafile(用作绘图画布)并使用它来填充中间 PictureBox 的 Image 属性。在高 DPI 中,您可以看到图像大小不合适或仅将图像的一部分复制到图元文件中。

最右侧 PictureBox 上方的按钮使用 Bitmap 作为绘图画布复制源 Image。他以 175% 正确渲染。

Picture of Application Results

这是将源图像转换为元文件并将其粘贴到另一个 PictureBox 中的代码。

      private void DrawUsingMetafile()
    {
        try
        {
            Image img = this.pictureBox1.Image;

            Metafile mf = NewMetafile();

            using (Graphics gmf = Graphics.FromImage(mf))
            {
                gmf.DrawImage(img, 0, 0, img.Width, img.Height);
            }

            this.pictureBox2.Image = mf;
        }
        catch (Exception ex)
        {

            MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

}

        public static Metafile NewMetafile()
    {
        using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))  // offscreen device context
        {
            IntPtr hdc = g.GetHdc(); // gets released by g.Dispose() called by using g
            return new Metafile(hdc, EmfType.EmfPlusOnly);
        }
    }

任何想法为什么会发生这种情况?

【问题讨论】:

  • 该构造函数创建一个带有MetafileFrameUnit.GdiCompatible 的元文件(这也意味着单位转换)。使用this other constructor(并可能让您应用 DPIAware)。
  • 否则你总是冒着这样的结局:Image is not drawn at the correct spot
  • Jimi,有没有办法在不指定大小矩形的情况下使用 MetafileFrameUnit.Pixel 获取图元文件?在这个简化的示例中,您预先知道大小......但一般来说,我们不知道大小,这就是我们使用不需要的构造函数的原因。查看 .NET 源代码,看起来 Gdip.GdipRecordMetafile 允许您将 NullHandleRef 与 MetafileFrameUnit 一起传递给 FrameRect。但是唯一使用需要文件或流的 Metafile 构造函数......我们希望在内存中执行此操作。有办法吗?
  • Jimi,或者有没有办法在构建 Metafile 之后更改 MetafileFrameUnit?
  • 流也可以是MemoryStream(它不需要是文件流)。这在构造函数中经常使用,如下所示:Metafile mf = new Metafile([MemoryStream], hDC, image.GetBounds(ref unit), MetafileFrameUnit.Pixel, EmfType.EmfPlusDual, "Metafile description");.

标签: .net winforms dpi hdpi .net-4.7.2


【解决方案1】:

仅供参考 - Microsoft 确认这是 .Net 4.8 中的一个错误。仅当您关闭功能“让 Windows 尝试修复应用程序以使其不模糊”时才会出现问题他们确认了该问题并对其进行了修补,但尚未发布该修复程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-20
    相关资源
    最近更新 更多