C++ 关于GDI/GDI+;协调兼容性?
我在交替使用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对象并进行绘图。我假设这会使图形上下文包
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)
更新:
我已经解决了这个问题,但不太好。基本方法是:
DPtoLP
函数)将它们转换为逻辑坐标MM\u TEXT
这是一个有点黑客,但它的工作。不过,我还是不知道为什么两者之间会有区别。至少它表明,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);