Comment faire pour dessiner les contours glyphe TrueType

Traductions disponibles Traductions disponibles
Numéro d'article: 243285 - Voir les produits auxquels s'applique cet article
Agrandir tout | Réduire tout

Résumé

La fonction API Win32 GetGlyphOutline peut renvoyer des données hiérarchiques glyphes native à partir d'une police TrueType. Pour dessiner un contour glyphes TrueType, les données doivent être converties de sa définition B-spline native à une séquence de définitions de ligne de courbe de Bézier. Puis la fonction de API Win32 PolyBezier peut être utilisée pour dessiner le contour.

Plus d'informations

La fonction GetGlyphOutline dans le Interface(API) programmation des applications Win32 peut récupérer un plan de TrueType. L'option de format GGO_NATIVE insère un tampon avec courbes quadratique B-spline d'un plan de TrueType. B-splines quadratique est utilisés par TrueType pour décrire la hiérarchie de glyphes dans un fichier de police TrueType. Pour dessiner ces courbes plan un peut implémenter une fonction dessin B-spline ou utilisez la fonction PolyBezier à partir de l'API Win32.

Quadratique courbe B-spline est une classe de courbes paramétrique qui définissent le chemin d'accès de plusieurs segments de courbe via quelques points de contrôle. Une courbe quadratique est une courbe de paramétrique commande deuxième. Il n'existe aucune fonction dans l'API pour dessiner une spline quadratique directement mais si le quadratique est convertie en cubique elle peut être dessinée avec l'API Win32 fonctionne pour dessiner une courbe de Bézier ; appelé PolyBezier .

En général, B-spline quadratique courbes en particulier et paramétrique courbes sont un sujet well-researched de graphiques en informatique. Ils peuvent également être très complexes. Algorithmes ont été publiés dans divers textes qui peut être utilisé pour implémenter une fonction pour dessiner une spline quadratique, mais décrivant un tel algorithme n'est pas abordée de cet article.

La fonction PolyBezier pouvez dessiner une spline quadratique car une courbe de Bézier est une courbe paramétrique cubes ou troisième commande. Une spline quadratique étant une deuxième équation ordre, il peut être exprimé en termes de l'équation mètres ordre supérieure. Même si une équation permettant d'exprimer une bicarrée comme un cubique est fournie dans l'exemple de code, son dérivation est abordée pas dans cet article.

Le code d'exemple dans cet article est une démonstration analyser un tampon de glyphes GGO_NATIVE renvoyé par la fonction GetGlyphOutline . La mémoire tampon retournée par l'indicateur de format GGO_NATIVE conforme à la structure TTPOLYGONHEADER . La structure TTPOLYGONHEADER et les données qui suivant immédiatement constituent un contour d'un glyphe TrueType. Un profil est un chemin complet de courbes est implicitement fermé si elle n'est explicitement renvoyée de cette façon.

Consultez le SDK de plate-forme pour la documentation sur les structures TTPOLYGONHEADER et TTPOLYCURVE .

Un profil de glyphes consiste en plusieurs segments de courbe représentées par TTPOLYCURVE structures. Dans un profil, le TTPOLYGONHEADER est suivi d'un ou plusieurs structures TTPOLYCURVE et les données de coordonnées du point. Le membre pfxStart fournit le point de coordonnées de départ du profil. Le décompte d'enregistrements courbe qui suivent la TTPOLYGONHEADER est fourni par le membre cb . Le point de départ est relative à l'origine du glyphe. L'origine d'un glyphe est l'angle inférieur gauche du caractère au planifié le caractère.

Chaque enregistrement de courbe TTPOLYCURVE (un segment courbe) est constituée des points de contrôle quadratique B-spline ou points Polyline simples. Le nombre de points est attribué par le membre cpfx TTPOLYCURVE . Le type de courbe de spline ou de polyligne est fourni par le membre wType . Le tableau de points de coordonnées suivre immédiatement la structure. Le point de départ de la courbe est fourni par le membre apfx .

