ExtTextOut fallisce con stringhe molto lunghe a meno che la qualità del carattere inferiore specificato

StackOverflow https://stackoverflow.com/questions/1367130

  •  21-09-2019
  •  | 
  •  

Domanda

A volte la nostra applicazione ha bisogno di disegnare le stringhe molto lunghe (ad esempio 6.000 caratteri) utilizzando ExtTextOut. A volte ExtTextOut non riesce e restituisce zero e restituisce GetLastError azzerare pure.

Per ricreare la situazione creare una semplice applicazione MFC documento unico e quindi impostare l'OnDraw essere:

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=\"&apos;Arial Unicode MS&apos;\" 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&apos;t actually fail if we switch to Anti-Aliased Fonts. Not sure why. It also doesn&apos;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&apos;t actually fail if we switch to Anti-Aliased Fonts. Not sure why. It also doesn&apos;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 );
}

Quando si esegue l'applicazione si dovrebbe vedere una sola riga 'Ma questo stampa' a metà strada verso il basso dello schermo. Se si imposta lfQuality = ANTIALIASED_QUALITY poi lo fa in realtà stampare qualcosa fuori, ma semplicemente non guardare a destra.

Ho provato questo su Vista e XP.

Tutte le idee?

È stato utile?

Soluzione 2

Ulteriori sperimentazioni hanno rivelato che non risulta essere specificamente giù alla lunghezza della linea o la larghezza risultante, cioè alcune linee con più caratteri e larghezza maggiore sarebbe bene stampare (ad esempio una linea con 7.365 caratteri e 40.360 larghezza stampata bene mentre una linea diversa, con 6.572 caratteri e 36.113 larghezza non). Tuttavia, quelle stesse linee più lunghe potrebbe essere fatto a fallire cambiando qualcosa come il colore della linea di fondo.

Il che mi porta a credere che questo potrebbe essere a causa della complessità della riga di testo, piuttosto che solo la lunghezza della linea e non v'è forse un time-out interno, vale a dire se ExtTextOut vede che sta prendendo troppo tempo allora appena si chiude senza stampare alcun output.

La nostra soluzione era quella di tritare ogni linea in 500 blocchi di caratteri. Così, invece di un unico ExtTextOut per 6.000 caratteri allineano ci sono 12 ExtTextOuts ogni stampa alla fine dell'ultimo. Questo sembra funzionare perfettamente con pochissimo calo di prestazioni e ci permette di stampare molto grandi linee (ho smesso di test dopo 60.000 caratteri).

Altri suggerimenti

ho creato un semplice font:

CFont font;
font.CreatePointFont(720, _T("Times New Roman"));
CFont * pold = pDC->SelectObject( &font );

Poi inizializzato una stringa fino a quando non è riuscito a stampare. 761 caratteri lavorato, 762 non riuscita:

CString str('a', 761); // Works
CString str('a', 762); // Fails

Ho provato un carattere diverso, non è riuscito a un numero maggiore di caratteri. non ha senso fino a quando ho preso le dimensioni di ogni stringa:

CSize s = pDC->GetTextExtent(str);

La larghezza di entrambe le stringhe era ~ 32700; proprio vicino a 16 bit firmato limite di 32767.

Ho avuto l'impressione che la limitazione di coordinate 16 bit è stato urtato a 32 bit che iniziano con NT, quindi non ho idea perché questo non avrebbe funzionato su XP o Vista. Posso vagamente ricordare un articolo KB in materia, ma non riesco a trovarlo.

Ho provato ad utilizzare TextOut e DrawText ed ho ottenuto gli stessi risultati.

Ho quindi provato disegnando una coppia di linee di garantire lavoravano oltre il limite di 16 bit:

pDC->MoveTo(10,0);
pDC->LineTo(10,38000);
pDC->MoveTo(10,38000);
pDC->LineTo(100, 38000);

e ha funzionato bene, quindi la mia ipotesi è che c'è un bug nei funzioni GDI di testo base.

  1. osservo lo stesso problema con 4000 caratteri in Windows 10 (quindi questo piuttosto vecchia domanda è ancora un argomento per l'anno 2016)
  2. osservo il problema su Windows 7, ma solo su un computer mentre si lavora su un altro computer con Windows 7.
  3. Quando ExtTextOut fallisce restituisce FALSE. Quindi questo non sembra essere un problema, perché la funzione già ha notato che qualcosa è andato storto.

Da queste osservazioni e da quello che gli altri hanno scritto qui posso dedurre:

  1. La conclusione di Fat Elvis che c'è un limite di 16 bit nella funcion è sicuramente sbagliato, altrimenti sarebbe fallire su tutti i Windows 7 macchine.
  2. La teoria di snowdude che un timeout ha un ruolo molto senso, perché osservo il problema sul lento di Windows 7 macchina, mentre su un Windows 7 macchina più veloce disegna correttamente la stessa stringa. Probabaly il driver grafico ha un limite di tempo in cui si deve disegnare i personaggi. Inoltre MSDN dice che la stringa non deve essere più lungo di 8192 caratteri. Così Microsoft afferma già che ci possono essere problemi con troppo lunghe stringhe.

La soluzione è sicuramente di non utilizzare un altro tipo di carattere, come suggerito nella domanda. (Il tipo di carattere di qualità inferiore rende il disegno più veloce che approva ancora una volta la teoria di un timeout.)

Ho scritto un codice che finalmente risolve il problema. Il funcion è altamente velocità ottimizzata.

// 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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top