Dessin de texte à partir de polices différentes sur la même ligne

Différents styles de type au sein d’une famille de polices peuvent avoir des largeurs différentes. Par exemple, les styles gras et italiques d’une famille sont toujours plus larges que le style romain pour une taille de point spécifiée. Lorsque vous affichez ou imprimez plusieurs styles de type sur une seule ligne, vous devez suivre la largeur de la ligne pour éviter d’afficher ou d’imprimer des caractères les uns sur les autres.

Vous pouvez utiliser deux fonctions pour récupérer la largeur (ou l’étendue) du texte dans la police actuelle. La fonction GetTabbedTextExtent calcule la largeur et la hauteur d’une chaîne de caractères. Si la chaîne contient un ou plusieurs caractères de tabulation, la largeur de la chaîne est basée sur un tableau spécifié de positions de taquet de tabulation. La fonction GetTextExtentPoint32 calcule la largeur et la hauteur d’une ligne de texte.

Si nécessaire, le système synthétise une police en modifiant les bitmaps de caractères. Pour synthétiser un caractère dans une police en gras, le système dessine le caractère deux fois : au point de départ, puis à nouveau un pixel à droite du point de départ. Pour synthétiser un caractère dans une police italique, le système dessine deux lignes de pixels en bas de la cellule de caractère, déplace le point de départ d’un pixel vers la droite, dessine les deux lignes suivantes et continue jusqu’à ce que le caractère ait été dessiné. En déplaçant les pixels, chaque caractère semble être ciselé à droite. La quantité de cisaillement est une fonction de la hauteur du caractère.

Une façon d’écrire une ligne de texte contenant plusieurs polices consiste à utiliser la fonction GetTextExtentPoint32 après chaque appel à TextOut et à ajouter la longueur à une position actuelle. L’exemple suivant écrit la ligne « Il s’agit d’un exemple de chaîne ». En utilisant des caractères gras pour « This is a », bascule vers des caractères italiques pour « sample », puis retourne en gras pour « string ». Après avoir imprimé toutes les chaînes, il restaure les caractères par défaut du système.

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); 

Dans cet exemple, la fonction GetTextExtentPoint32 initialise les membres d’une structure SIZE avec la longueur et la hauteur de la chaîne spécifiée. La fonction GetTextMetrics récupère le surplomb de la police actuelle. Étant donné que le surplomb est égal à zéro si la police est une police TrueType, la valeur de surplomb ne modifie pas le placement de la chaîne. Toutefois, pour les polices raster, il est important d’utiliser la valeur de surplomb.

Le surplomb est soustrait de la chaîne en gras une fois, pour rapprocher les caractères suivants de la fin de la chaîne si la police est une police raster. Étant donné que le surplomb affecte à la fois le début et la fin de la chaîne italique dans une police raster, les glyphes commencent à droite de l’emplacement spécifié et se terminent à gauche du point de terminaison de la dernière cellule de caractère. (La fonction GetTextExtentPoint32 récupère l’étendue des cellules de caractères, et non l’étendue des glyphes.) Pour prendre en compte le surplomb dans la chaîne italique raster, l’exemple soustrait le surplomb avant de placer la chaîne et le soustrait à nouveau avant de placer les caractères suivants.

La fonction SetTextJustification ajoute un espace supplémentaire aux caractères d’arrêt d’une ligne de texte. Vous pouvez utiliser la fonction GetTextExtentPoint pour déterminer l’étendue d’une chaîne, puis soustraire cette étendue de la quantité totale d’espace que la ligne doit occuper et utiliser la fonction SetTextJustification pour répartir l’espace supplémentaire entre les caractères de saut dans la chaîne. La fonction SetTextCharacterExtra ajoute un espace supplémentaire à chaque cellule de caractère de la police sélectionnée, y compris le caractère d’arrêt. (Vous pouvez utiliser la fonction GetTextCharacterExtra pour déterminer la quantité actuelle d’espace supplémentaire ajoutée aux cellules de caractères ; le paramètre par défaut est zéro.)

Vous pouvez placer des caractères avec une plus grande précision à l’aide de la fonction GetCharWidth32 ou GetCharABCWidths pour récupérer les largeurs des caractères individuels dans une police. La fonction GetCharABCWidths est plus précise que la fonction GetCharWidth32 , mais elle ne peut être utilisée qu’avec des polices TrueType.

L’espacement ABC permet également à une application d’effectuer un alignement de texte très précis. Par exemple, lorsque l’application aligne à droite une police raster roman sans utiliser l’espacement ABC, la largeur avancée est calculée comme largeur de caractères. Cela signifie que l’espace blanc à droite du glyphe dans la bitmap est aligné, et non le glyphe lui-même. En utilisant des largeurs ABC, les applications disposent d’une plus grande flexibilité dans le placement et la suppression des espaces blancs lors de l’alignement du texte, car elles disposent d’informations qui leur permettent de contrôler finement l’espacement entre les caractères.