Поделиться через


Рисование текста из разных шрифтов в одной строке

Различные стили типов в семействе шрифтов могут иметь разные ширины. Например, полужирные и курсивные стили семейства всегда шире, чем римский стиль для указанного размера точки. При отображении или печати нескольких шрифтовых стилей в одной строке необходимо отслеживать ширину строки, чтобы избежать отображения или печати символов друг на друге.

Вы можете использовать две функции для получения ширины (или размера) текста в текущем шрифте. Функция GetTabbedTextExtent вычисляет ширину и высоту символьной строки. Если строка содержит один или несколько символов табуляции, ширина строки основана на указанном массиве позиций остановок табуляции. Функция GetTextExtentPoint32 вычисляет ширину и высоту строки текста.

При необходимости система синтезирует шрифт, изменяя растровые изображения символов. Чтобы синтезировать символ в полужирном шрифте, система дважды рисует символ: в начальной точке и снова один пиксель справа от начальной точки. Чтобы синтезировать символ в курсивном шрифте, система рисует две строки пикселей в нижней части ячейки символа, перемещает начальную точку вправо, рисует следующие две строки и продолжается до тех пор, пока символ не будет нарисован. При перемещении пикселей каждый символ, как представляется, передвигается вправо. Величина сдвига является функцией высоты символа.

Одним из способов написания строки текста, содержащей несколько шрифтов, является использование функции GetTextExtentPoint32 после каждого вызова TextOut и добавляя длину к текущей позиции. В следующем примере записывается строка "Это пример строки". Используются полужирные символы для "Это", затем переключается на курсивные символы для "пример", а затем возвращается к полужирным символам для "строки". После печати всех строк восстанавливает настройки шрифтов по умолчанию системы.

int XIncrement; 
int YStart; 
TEXTMETRIC tm; 
HFONT hfntDefault, hfntItalic, hfntBold; 
SIZE sz; 
LPSTR lpszString1 = "This is a "; 
LPSTR lpszString2 = "sample "; 
LPSTR lpszString3 = "string."; 
HRESULT hr;
size_t * pcch;
 
// Create a bold and an italic logical font.  
 
hfntItalic = MyCreateFont(); 
hfntBold = MyCreateFont(); 
 
 
// Select the bold font and draw the first string  
// beginning at the specified point (XIncrement, YStart).  
 
XIncrement = 10; 
YStart = 50; 
hfntDefault = SelectObject(hdc, hfntBold); 
hr = StringCchLength(lpszString1, 11, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        }
TextOut(hdc, XIncrement, YStart, lpszString1, *pcch); 
 
// Compute the length of the first string and add  
// this value to the x-increment that is used for the  
// text-output operation.  

hr = StringCchLength(lpszString1, 11, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        } 
GetTextExtentPoint32(hdc, lpszString1, *pcch, &sz); 
XIncrement += sz.cx; 
 
// Retrieve the overhang value from the TEXTMETRIC  
// structure and subtract it from the x-increment.  
// (This is only necessary for non-TrueType raster  
// fonts.)  
 
GetTextMetrics(hdc, &tm); 
XIncrement -= tm.tmOverhang; 
 
// Select an italic font and draw the second string  
// beginning at the point (XIncrement, YStart).  
 
hfntBold = SelectObject(hdc, hfntItalic); 
GetTextMetrics(hdc, &tm); 
XIncrement -= tm.tmOverhang;
hr = StringCchLength(lpszString2, 8, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        } 
TextOut(hdc, XIncrement, YStart, lpszString2, *pcch); 
 
// Compute the length of the second string and add  
// this value to the x-increment that is used for the  
// text-output operation.  

hr = StringCchLength(lpszString2, 8, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        }  
GetTextExtentPoint32(hdc, lpszString2, *pcch, &sz); 
XIncrement += sz.cx; 
 
// Reselect the bold font and draw the third string  
// beginning at the point (XIncrement, YStart).  
 
SelectObject(hdc, hfntBold);
hr = StringCchLength(lpszString3, 8, pcch);
        if (FAILED(hr))
        {
        // TODO: write error handler 
        }  
TextOut(hdc, XIncrement - tm.tmOverhang, YStart, lpszString3, 
            *pcch); 
 
// Reselect the original font.  
 
SelectObject(hdc, hfntDefault); 
 
// Delete the bold and italic fonts.  
 
DeleteObject(hfntItalic); 
DeleteObject(hfntBold); 

В этом примере функция GetTextExtentPoint32 инициализирует элементы структуры SIZE, используя длину и высоту указанной строки. Функция GetTextMetrics извлекает выступ для текущего шрифта. Так как нависание равно нулю, если шрифт является шрифтом TrueType, значение перевеса не изменяет размещение строки. Однако для растровых шрифтов важно использовать значение выступа.

Перевес вычитается из полужирной строки один раз, чтобы принести последующие символы ближе к концу строки, если шрифт является растровым шрифтом. Поскольку навес влияет как на начало, так и на конец курсивной строки в растровом шрифте, глифы начинают располагаться справа от указанного местоположения и завершаются слева от конечной точки последней ячейки символов. (Функция GetTextExtentPoint32 извлекает степень ячеек символов, а не степень глифов.) Чтобы учесть навес в растровой курсивной строке, пример вычитает навес перед размещением строки и вычитает его еще раз перед размещением последующих символов.

Функция SetTextJustification добавляет дополнительное пространство к разделительным символам в строке текста. Вы можете использовать функцию GetTextExtentPoint для определения ширины строки, затем вычесть эту ширину из общей ширины пространства, которое должна занимать строка, и использовать функциюSetTextJustification, чтобы распределить дополнительное пространство между символами разрыва в строке. Функция SetTextCharacterExtra добавляет дополнительное пространство к каждой ячейке символа выбранного шрифта, включая символ разрыва. (Функцию GetTextCharacterExtra можно использовать для определения текущего объема дополнительного пространства, добавляемого в ячейки символов; значение по умолчанию равно нулю.)

Вы можете поместить символы с большей точностью с помощью GetCharWidth32 или функции GetCharABCWidths для получения ширины отдельных символов в шрифте. Функция GetCharABCWidths более точная, чем функция GetCharWidth32, но ее можно использовать только с шрифтами TrueType.

Интервалы ABC также позволяют приложению выполнять очень точное выравнивание текста. Например, если приложение справа выравнивает растровый римский шрифт без использования интервала ABC, ширина заранее вычисляется как ширина символа. Это означает, что пробел справа от глифа в растровом рисунке выравнивается, а не сам глиф. Используя ширины ABC, приложения имеют большую гибкость в размещении и удалении пробелов при выравнивании текста, так как у них есть информация, позволяющая точно управлять межсимвольными интервалами.