C++ 除非指定了较低的字体质量,否则ExtTextOut失败,字符串很长
有时我们的应用程序需要使用ExtTextOut绘制很长的字符串(例如6000个字符)。有时ExtTextOut失败并返回零,GetLastError也返回零 要重新创建这种情况,请创建一个简单的MFC单文档应用程序,然后将OnDraw设置为:C++ 除非指定了较低的字体质量,否则ExtTextOut失败,字符串很长,c++,mfc,draw,C++,Mfc,Draw,有时我们的应用程序需要使用ExtTextOut绘制很长的字符串(例如6000个字符)。有时ExtTextOut失败并返回零,GetLastError也返回零 要重新创建这种情况,请创建一个简单的MFC单文档应用程序,然后将OnDraw设置为: void CTestExtTextView::OnDraw(CDC* pDC) { CTestExtTextDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; L
void CTestExtTextView::OnDraw(CDC* pDC)
{
CTestExtTextDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
LOGFONT lfDetail = {0};
lfDetail.lfHeight = -(::MulDiv(100, pDC->GetDeviceCaps(LOGPIXELSY), 720));
lfDetail.lfCharSet = ANSI_CHARSET;
lfDetail.lfOutPrecision = OUT_DEFAULT_PRECIS;
lfDetail.lfQuality = CLEARTYPE_QUALITY;
lfDetail.lfWeight = 400;
_tcscpy_s(lfDetail.lfFaceName, LF_FACESIZE, _T("Arial"));
CFont font;
font.CreateFontIndirectW( &lfDetail );
CFont * pold = pDC->SelectObject( &font );
CString str = L"2 <office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:presentation=\"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\" xmlns:math=\"http://www.w3.org/1998/Math/MathML\" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\" xmlns:ooo=\"http://openoffice.org/2004/office\" xmlns:ooow=\"http://openoffice.org/2004/writer\" xmlns:oooc=\"http://openoffice.org/2004/calc\" xmlns:dom=\"http://www.w3.org/2001/xml-events\" xmlns:xforms=\"http://www.w3.org/2002/xforms\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" office:version=\"1.1\"><office:scripts/><office:font-face-decls><style:font-face style:name=\"Arial\" svg:font-family=\"Arial\" style:font-family-generic=\"swiss\" style:font-pitch=\"variable\"/><style:font-face style:name=\"Arial Unicode MS\" svg:font-family=\"'Arial Unicode MS'\" style:font-family-generic=\"system\" style:font-pitch=\"variable\"/><style:font-face style:name=\"Tahoma\" svg:font-family=\"Tahoma\" style:font-family-generic=\"system\" style:font-pitch=\"variable\"/></office:font-face-decls><office:automatic-styles><style:style style:name=\"co1\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"6.659cm\"/></style:style><style:style style:name=\"co2\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"7.408cm\"/></style:style><style:style style:name=\"co3\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"7.02cm\"/></style:style><style:style style:name=\"co4\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"7.214cm\"/></style:style><style:style style:name=\"co5\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"2.267cm\"/></style:style><style:style style:name=\"ro1\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"0.473cm\" fo:break-before=\"auto\" style:use-optimal-row-height=\"true\"/></style:style><style:style style:name=\"ro2\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"0.453cm\" fo:break-before=\"auto\" style:use-optimal-row-height=\"true\"/></style:style><style:style style:name=\"ta1\" style:family=\"table\" style:master-page-name=\"Default\"><style:table-properties table:display=\"true\" style:writing-mode=\"lr-tb\"/></style:style><style:style style:name=\"T1\" style:family=\"text\"><style:text-properties style:text-position=\"super 58%\"/></style:style></office:automatic-styles><office:body><office:spreadsheet><table:table table:name=\"Sheet1\" table:style-name=\"ta1\" table:print=\"false\"><office:forms form:automatic-focus=\"false\" form:apply-design-mode=\"false\"/><table:table-column table:style-name=\"co1\" table:default-cell-style-name=\"Default\"/><table:table-column table:style-name=\"co2\" table:default-cell-style-name=\"Default\"/><table:table-column table:style-name=\"co3\" table:default-cell-style-name=\"Default\"/><table:table-column table:style-name=\"co4\" table:default-cell-style-name=\"Default\"/><table:table-row table:style-name=\"ro1\"><table:table-cell office:value-type=\"string\"><text:p>Sample text for ExtTextOut</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>Second Column Sample Text</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>3<text:span text:style-name=\"T1\">rd</text:span> Column</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>A More Lengthly bit of text just to make sure we increase the size of the line to something that might make ExtTextOut fail. It doesn't actually fail if we switch to Anti-Aliased Fonts. Not sure why. It also doesn't fail if we make the text shorter.</text:p></table:table-cell></table:table-row><table:table-row table:style-name=\"ro1\"><table:table-cell office:value-type=\"string\"><text:p>Sample text for ExtTextOut</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>Second Column Sample Text</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>3<text:span text:style-name=\"T1\">rd</text:span> Column</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>A More Lengthly bit of text just to make sure we increase the size of the line to something that might make ExtTextOut fail. It doesn't actually fail if we switch to Anti-Aliased Fonts. Not sure why. It also doesn't fail if we make the text shorter.</text:p></table:table-cell></table:table-row><table:table-row table:style-name=\"ro1\"><table:table-cell office:value-type=\"string\"><text:p>Sample text for ExtTextOut</text:p></table:table-cell><table:table-cell office:value-type=\"string\"><text:p>Second Column Sample Text</text:p></table:table-cell><table:table-cell office:value-type=\"string\">";
pDC->ExtTextOutW( 0,0, NULL, NULL, str, NULL );
pDC->ExtTextOutW( 0,50, NULL, NULL, CString(L"But this will print out"), NULL );
pDC->SelectObject( pold );
}
void ctestextextview::OnDraw(CDC*pDC)
{
CTestExtTextDoc*pDoc=GetDocument();
断言有效(pDoc);
if(!pDoc)
返回;
LOGFONT lfDetail={0};
lfDetail.lfHeight=-(::MulDiv(100,pDC->GetDeviceCaps(LOGPIXELSY),720));
lfDetail.lfCharSet=ANSI_字符集;
lfDetail.lfOutPrecision=OUT\u DEFAULT\u precision;
lfDetail.lfQuality=CLEARTYPE\u质量;
lfDetail.lfWeight=400;
_tcscpy_s(lfDetail.lfFaceName,LF_FACESIZE,_T(“Arial”);
CFont字体;
font.CreateFontIndirectW(&lfDetail);
CFont*pold=pDC->SelectObject(&font);
CString str=L"ExtTextOutSecond Column示例文本ExtText3rd Column示例文本第二列示例文本第三列更长一点的文本,只是为了确保我们将行的大小增加到可能导致ExtTextOut失败的程度。如果我们切换到抗锯齿字体,它实际上不会失败。不确定原因。如果我们将文本变短,它也不会失败。ExtTextOutS示例文本第二列示例文本第三列更长一点的文本,只是为了确保我们将行的大小增加到可能导致ExtTextOut失败的程度。如果我们切换到抗锯齿字体,它实际上不会失败。不确定原因。如果我们将文本变短,它也不会失败。ExtTextOutSecond列示例文本的示例文本“;
pDC->extTextOut(0,0,NULL,NULL,str,NULL);
pDC->extTextOut(0,50,NULL,NULL,CString(L“但这将打印出来”),NULL;
pDC->选择对象(pold);
}
当你运行应用程序时,你会看到屏幕中间有一行“但这会打印出来”。如果你设置lfQuality=ANTIALIASED\u QUALITY,那么它确实会打印出一些东西,但看起来不太对劲
我已经在Vista和XP上测试过了
有什么想法吗?我创建了一种简单的字体:
CFont font;
font.CreatePointFont(720, _T("Times New Roman"));
CFont * pold = pDC->SelectObject( &font );
然后初始化字符串,直到无法打印。761个字符有效,762个字符失败:
CString str('a', 761); // Works
CString str('a', 762); // Fails
我尝试了不同的字体,但在字符数较多时失败。直到我计算了每个字符串的大小后才有意义:
CSize s = pDC->GetTextExtent(str);
两个字符串的宽度约为32700;正好接近16位有符号限制32767
我的印象是,16位坐标限制从NT开始被提升到了32位,所以我不知道为什么这在XP或Vista上不起作用。我模糊地记得一篇关于这个主题的KB文章,但我找不到它
我尝试使用TextOut和DrawText,得到了相同的结果
然后我试着画了几条线,以确保它们在16位限制之外工作:
pDC->MoveTo(10,0);
pDC->LineTo(10,38000);
pDC->MoveTo(10,38000);
pDC->LineTo(100, 38000);
它工作得很好,所以我猜基于文本的GDI函数中有一个bug。进一步的实验表明,它似乎并不具体取决于行的长度或结果的宽度,也就是说,一些字符更多、宽度更宽的行可以很好地打印出来(例如,7365个字符和40360个宽度的行打印得很好,而6572个字符和36113个宽度的另一行打印得不好)。但是,可以通过更改行的背景色之类的内容使这些较长的行失败 这让我相信,这可能是由于文本行的复杂性,而不仅仅是行的长度,并且可能存在内部超时,即如果ExtTextOut发现它花费的时间太长,那么它会在不打印任何输出的情况下退出 我们的解决方案是将每行分割成500个字符的块。因此,不是6000个字符的行只打印一个ExtTextOut,而是在最后一行末尾每次打印12个ExtTextOut。这似乎可以完美地工作,性能影响很小,并允许我们打印非常大的行(我在60000个字符后停止了测试)
// ATTENTION:
// The function returns FALSE on error but you cannot use GetLastError()!
BOOL ExtTextOutChunks(HDC h_Dc, int X, int Y, UINT u32_Flags, const RECT* pk_Rect,
const WCHAR* u16_String, UINT u32_StrLen, const int* ps32_DX)
{
// The maximum amount of characters that are printed at once.
// The slower the computer the lower the value must be.
const UINT CHUNK_SIZE = 500;
// Speed optimization
if (u32_StrLen <= CHUNK_SIZE)
return ExtTextOut(h_Dc, X, Y, u32_Flags, pk_Rect, u16_String, u32_StrLen, ps32_DX);
BOOL b_Return = TRUE;
UINT u32_TxtAlign = GetTextAlign(h_Dc);
BOOL b_SetFlag = (u32_TxtAlign & TA_UPDATECP) == 0;
// Set TA_UPDATECP to move the drawing position automagically after each drawing.
// This is much faster than calling GetTextExtentPoint32() each time.
if (b_SetFlag)
{
SetTextAlign(h_Dc, u32_TxtAlign | TA_UPDATECP);
MoveToEx(h_Dc, X, Y, NULL);
}
while (u32_StrLen > 0)
{
UINT u32_Count = min(u32_StrLen, CHUNK_SIZE);
if (!ExtTextOut(h_Dc, 0, 0, u32_Flags, pk_Rect, u16_String, u32_Count, ps32_DX))
{
b_Return = FALSE;
break;
}
u32_StrLen -= u32_Count;
u16_String += u32_Count;
if (ps32_DX) ps32_DX += u32_Count;
}
// Reset the flag if it was not set before (ALWAYS!)
if (b_SetFlag)
SetTextAlign(h_Dc, u32_TxtAlign);
assert(b_Return);
return b_Return;
}
//注意:
//函数在出错时返回FALSE,但不能使用GetLastError()!
BOOL ExtTextOutChunks(HDC h_Dc、int X、int Y、UINT u32_标志、const RECT*pk_RECT、,
常量WCHAR*u16_字符串,UINT u32_字符串,常量int*ps32_DX)
{
//一次打印的最大字符数。
//计算机速度越慢,该值必须越低。
consuint CHUNK_SIZE=500;
//速度优化
如果(u32_StrLen 0)
{
UINT u32_Count=min(u32_StrLen,块大小);
if(!ExtTextOut(h_Dc,0,0,u32_标志,pk_Rect,u16_字符串,u32_计数,ps32_DX))
{
b_返回=F