如何加快打印 Unicode?
Posted
技术标签:
【中文标题】如何加快打印 Unicode?【英文标题】:How To Speed Up Printing Unicode? 【发布时间】:2021-07-26 23:09:54 【问题描述】:我正在使用 windows.h "TextOutW" 函数将文本打印到位图。打印常规 ascii 确实很快,但 unicode 范围内的打印似乎会导致速度大大减慢。这是我打印 unicode 方块并测试持续时间的代码:
wchar_t b = 0x25A0;
LPCWSTR s = &b;
TextOutW(hMyDC, x, y, s, wcslen(s));
有什么方法可以加快速度吗?
编辑: 我用计时器运行我的循环来测试速度:
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
auto t1 = high_resolution_clock::now();
for(int i = 0; i<1000; i++)
TextOutW(hMyDC, 25, 25, s, 1);
auto t2 = high_resolution_clock::now();
// auto ms_int = duration_cast<milliseconds>(t2 - t1);
duration<double, std::milli> ms_double = t2 - t1;
cout << ms_double.count() << "ms\n";
打印 'H' 1000 次大约需要 5 毫秒 打印 0x25A0 1000 次大约需要 50 毫秒
【问题讨论】:
您没有将有效字符串传递给wcslen
或 TextOutW
。
不,你不会。您正在使用 Unicode API 和显式宽字符。这些都不取决于构建配置。如果您切换到TCHAR
s,情况就会发生变化,正如我所指出的,没有人再使用它了。这是 Microsoft 有 2 种不同的操作系统系列时的遗留物,一种不支持 Unicode,另一种支持。今天,只有一个操作系统。无论如何,我们仍然看不到您是如何确定减速的。
@i486 Windows 本身在内部使用宽字符,因此如果您使用 ANSI 模式函数,它无论如何都必须进行转换。您之前的示例不能用作 ANSI 字符串,因为 0x25a0 不适合单个字节,即使可以,也不是有效字符。
@i48 通用文本映射(如TCHAR
)的唯一目的是能够编译单个源代码库以在 Windows NT 和 Windows 9x 上运行. MSLU 甚至缓解了这种需求。 MSLU 已在 两年 年前发货。因此,即使您是少数仍然需要针对已失去支持超过 15 年的操作系统的开发人员之一,您甚至不需要TCHAR
s。虽然,你是对的,当然。我应该说:“没有人会推荐使用TCHAR
s”。
@i48 LPCWSTR
的用途与TCHAR
完全不同。它将语言级别的类型映射到 ABI 类型。与TCHAR
不同,LPCWSTR
是明确的。如果您在代码中看到它,毫无疑问它映射到什么。与TCHAR
不同,它需要您的代码阅读者查看您的构建配置以了解它是什么,并提出更改该代码是否需要与 ANSI 和 Unicode 兼容的问题。使用TCHAR
会使代码更难阅读和理解,完全没有任何好处。
【参考方案1】:
问题在于您指向的是单个字符,而不是字符串。 wcslen
表现出未定义的行为并且可能返回一个非常大的数字。将其替换为1
,速度应该会大大加快。
【讨论】:
像这样:TextOutW(hMyDC, x, y, s, 1); ? @NO_GUI 是的,完全正确。 它确实加快了一点,但它似乎仍然比绘制 H 慢得多 我们既看不到进行渲染的minimal reproducible example,也看不到您测量速度的方式。任何一个都可能是错的。 @IInspectable Ooo 好的,我会添加更多【参考方案2】:您正在点击 Uniscribe。 ExtTextOutW
和 TextOutW
检查文本是否应该通过 Uniscribe 串接或直接传递给 GDI。
为了避免 Uniscribe 开销(不推荐),您可以将 ETO_IGNORELANGUAGE
传递给 ExtTextOutW
,但您会错过一些更高级的脚本(CJK aka Chinese+Japan+Korean,从右到左书写,字符根据位置改变形状它们被放置等)或根本没有文字。
对于 0x25A0 字符,我会减速大约 8 倍
对于 0x6F22 减速增加至 17×
在我的系统上,当指定ETO_IGNORELANGUAGE
时,没有减速。 0x25A0显示正确,0x6F22被默认框替换。
【讨论】:
感谢您的回答!我无法在我的系统上获得指定ETO_IGNORELANGUAGE
的方形字符,但我使用了 ETO_OPAQUE
选项来获得类似的效果。 :ExtTextOutW(hMyDC, x, y, ETO_OPAQUE | ETO_IGNORELANGUAGE, NULL, s, 1, NULL);
【参考方案3】:
这不是答案。我只是想发布代码来确认这个问题的时间。
注释掉的字符需要 7-8 毫秒,0x25A0
需要大约 50 毫秒。
我使用Times New Roman
,因为this page 声称它有那个UNICODE 符号。
#include <iostream>
#include <chrono>
#include <windows.h>
int main()
wchar_t b = 0x25A0;
//wchar_t b = 0x0416;
//wchar_t b = L'H';
LPCWSTR s = &b;
HDC hDC = ::GetWindowDC(::GetDesktopWindow());
HFONT hFont = CreateFontW(36, 20, 0, 0, FW_DONTCARE, FALSE, TRUE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, L"Times New Roman");
HGDIOBJ hOld = ::SelectObject(hDC, hFont);
auto t1 = std::chrono::steady_clock::now();
for (int i = 0; i < 1000; i++)
TextOutW(hDC, 25, 25, s, 1);
auto t2 = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << " msec" << std::endl;
return 0;
【讨论】:
以上是关于如何加快打印 Unicode?的主要内容,如果未能解决你的问题,请参考以下文章