How to fit text in rectangle-MSDN

来源:互联网 发布:多目标优化是什么 编辑:程序博客网 时间:2024/05/15 02:06
Microsoft Windows 操作系统中的 TrueType 字体是线性可缩放的。 但是,是 TrueType 字体的可伸缩性的线性是仅适用于一种字体的字符高度跃点数。 一种字体的外观的所有其他方面很少线性缩放相对于字符高度。 这提供了为缩放文本输出使用 TrueType 字体时,两个问题。

第一个问题是单元格高度 (文本输出的垂直程度) 不能扩展线性字符高度。 发生此问题是因为单元格高度与字符高度不同调用内部 Leading Windows 中的内部标志符号尺寸。 受字符标志符号的这一部分是设计的缩放时,TrueType 提示。 因为提示会影响标志符号度量标准以一种非线性方式,单元格高度而变化非线性增长。

这提供了一个问题具有以适应目标矩形的垂直程度的比例的文字。 如果某个程序尝试创建一系列单元格高度 (正 lfHeight 值) 的连续域通过字体大小,不连续的大量实际的单元格高度结果,因为单元格高度的真正的域不连续。 如果字符大小 (负 lfHeight 值) 的连续的域创建,单元格高度所导致的范围可能是不连续的。

for example,may try to create one of each size of font with lfHeight values from 9 to 15,but resulting cell height may be 9,10,11,11,13,14,15 where cell height of 12 was requested but result was 11。 this occurs because of font no size has cell height of 12。 在本刻意示例,字符大小可能是 12 的 8、 9、 10、 10、 11、 12、 13,这表示字体的单元格高度大小请求没有一个字符大小等效。

遗憾的是,这是 TrueType 提示将产生可读的文本在屏幕大小的一个特征。 如果您必须指定单元格高度,则有两个选项:
  • accept that operating system chooses,and accordingly deal with output closest match。
  • 选择下一个最大的字体大小,然后剪贴输出到目标矩形。
如果可能,程序应缩放字体使用线性缩放的跃点数: 字符高度 (负 lfHeight 值)。 通过使用这种方法,您可以获得正确的线性字符高度。 这将创建的文本直观地连续和平滑缩放,但如它缩放该程序的代码必须付与文本的总范围的非线性性质。

第二个问题是宽度的在一种字体的缩放比例线性的问题。 通常,较小的字体、 相对较宽字体的标志符号成为。 发生此问题是因为当一种字体变得较小的您必须有要使每个标志符号易于阅读的水平空间相对较大的量。

若要使此问题更困难,TrueType 提示可能会调整以一个特定的大小来维护该标志符号的可读性该字体中一个单独的标志符号的宽度。 请考虑在字符串中有被提示调整的几个标志符号的宽度的总和。 在这种情况下,该字符串的宽度是不可预知的。

如果在标准 TextOut 函数用于输出字符串,较小的字体产生超出所需水平程度的已线性调整大小的文本输出。 较大的字体会导致退水平要求短期的文本输出。 there are two solutions to this problem:
  • make font larger or smaller until horizontal extent comes requirement to close。 this approach suffers from two flaws in that will unlikely get exact horizontal extent,and vertical scale requirement is broken。
  • 使用符合垂直要求,字体大小但不使用 TextOut 。 而是使用 ExtTextOut 定位的所有要覆盖该矩形的水平程度字符串的字符。
