C++ 通过EM_FORMATRANGE缩放rich edit控件的渲染输出时出现舍入错误

C++ 通过EM_FORMATRANGE缩放rich edit控件的渲染输出时出现舍入错误,c++,c,windows,winapi,richtextbox,C++,C,Windows,Winapi,Richtextbox,我使用该消息将富格文本控件的输出呈现到任意设备上下文。但是,渲染到位图时,位图设备上下文的每英寸点数与显示设备的DPI相同,即每英寸96点。这比我想渲染的要低得多。我宁愿以更高的DPI渲染,这样用户可以放大,也许以后可以在高DPI打印机上打印 我怀疑RTF控件调用LOGPIXELSX和LOGPIXELSY来获取设备每英寸的像素数。然后,它使用此DPI值以100%缩放级别呈现文档。Windows显示设备始终返回96 DPI的值,除非系统上正在使用大字体(如控制面板中所设置),并且应用程序支持DPI

我使用该消息将富格文本控件的输出呈现到任意设备上下文。但是,渲染到位图时,位图设备上下文的每英寸点数与显示设备的DPI相同,即每英寸96点。这比我想渲染的要低得多。我宁愿以更高的DPI渲染,这样用户可以放大,也许以后可以在高DPI打印机上打印

我怀疑RTF控件调用
LOGPIXELSX
LOGPIXELSY
来获取设备每英寸的像素数。然后,它使用此DPI值以100%缩放级别呈现文档。Windows显示设备始终返回96 DPI的值,除非系统上正在使用大字体(如控制面板中所设置),并且应用程序支持DPI

互联网上的许多例子建议缩放
EM\u FORMATRANGE
的输出。这样就可以实现任意的DPI分辨率。大多数示例通常涉及使用和(例如,请参阅)。这些函数可用于缩放富格文本控件的渲染输出:例如,如果我指定400%缩放,那么如果富格文本控件渲染了5像素宽的内容,它实际上将变为20像素宽

不幸的是,旧的GDI函数使用整数而不是浮点数。例如,假设RTF控件决定以(12.7,15.3)像素绘制元素。这将四舍五入到(13,15)的位置。这些舍入的坐标被传递给GDI,然后GDI使用
SetMapMode
指定的缩放比例放大图像:例如,400%,它将是(13*4,15*4)或(52,60)。但这并不准确:元素最好放在(12.7*4,15.3*4)或(51,61)处。最糟糕的是,在某些情况下,错误会累积

我相信这是在缩放一些简单文本时出现这一非常明显错误的根本原因:

并使用SetMapMode“>

上面的示例是8点Segoe UI,在96 DPI显示设备上下文中使用
EM_FORMATRANGE
SetMapMode
缩放到400%。文本现在已变为32点大小,但每个字符之间的间距太大,看起来不自然

上面的示例是在写字板中创建的,输入文本作为8点Segoe UI,然后使用缩放控件将其设置为400%缩放级别。每个字符之间的间距看起来正常。使用32点字体和100%缩放级别可获得完全相同的结果

为了解决这个问题,我尝试了以下方法。对于每一种尝试,当缩放到400%时,结果都同样不令人满意

  • 使用缩放变换集,而不是使用
    SetMapMode
    SetWindowExtEx
    等进行缩放
  • 将图元文件的设备上下文传递到
    EM_FORMATRANGE
    ,然后稍后缩放图元文件
  • 使用
    SetMapMode
    结合渲染到图元文件进行缩放,然后在不缩放的情况下显示图元文件
我相信结果总是不令人满意的,因为问题归结为这样一个事实:rich edit控件舍入到最接近的整数,并渲染到它认为是96 DPI的设备,忽略了现有的转换。我查看了图元文件格式,发现单个字符的位置是实际上以像素级分辨率存储在图元文件中-这就是为什么缩放图元文件显然不起作用的原因,因为在该点之前已经进行了舍入

我可以想出两个真正的解决方案来解决这个问题:

  • 使用具有更高用户指定的每英寸点数的设备上下文,以便
    GetDeviceCaps
    返回不同的值。(注意:有些示例建议使用打印机设备,因为它们通常具有更高的DPI,但我希望我的代码能够在没有打印机且能够渲染到屏幕外缓冲区的系统上工作)
  • 告诉rich edit控件假定设备上下文的每英寸点数不同于
    GetDeviceCaps
    报告的点数
其他任何东西似乎仍会受到这些舍入误差的影响


是否有人(1)知道如何实施我提出的任一解决方案,或者(2)知道如何实现我的目标,将准确的高DPI输出输入缓冲区?

我遇到了完全相同的问题

一个快速的解决方案是将文本绘制成100%比例的位图,然后仅缩放位图。 这不是最好的解决方案,但可能对你有用

你有没有找到更好的解决方案?如果有,请在这里分享

另外请注意,当您将文本绘制为100%的元文件,然后将元文件缩放到屏幕时,也会出现此问题-我相信这与GDI文本绘制功能的缩放效果不佳有关


Roey

您可以将控件中所有文本的点大小乘以4的因子,并将控件渲染为4倍大的位图


如果您自己填充控件,这将非常简单。如果您支持用户输入的任意内容,这将需要更多的工作,并且需要额外的努力来处理任何非文本的内容(例如嵌入位图).

我刚刚花了两周时间解决了一个类似的问题。我需要一个可扩展的富编辑,用于WYSISWG编辑。我们发现windows富编辑控件不支持使用EM_FORMATRANGE正确缩放,字符间距在缩放级别和字体大小之间不会改变,仅在离散的字体大小步骤中缩放

因为我不需要规模上的巨大差异,所以我解决了这个问题