Étant donné qu'un glyphe peut contenir plus d'un profil, la mémoire tampon contient d'un ou plusieurs groupes de TTPOLYGONHEADER structures et les données. Les profils suivants sont compressés qui suit immédiatement celle précédente dans le tampon natif. Le profil suivant commence par un TTPOLYGONHEADER à l'octet suivant au-delà du dernier point de l'enregistrement précédent de la courbe.

Cet exemple de code dessine le contour d'un glyphe TrueType par l'analyse de la mémoire tampon GGO_NATIVE pour créer une liste de segments de courbe de Bézier qui forment chaque profil. La liste des segments de courbe de Bézier est dessinée puis à l'aide de PolyBezier . Le code qui analyse la mémoire tampon est dans la fonction DrawT2Outline .

La première étape pour créer une liste de lignes de la courbe de Bézier consiste à déterminer la taille du tampon de la liste. Quatre points définissent des lignes de courbe de Bézier. La fonction PolyBezier interprète une disposition de points comme étant une ligne continue de segments de courbe de Bézier dans laquelle le début de la ligne suivante est coincident avec le point final de la ligne précédente. Par conséquent, seules trois points sont nécessaires pour décrire un segment de trait courbe de Bézier supplémentaire.

Le tampon GGO_NATIVE peut contenir une courbe en forme de polyligne ou une courbe B-spline quadratique. Deux points définissent un segment de trait alors que trois points définissent une B-spline. Chaque type étant d'être dessiné avec une ligne courbe de Bézier à l'aide de PolyBezier, le scénario pire se produit lorsqu'un profil est entièrement composé de segments de ligne se développe pour plusieurs Beziers.

Notez que pour exprimer une courbe plue segment dans une représentation de courbe B-spline ne nécessite qu'un seul point supplémentaire. Ce point définit explicitement la B ou désactiver courbe point et implicitement définit la sur point de courbe. Le point de courbe en est le milieu et le point "B" Suivant. Ainsi, soit un segment de trait supplémentaires ou un segment de courbe supplémentaires se développera pour trois points supplémentaires d'une ligne courbe de Bézier.

Le code suppose que le tampon entier natif sera composé de structures POINTFX afin que qu'il puisse déterminer le plus grand nombre de points représenté par la mémoire tampon possible. Le nombre réel est légèrement plus petit car il est surcharge de structure à décrire les profils et des courbes. La taille du tampon de la liste de courbe de Bézier est fournie par le nombre maximal possible de points multipliée par la taille d'une structure de POINT de données et multipliée par trois. Trois sont le nombre de points supplémentaires qui sont nécessaires pour chaque segment de trait supplémentaires ou d'un segment de spline quadratique lorsque converti en une courbe de Bézier.

Une fois que le tampon de courbe de Bézier a été affecté le code analyse le tampon natif en démarrant à la première TTPOLYGONHEADER . Pendant une itération de la boucle, le code traite un profil et il dessine. Une boucle interne second analyse chaque type de courbe.

Dans le cas d'une courbe polyligne (TT_PRIM_LINE), chaque segment de trait de la polyligne est convertie et ajouté à la liste des Beziers avec la fonction AppendPolyLineToBezier . Si la courbe est un B-spline quadratique (TT_PRIM_QSPLINE), la fonction AppendQuadBSplineToBezier convertit et ajoute la quadratique B-spline. Chacune de ces fonctions utilise une boucle pour analyser chaque segment de la courbe dans ses points de contrôle indépendant. Puis la ligne ou la spline est converti en une courbe de Bézier et ajouté à la liste des Beziers.

Une ligne courbe de Bézier pouvez dessiner une ligne droite facilement. Le début et fin vecteurs pointez tout simplement à l'extrémité opposée du segment de trait. Pour ce faire dans la fonction MakeBezierFromLine .

Pour convertir une spline quadratique une spline de Bézier mètres requiert exprimer des points de contrôle le cubique en termes de points de contrôle le bicarrée. L'équation pour convertir les points de contrôle se trouve dans la fonction MakeBezierFromQBSpline .