第二种方法是说明了在后面的示例代码中。 仅主要缺点是文本的可读性会受到影响有点,因为已从设计到字体字符间距更改字符间距。
BOOL GetTextBlackExtentPoint(  HDC hdc,           // handle to DC  LPCTSTR lpString,  // text string  int cbString,      // number of characters in string  LPSIZE lpSize      // string size){    SIZE sizeTx;    ABC lead;    ABC trail;    TCHAR ch = lpString[lstrlen(lpString)-1];    if (NULL == lpSize)        return false;    if (!GetTextExtentPoint32(hdc, lpString, cbString, &sizeTx))        return false;    if (!GetCharABCWidths(hdc, lpString[0], lpString[0], &lead))        return false;    if (!GetCharABCWidths(hdc, ch, ch, &trail))        return false;    sizeTx.cx = sizeTx.cx - lead.abcA -trail.abcC;    *lpSize = sizeTx;    return true;}BOOL SnugTextOut( HDC hDC, RECT &rc, LPTSTR szString ){    int     i, nStringLength;    BOOL    bResult;    int     *pDx;    int     nX = rc.left;    int     nY = rc.top;    int     Width = 0;    // How long is the string - you need this later in this code.    nStringLength = lstrlen( szString );    // Allocate enough memory for the intercharacter spacing array.    pDx = (int *)new int[ sizeof(int) * nStringLength ];    // Initialize the array with the standard values.    for(i=0; i < nStringLength; i++)    {        ABC     abc;        if( ! GetCharABCWidths( hDC, szString[i], szString[i], &abc ) )        {            delete [] pDx;            return FALSE;        }        pDx[i] = abc.abcA + abc.abcB + abc.abcC;                // You need the width.        Width += pDx[i];                // Also, account for the Black extent of the string.        if (i == 0)        {            // Adjustment before the first character for underhang            nX -= abc.abcA;            Width -= abc.abcA;        }        if (i == nStringLength-1)        {            // Adjustment for overhang            Width -= abc.abcC;        }    }    int deltaCX = rc.right-rc.left - Width;    int deltaCh = deltaCX / nStringLength;    int remainder = deltaCX % nStringLength;    int error = 0;    // Distribute the adjustment through the intercharacter spacing.    // For a more typographically correct approach, distribute the     // adjustment in the "white space."    for(i=0; i < nStringLength; i++)    {        pDx[i] += deltaCh;        error += remainder;        if (abs(error) >= nStringLength)    // adjustment?        {            int adjustment = abs(error)/error;            pDx[i] += adjustment;            error -= nStringLength*adjustment;        }    }    // ExtTextOut() draws our text with our ICS array.    bResult = ExtTextOut( hDC, nX, nY, 0, &rc, szString, nStringLength, pDx );    // Clean up.    delete [] pDx;    return bResult;}double ScaleFactor = 1.0;BOOL OnPaint(HWND hWnd){    PAINTSTRUCT     ps;    HDC             hdc;    LOGFONT         lf;    HFONT           hFont, hScaledFont, hOldFont;    SIZE            sizeText;    TCHAR           Buffer[] = TEXT("for this is sample text of");    RECT            rcText;    hdc = BeginPaint(hWnd, &ps);    // Get the unscaled metrics.    ZeroMemory(&lf, sizeof(lf));    lf.lfHeight = -MulDiv( 14, GetDeviceCaps(hdc, LOGPIXELSY), 72 );    lf.lfCharSet = ANSI_CHARSET;    lf.lfItalic = true;    lstrcpy(lf.lfFaceName, TEXT("Times New Roman"));    hFont = CreateFontIndirect(&lf);    hOldFont = (HFONT)SelectObject(hdc, hFont);    GetTextBlackExtentPoint(hdc, Buffer, lstrlen(Buffer), &sizeText);    SelectObject(hdc, hOldFont);    // Draw the scaled text.    lf.lfHeight = -MulDiv( 14*ScaleFactor*100, GetDeviceCaps(hdc, LOGPIXELSY), 7200 );    lf.lfCharSet = ANSI_CHARSET;    lf.lfItalic = true;    lstrcpy(lf.lfFaceName, TEXT("Times New Roman"));    hScaledFont = CreateFontIndirect(&lf);    SelectObject(hdc, hScaledFont);    rcText.left = 100;    rcText.top = 100;    rcText.right = rcText.left + sizeText.cx*ScaleFactor;    rcText.bottom = rcText.top + sizeText.cy*ScaleFactor;    SnugTextOut(hdc, rcText, Buffer);    SelectObject(hdc, GetStockObject(NULL_BRUSH));    // Rectangles are right-bottom exclusive.    rcText.right++;    rcText.bottom++;    Rectangle(hdc, rcText.left, rcText.top, rcText.right, rcText.bottom);    // Clean up.    SelectObject(hdc, hOldFont);    DeleteObject(hFont);    DeleteObject(hScaledFont);    EndPaint(hWnd, &ps);    return true;}
若要了解操作中的此示例代码,创建一个简单的 Win 32 Windows 应用程序,并使用 OnPaint 函数来处理 WM _ PAINT 消息。 对于某些用户交互,如击键信息、 一个菜单项选择或单击鼠标,更改 ScaleFactor 变量,然后使工作区。
原创粉丝点击