C++ 关于GDI/GDI+;协调兼容性?

C++ 关于GDI/GDI+;协调兼容性?,c++,windows,gdi+,gdi,C++,Windows,Gdi+,Gdi,我在交替使用GDI和GDI+绘图时遇到问题。页面转换(尤其是缩放)在两者之间似乎有点不协调。除了SetViewportExt和SetWindowExt之外,GDI上下文的哪些属性会影响输出的缩放 该代码的绘图几乎完全使用GDI,但在一些需要其功能(半透明)的情况下使用GDI+。它使用SetViewportExt、SetWindowExt和SetViewportOrg来启用缩放和滚动 当需要GDI+时,我在HDC周围构造一个Gdiplus::Graphics对象并进行绘图。我假设这会使图形上下文包

我在交替使用GDI和GDI+绘图时遇到问题。页面转换(尤其是缩放)在两者之间似乎有点不协调。除了
SetViewportExt
SetWindowExt
之外,GDI上下文的哪些属性会影响输出的缩放

该代码的绘图几乎完全使用GDI,但在一些需要其功能(半透明)的情况下使用GDI+。它使用
SetViewportExt
SetWindowExt
SetViewportOrg
来启用缩放和滚动

当需要GDI+时,我在HDC周围构造一个
Gdiplus::Graphics
对象并进行绘图。我假设这会使图形上下文包装设备上下文,并将其渲染中继到设备上下文。如果我提取GDI+图形上下文的转换矩阵,我会看到它是身份矩阵,所以缩放是在其他地方进行的(我猜是在设备上下文中)

我设计了一个简单的测试,在这个测试中,我用GDI和GDI+绘制相同的矩形数组,以确保所有的转换在这两种情况下都是相同的。代码片段如下所示:

CRect rect = ...;

// Draw the rectangle using GDI
CPen cpen(PS_DASH, 0, RGB(0,0,255));
pDC->SelectObject(&cpen);
pDC->Rectangle(rect);

{
    // Draw the rectangle using GDI+
    Gdiplus::Graphics graphics(pDC->m_hDC);

    Gdiplus::Pen pen(Gdiplus::Color(180,180,180));
    graphics.DrawRectangle(
        &pen,
        Gdiplus::Rect(rect.left, rect.top, rect.Width(), rect.Height()));
}
结果如下:(蓝色虚线由GDI绘制,灰色由GDI+绘制)

我可以清楚地看到这两个坐标系是不同的。我预期会出现一些舍入错误,但不像这里看到的那样是缩放错误。此外,当我更改缩放因子时,GDI+会在两个方向上跳跃±4个像素,具体取决于缩放。这也在屏幕截图中突出显示,因为与GDI矩形相比,GDI+矩形在X轴上有正偏移,在Y轴上有负偏移

  • 有人知道这里发生了什么吗

  • 我将如何着手调查/调试此问题?这是在windows内部发生的,所以很遗憾我无法调试它

作为参考,这是我的视口/窗口组织/外部的外观:

Window Ext: (134000, 80500)
Window Org: (0, 0)
Viewport Ext: (1452 872)
Viewport Org: (35 35)
更新: 我已经解决了这个问题,但不太好。基本方法是:

  • 在屏幕空间中获取两个坐标(原点和第二个适当的点),并使用GDI(
    DPtoLP
    函数)将它们转换为逻辑坐标

  • 将GDI转换重置为
    MM\u TEXT

  • 使用变换点为表示相同变换的GDI+构造变换矩阵

  • 最后使用这个矩阵构造一个具有正确转换的GDI+上下文


  • 这是一个有点黑客,但它的工作。不过,我还是不知道为什么两者之间会有区别。至少它表明,GDI+上下文可以模拟GDI转换。

    需要记住的一点是,大多数GDI通常在硬件上运行(即GDI功能映射到在硅上实现某些功能的显示驱动程序) GDI+本来应该得到硬件加速,但它仍然只是一个软件渲染器

    尝试通过GDI+和GDI手动设置几个像素,看看它们是否不同


    也许您的特定图形卡转换坐标的方式与GDI+中发生的方式不同,我们也遇到了同样的问题

    (背景:GDI几乎适用于所有方面,对于需要呈现1000个文本单元格的电子表格样式显示,它似乎要快得多。但是,我们需要GDI+来显示.jpg。)

    在屏幕上显示内容时,GDI+缩放似乎是正确的。我们有一个打印预览功能,它使用坐标变换让应用程序使用打印机坐标进行渲染,但显示在屏幕上。一切都很好,直到我们把它送到一个真正的打印机(或PDF编写器)时,缩放被塞满

    经过一周的工作(并从您的解决方案中得到提示),以下是我们的理解:

    GDI+中存在一个缺陷,当您调用“Graphics(HDC)”(从GDI设备上下文创建图形对象)时,其中HDC来自打印机或软件打印机,分辨率为6000 x 4000像素,然后GDI+忽略了HDC使用如此高分辨率的事实,而是应用了它自己的大约1000 x 800像素的分辨率

    因此,您的变通方法可能是解决该问题的正确且最佳的解决方案

    我们的解决方案类似,但有点不同,因为我们实际上不需要任何坐标变换:

            graphics.GetVisibleClipBounds(&rect);
            double deltaY = (double)GetPrinterH()/(double)rect.Height;
            double deltaX = (double)GetPrinterW()/(double)rect.Width;
            x1=x1/deltaX;
            x2=x2/deltaX;
            y1=y1/deltaY;
            y2=y2/deltaY;
            graphics.DrawImage(jpeg->image, x1,y1,x2-x1,y2-y1);
    

    在许多打印机驱动程序上,这些比例因子似乎非常接近“6”。

    我找到了解决打印问题的方法。请注意,示例中的图形对象没有设置任何世界空间变换,因此直接在页面空间中绘制

    将页面单位设置为英寸,然后将坐标转换为英寸似乎可以解决绘图问题,而无需进行大量额外工作。在不同的DPI(范围从72到4000)下使用显示器和打印机DCs进行测试


    简短回答:调用
    graphics.SetPageUnit(Gdiplus::UnitPixel)

    我遇到的问题与:打印时,GDI+(Gdiplus::Graphics)的坐标与GDI(HDC)的坐标不匹配

    graphics.GetPageUnit()
    正在返回
    UnitDisplay
    UnitDisplay
    的文档包括:

    指定显示单位。例如,如果显示设备是监视器,则单位为1像素


    我错误地认为,对于打印机,
    UnitDisplay
    将使用打印机点。经过一番努力,我终于发现它实际上使用了1/100英寸,原因不明。如果我使用Gdiplus::UnitPixel,那么GDI+坐标与GDI坐标相同。

    我收集了同样多的坐标,但我仍然不明白为什么GDI与GDI+之间有如此大的差异。(除非硬件加速是由图形卡驱动程序实现的,并且它有一个故障implem
    Gdiplus::Graphics graphics(..);
    Gdiplus::RectF    rect(0.0f, 0.0f, 1.0f, 1.0f);
    Gdiplus::REAL     dpiX = graphics.getDpiX();
    Gdiplus::REAL     dpiY = graphics.getDpiY();
    
    /* Logical coordinates to inches. In this example, the window extents are
       equal to the DC's DPI. You will have to convert to inches based on your
       specific configuration. */
    rect.X      /= dpiX;
    rect.Y      /= dpiY;
    rect.Width  /= dpiX;
    rect.Height /= dpiY;
    
    graphics.SetPageUnit(Gdiplus::UnitInch);
    graphics.FillRectangle(.., rect);