Avant du profil de dessin, le code garantit que le chemin d'accès est fermé en appelant la fonction CloseContour . La fonction est appelée uniquement si les points de début et fin de la séquence de Beziers ne sont pas coincident. La fonction PolyBezier est appelée.

Après que le profil est dessiné, le profil suivant TTPOLYGONHEADER se trouve en exécutant le pointeur lpHeader au-delà de la fin des enregistrements du profil actuel. Si cela entraîne une valeur de pointeur au-delà de la fin du tampon natif, le code a traité tous les profils et se ferme.
/****************************************************************************
 *  FUNCTION   : IntFromFixed
 *  RETURNS    : int value approximating the FIXED value.
 ****************************************************************************/ 
int PASCAL NEAR IntFromFixed(FIXED f)
{
    if (f.fract >= 0x8000)
    return(f.value + 1);
    else
    return(f.value);
}

/****************************************************************************
 *  FUNCTION   : fxDiv2
 *  RETURNS    : (val1 + val2)/2 for FIXED values
 ****************************************************************************/ 
FIXED PASCAL NEAR fxDiv2(FIXED fxVal1, FIXED fxVal2)
{
    long l;

    l = (*((long far *)&(fxVal1)) + *((long far *)&(fxVal2)))/2;
    return(*(FIXED *)&l);
}

/****************************************************************************
 *  FUNCTION   : MakeBezierFromLine
 *
 *  PURPOSE    : Converts a line define by two points to a four point Bezier
 *               spline representation of the line in pPts.
 *
 *
 *  RETURNS    : number of Bezier points placed into the pPts POINT array.
 ****************************************************************************/ 
UINT MakeBezierFromLine( POINT *pPts, POINT startpt, POINT endpt )
{
    UINT cTotal = 0;

    // starting point of Bezier
    pPts[cTotal] = startpt;
    cTotal++;

    // 1rst Control, pt == endpoint makes Bezier a line
    pPts[cTotal].x = endpt.x;
    pPts[cTotal].y = endpt.y;
    cTotal++;

    // 2nd Control, pt == startpoint makes Bezier a line
    pPts[cTotal].x = startpt.x;
    pPts[cTotal].y = startpt.y;
    cTotal++;

    // ending point of Bezier
    pPts[cTotal] = endpt;
    cTotal++;
    
    return cTotal;
}

/****************************************************************************
 *  FUNCTION   : MakeBezierFromQBSpline
 *
 *  PURPOSE    : Converts a quadratic spline in pSline to a four point Bezier
 *               spline in pPts.
 *
 *
 *  RETURNS    : number of Bezier points placed into the pPts POINT array.
 ****************************************************************************/ 
UINT MakeBezierFromQBSpline( POINT *pPts, POINTFX *pSpline )
{
    POINT   P0,         // Quadratic on curve start point
            P1,         // Quadratic control point
            P2;         // Quadratic on curve end point
    UINT    cTotal = 0;

    // Convert the Quadratic points to integer
    P0.x = IntFromFixed( pSpline[0].x );
    P0.y = IntFromFixed( pSpline[0].y );
    P1.x = IntFromFixed( pSpline[1].x );
    P1.y = IntFromFixed( pSpline[1].y );
    P2.x = IntFromFixed( pSpline[2].x );
    P2.y = IntFromFixed( pSpline[2].y );

    // conversion of a quadratic to a cubic

    // Cubic P0 is the on curve start point
    pPts[cTotal] = P0;
    cTotal++;
    
    // Cubic P1 in terms of Quadratic P0 and P1
    pPts[cTotal].x = P0.x + 2*(P1.x - P0.x)/3;
    pPts[cTotal].y = P0.y + 2*(P1.y - P0.y)/3;
    cTotal++;

    // Cubic P2 in terms of Qudartic P1 and P2
    pPts[cTotal].x = P1.x + 1*(P2.x - P1.x)/3;
    pPts[cTotal].y = P1.y + 1*(P2.y - P1.y)/3;
    cTotal++;

    // Cubic P3 is the on curve end point
    pPts[cTotal] = P2;
    cTotal++;

    return cTotal;
}


