question

ZoltnHegeds-7054 avatar image
0 Votes"
ZoltnHegeds-7054 asked Viorel-1 commented

TextOutW unicode support depends on the length of the text

My English is not perfect, sorry.

I am using Visual C++ 2019 16.9.2 Community, and MFC. At debug mode, at the start of my program, there is an assertion error in a file what is part of MFC, at the line 666. So, I used release mode, IA-32 and AMD64 CPU architecture. I am using Consolas font, with size 9. At Visual Studio text editor, and at LibreOffice Writer (a word processor), this works correct. The most characters have the same width, some have not, but the cursor is always between 2 characters. Wide characters for example:

∧∨∃∄∀∈∉∌∋∪⊂⊆⊄⊈⊃⊅⊇⊉⇒⇔≪≫∇⊥▲▼◆◇

I tried CDC::GetCharWidth, CDC::GetOutputCharWidth, CDC::GetCharABCWidths. The most chacters are 20 pixel wide (3-times scale: 3*96 dpi = 288 dpi at Windows's setting), 6 characters have 0 width (not ABC-width). The ABC widths of the characters I wrote have 20 pixel width. I tried 0 instead of a negative A, C, width, but this did not help. But there is a bigger problem. These characters look correct if there are other characters after them. If has not, these are unknown unicodes:

 const wchar_t text[] = L"∧∨∃∄∀∈∉∌∋∪⊂⊆⊄⊈⊃⊅⊇⊉⇒⇔≪≫∇⊥▲▼◆◇";
 pDC->TextOutW(4, 0, text);
 pDC->TextOutW(4, 60, L"0000000000000000000000000000");
 for (int i = 0, pos = 4; text[i]; pos += 20, ++i)
     pDC->TextOutW(pos, 120, text+i, 1);
 // ::TextOutW((HDC) *pDC, pos, 120, text+i, 1);

I tried CDC:: and global form of TextOutW so. This can not display these characters correctly. The number of 0s is 28 = number of special characters in text[].

[1]: /answers/storage/attachments/80622-width.png

[2]: /answers/storage/attachments/80681-ideview.txt

c++windows-api-general
width.png (27.0 KiB)
ideview.txt (3.1 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Viorel-1 avatar image
0 Votes"
Viorel-1 answered Viorel-1 commented

To solve the drawing problem of TextOut, consider a powerful alternative — DrawText:

 for( int i = 0, pos = 4; text[i]; pos += 20, ++i )
 {
    pDC->DrawText( text + i, 1, CRect( CPoint( pos, 120 ), CSize( 0, 0 ) ), DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX );
 }



· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you. Do you have a method for getting the width of characters? I always get 20. Writing all the characters:

Around 15 s normal
Around 12 s with CDC::SetBkMode(TRANSPARENT)
Around 3 s with GetTextExtentPoint32.
I do not perceive with CDC::GetCharWidth, CDC::GetOutputCharWidth, CDC::GetCharABCWidths, so less than 0,1 s, but these gives 20 always. (Times on Ryzen 3 3100).

0 Votes 0 ·

To determine the width, try DrawText, for example:

 CRect r( 0, 0, 0, 0 );
 pDC->DrawText( L"∃", 1, r, DT_LEFT | DT_TOP | DT_NOPREFIX | DT_CALCRECT );
 int width = r.Width( );

Drawing the series of characters:

 for( int i = 0, pos = 4; text[i]; ++i )
 {                                                                      -
    pDC->DrawText( text + i, 1, CRect( CPoint( pos, 120 ), CSize( 0, 0 ) ), DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX );
    
    CRect r( 0, 0, 0, 0 );
    pDC->DrawText( text + i, 1, r, DT_LEFT | DT_TOP | DT_NOPREFIX | DT_CALCRECT );
    
    pos += r.Width( );
 }

0 Votes 0 ·

Thank you, but this takes at least 6 second. GetTextExtentPoint32 is faster, 3 second. (All the 65536 characters).

0 Votes 0 ·
Show more comments
ZoltnHegeds-7054 avatar image
0 Votes"
ZoltnHegeds-7054 answered ZoltnHegeds-7054 edited

Workaround: write 2 characters: what must, and after it, what's code is 0 (space is not suit):

 pDC->SetTextAlign(TA_UPDATECP);
 pDC->MoveTo(4, 120);
 wchar_t tt[2] = {0, 0};
 for (int i = 0; text; ++i) {
     tt[0] = text[i];
     pDC->TextOutW(0, 0, tt, 2);
     CPoint const xy = pDC->GetCurrentPosition();
     pDC->MoveTo(xy.x-20, xy.y);  // 20 is the width of the character of code 0
 }

There are project files so, so there are a lot of files, and I can not upload a .zip to here: not allowed. I tried to rename to .pdf, but the websize analyzes the content of the file.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I wish a real solution, not a workaround: this writes 2 characters, so deletes the character after the written character. So, line must be rewrited: all what are after the written character.

Getting the width of characters gives the normal size at broad characters so. So, at now, I must write all the 65536 characters, and get the cursor position after it. This takes 15 second. So, I am interested in how WriteOutW finds out the wide of the characters.

Assertion error in Debug mode is solved: at the resource, in the string table, before the file extension, requires the . (point).

0 Votes 0 ·