关于GDI / GDI +的协调兼容性?

在使用GDI和GDI +进行交互绘图时遇到问题。 页面转换(特别是缩放)似乎在两者之间稍微偏离了一点点。 GDI上下文的哪些属性影响除SetViewportExtSetWindowExt之外的输出的缩放?

该代码几乎只使用GDI绘制graphics,但在less数需要使用GDI +function(半透明)的情况下使用GDI +。 它使用SetViewportExtSetWindowExtSetViewportOrg来启用缩放和滚动。

当需要GDI +时,我会在HDC周围构build一个Gdiplus::Graphics对象并进行绘制。 我假设这使得graphics上下文包装设备上下文,并将其渲染中继到设备上下文。 如果我提取GDI +graphics上下文的变换matrix,我看到它是单位matrix,所以缩放是在其他地方完成的(在我猜的设备上下文中)。

我devise了一个简单的testing,用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轴上具有负偏移。

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

  • 我将如何去调查/debugging呢? 这发生在窗户的肠子,所以我不幸无法debugging它。

作为参考,这是我的视口/窗口组织/外部看起来像:

 Window Ext: (134000, 80500) Window Org: (0, 0) Viewport Ext: (1452 872) Viewport Org: (35 35) 

更新:

我已经解决了这个问题,但并不漂亮。 基本的方法是:

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

  2. 将GDI转换重置为MM_TEXT

  3. 使用变换后的点为GDI +构build一个代表相同变换的变换matrix

  4. 最后用这个matrix构build一个正确转换的GDI +上下文。

这是一个黑客,但它的作品。 尽pipe如此,我仍然不知道为什么两者有差别。 至less可以certificateGDI +上下文可以模拟GDI转换。

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

我遇到了与https://stackoverflow.com/a/4894969/700027相同的问题:打印时,GDI +(Gdiplus :: Graphics)的坐标与GDI(HDC)的坐标不匹配。

graphics.GetPageUnit()返回UnitDisplayUnitDisplay的文档是:

指定显示单位。 例如,如果显示设备是显示器,那么单位是1个像素。

我错误地认为,对于打印机, UnitDisplay将使用打印机点。 经过很多的斗争,我终于发现,它实际上是使用1/100英寸的原因不明。 如果我使用Gdiplus :: UnitPixel,则GDI +坐标与GDI坐标相同。

我们有同样的问题。

(背景:GDI几乎可以正常工作,而且我们的电子表格样式的显示效果要好得多,需要渲染1000个单元格的文本,但是我们需要GDI +来显示.jpg。)

在屏幕上显示内容时,GDI +缩放似乎是正确的。 我们有一个打印预览功能,它使用坐标转换,让应用程序使用打印机坐标呈现,但出现在屏幕上。 一切工作正常,直到我们把它发送到一个真正的打印机(或PDF作家)时,缩放得到了塞满。

经过一个星期的工作(并从你的解决方案中得到一个提示),这是我们的理解:

GDI +中存在一个错误,当您调用:“图形(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)的显示器和打印机DC进行测试。

 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); 

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

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

也许你特定的图形卡转换坐标的方式偏离了它在GDI +中发生的方式