/****************************************************************************
 *  FUNCTION   : AppendPolyLineToBezier
 *
 *  PURPOSE    : Converts line segments into their Bezier point 
 *               representation and appends them to a list of Bezier points. 
 *
 *               WARNING - The array must have at least one valid
 *               start point prior to the address of the element passed.
 *
 *  RETURNS    : number of Bezier points added to the POINT array.
 ****************************************************************************/ 
UINT AppendPolyLineToBezier( LPPOINT pt, POINTFX start, LPTTPOLYCURVE lpCurve )
{
    int     i;
    UINT    cTotal = 0;
    POINT   endpt;
    POINT   startpt;
    POINT   bezier[4];

    endpt.x = IntFromFixed(start.x);
    endpt.y = IntFromFixed(start.y);

    for (i = 0; i < lpCurve->cpfx; i++)
    {
        // define the line segment
        startpt = endpt;
        endpt.x = IntFromFixed(lpCurve->apfx[i].x);
        endpt.y = IntFromFixed(lpCurve->apfx[i].y);

        // convert a line to a bezier representation
        MakeBezierFromLine( bezier, startpt, endpt );

        // append the Bezier to the existing ones
                                    // Point 0 is Point 3 of previous.
        pt[cTotal++] = bezier[1];   // Point 1
        pt[cTotal++] = bezier[2];   // Point 2
        pt[cTotal++] = bezier[3];   // Point 3

    }

    return cTotal;
}


/****************************************************************************
 *  FUNCTION   : AppendQuadBSplineToBezier
 *
 *  PURPOSE    : Converts Quadratic spline segments into their Bezier point 
 *               representation and appends them to a list of Bezier points. 
 *
 *               WARNING - The array must have at least one valid
 *               start point prior to the address of the element passed.
 *
 *  RETURNS    : number of Bezier points added to the POINT array.
 ****************************************************************************/ 
UINT AppendQuadBSplineToBezier( LPPOINT pt, POINTFX start, LPTTPOLYCURVE lpCurve )
{
    WORD                i;
    UINT                cTotal = 0;
    POINTFX             spline[3];  // a Quadratic is defined by 3 points
    POINT               bezier[4];  // a Cubic by 4

    // The initial A point is on the curve.
    spline[0] = start;

    for (i = 0; i < lpCurve->cpfx;)
    {
        // The B point.
        spline[1] = lpCurve->apfx[i++];

        // Calculate the C point.
        if (i == (lpCurve->cpfx - 1))
        {
            // The last C point is described explicitly
            // i.e. it is on the curve.
            spline[2] = lpCurve->apfx[i++];
        }     
        else
        {
            // C is midpoint between B and next B point
            // because that is the on curve point of 
            // a Quadratic B-Spline.
            spline[2].x = fxDiv2(
                lpCurve->apfx[i-1].x,
                lpCurve->apfx[i].x
                );
            spline[2].y = fxDiv2(
                lpCurve->apfx[i-1].y,
                lpCurve->apfx[i].y
                );
        }

        // convert the Q Spline to a Bezier
        MakeBezierFromQBSpline( bezier, spline );
        
        // append the Bezier to the existing ones
                                    // Point 0 is Point 3 of previous.
        pt[cTotal++] = bezier[1];   // Point 1
        pt[cTotal++] = bezier[2];   // Point 2
        pt[cTotal++] = bezier[3];   // Point 3

        // New A point for next slice of spline is the 
        // on curve C point of this B-Spline
        spline[0] = spline[2];
    }

    return cTotal;
}

/****************************************************************************
 *  FUNCTION   : CloseContour
 *
 *  PURPOSE    : Adds a bezier line to close the circuit defined in pt.
 *
 *
 *  RETURNS    : number of points aded to the pt POINT array.
 ****************************************************************************/ 
UINT CloseContour( LPPOINT pt, UINT cTotal )
{
    POINT               endpt, 
                        startpt;    // definition of a line
    POINT               bezier[4];

    // connect the first and last points by a line segment
    startpt = pt[cTotal-1];
    endpt = pt[0];

    // convert a line to a bezier representation
    MakeBezierFromLine( bezier, startpt, endpt );

    // append the Bezier to the existing ones
                                // Point 0 is Point 3 of previous.
    pt[cTotal++] = bezier[1];   // Point 1
    pt[cTotal++] = bezier[2];   // Point 2
    pt[cTotal++] = bezier[3];   // Point 3

    return 3;
}

/****************************************************************************
 *  FUNCTION   : DrawT2Outline
 *
 *  PURPOSE    : Decode the GGO_NATIVE outline, create a sequence of Beziers
 *               for each contour, draw with PolyBezier.  Color and relative 
 *               positioning provided by caller. The coordinates of hDC are
 *               assumed to have MM_TEXT orientation.
 *
 *               The outline data is not scaled. To draw a glyph unhinted
 *               the caller should create the font at its EMSquare size
 *               and retrieve the outline data. Then setup a mapping mode
 *               prior to calling this function.
 *
 *  RETURNS    : none.
 ****************************************************************************/ 
void DrawT2Outline(HDC hDC, LPTTPOLYGONHEADER lpHeader, DWORD size) 
{
    WORD                i;
    UINT                cTotal = 0; // Total points in a contour.
    LPTTPOLYGONHEADER   lpStart;    // the start of the buffer
    LPTTPOLYCURVE       lpCurve;    // the current curve of a contour
    LPPOINT             pt;         // the bezier buffer
    POINTFX             ptStart;    // The starting point of a curve
    DWORD               dwMaxPts = size/size of(POINTFX); // max possible pts.
    DWORD               dwBuffSize;

    dwBuffSize = dwMaxPts *     // Maximum possible # of contour points.
                 sizeof(POINT) * // sizeof buffer element
                 3;             // Worst case multiplier of one additional point
                                // of line expanding to three points of a bezier

   lpStart = lpHeader;
   pt = (LPPOINT)malloc( dwBuffSize );

    // Loop until we have processed the entire buffer of contours.
    // The buffer may contain one or more contours that begin with
    // a TTPOLYGONHEADER. We have them all when we the end of the buffer.
    while ((DWORD)lpHeader < (DWORD)(((LPSTR)lpStart) + size) && pt != NULL)
    {
        if (lpHeader->dwType == TT_POLYGON_TYPE)
        // Draw each coutour, currently this is the only valid
        // type of contour.
        {
            // Convert the starting point. It is an on curve point.
            // All other points are continuous from the "last" 
            // point of the contour. Thus the start point the next
            // bezier is always pt[cTotal-1] - the last point of the 
            // previous bezier. See PolyBezier.
            cTotal = 1;
            pt[0].x = IntFromFixed(lpHeader->pfxStart.x);
            pt[0].y = IntFromFixed(lpHeader->pfxStart.y);

            // Get to first curve of contour - 
            // it starts at the next byte beyond header
            lpCurve = (LPTTPOLYCURVE) (lpHeader + 1);

            // Walk this contour and process each curve( or line ) segment 
            // and add it to the Beziers
            while ((DWORD)lpCurve < (DWORD)(((LPSTR)lpHeader) + lpHeader->cb))
            {
                //**********************************************
                // Format assumption:
                //   The bytes immediately preceding a POLYCURVE
                //   structure contain a valid POINTFX.
                // 
                //   If this is first curve, this points to the 
                //      pfxStart of the POLYGONHEADER.
                //   Otherwise, this points to the last point of
                //      the previous POLYCURVE.
                // 
                //   In either case, this is representative of the
                //      previous curve's last point.
                //**********************************************

                ptStart = *(LPPOINTFX)((LPSTR)lpCurve - sizeof(POINTFX));
                if (lpCurve->wType == TT_PRIM_LINE)
                {
                    // convert the line segments to Bezier segments
                    cTotal += AppendPolyLineToBezier( &pt[cTotal], ptStart, lpCurve );
                    i = lpCurve->cpfx;
                }
                else if (lpCurve->wType == TT_PRIM_QSPLINE)
                {
                    // Decode each Quadratic B-Spline segment, convert to bezier,
                    // and append to the Bezier segments
                    cTotal += AppendQuadBSplineToBezier( &pt[cTotal], ptStart, lpCurve );
                    i = lpCurve->cpfx;
                }
                else
                    // Oops! A POLYCURVE format we don't understand.
                    ; // error, error, error

            // Move on to next curve in the contour.
            lpCurve = (LPTTPOLYCURVE)&(lpCurve->apfx[i]);
            }

            // Add points to close the contour.
            // All contours are implied closed by TrueType definition.
            // Depending on the specific font and glyph being used, these
            // may not always be needed.
            if ( pt[cTotal-1].x != pt[0].x || pt[cTotal-1].y != pt[0].y )
            {
                cTotal += CloseContour( pt, cTotal );
            }

            // flip coordinates to get glyph right side up (Windows coordinates)
            // TT native coordiantes are zero originate at lower-left.
            // Windows MM_TEXT are zero originate at upper-left.
            for (i = 0; i < cTotal; i++)
                pt[i].y = 0 - pt[i].y;

            // Draw the contour
            PolyBezier( hDC, pt, cTotal );
        }
        else
            // Bad, bail, must have a bogus buffer.
            break; // error, error, error

        // Move on to next Contour.
        // Its header starts immediate after this contour
        lpHeader = (LPTTPOLYGONHEADER)(((LPSTR)lpHeader) + lpHeader->cb);
    }

    free( pt );
}
				

Références

Pour plus d'informations sur la spécification TrueType consultez :
Microsoft TrueType Specifications (http://www.microsoft.com/typography/tt/tt.htm)

Également disponible sur du Microsoft Developer Network bibliothèque CD-ROM sous spécifications.

Propriétés

Numéro d'article: 243285 - Dernière mise à jour: lundi 12 février 2007 - Version: 1.5
Les informations contenues dans cet article s'appliquent au(x) produit(s) suivant(s):
  • Microsoft Win32 Application Programming Interface
  • Microsoft Windows XP Professional
  • the operating system: Microsoft Windows XP 64-Bit Edition
Mots-clés : 
kbmt kbdswgdi2003swept kbdraw kbfont kbgdi kbhowto KB243285 KbMtfr
Traduction automatique
IMPORTANT : Cet article est issu du système de traduction automatique mis au point par Microsoft (http://support.microsoft.com/gp/mtdetails). Un certain nombre d?articles obtenus par traduction automatique sont en effet mis à votre disposition en complément des articles traduits en langue française par des traducteurs professionnels. Cela vous permet d?avoir accès, dans votre propre langue, à l?ensemble des articles de la base de connaissances rédigés originellement en langue anglaise. Les articles traduits automatiquement ne sont pas toujours parfaits et peuvent comporter des erreurs de vocabulaire, de syntaxe ou de grammaire (probablement semblables aux erreurs que ferait une personne étrangère s?exprimant dans votre langue !). Néanmoins, mis à part ces imperfections, ces articles devraient suffire à vous orienter et à vous aider à résoudre votre problème. Microsoft s?efforce aussi continuellement de faire évoluer son système de traduction automatique.
La version anglaise de cet article est la suivante: 243285
L'INFORMATION CONTENUE DANS CE DOCUMENT EST FOURNIE PAR MICROSOFT SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE. L'UTILISATEUR ASSUME LE RISQUE DE L'UTILISATION DU CONTENU DE CE DOCUMENT. CE DOCUMENT NE PEUT ETRE REVENDU OU CEDE EN ECHANGE D'UN QUELCONQUE PROFIT.

Envoyer des commentaires

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com