Jak Kreslit obrysy TrueType glyfů

Překlady článku Překlady článku
ID článku: 243285 - Produkty, které se vztahují k tomuto článku.
Rozbalit všechny záložky | Minimalizovat všechny záložky

Souhrn

Funkce rozhraní Win32 API GetGlyphOutline může vrátit data přehledu nativní glyfů z písma TrueType. Nakreslete osnovy aplikace TrueType glyfů, data musí být převeden z jeho nativní definice B křivka na posloupnost definice řádku Bezierovy křivky. Potom funkce rozhraní Win32 API PolyBezier lze nakreslete obrys.

Další informace

Funkce GetGlyphOutline v Interface(API) programování aplikace Win32 může načíst TrueType osnovy. Možnost formátování GGO_NATIVE vyplní do vyrovnávací paměti s křivky kvadratické B křivka pro TrueType osnovy. TrueType B-křivky kvadratické používají k popisu osnovy glyfů v souboru písma TrueType. K nakreslení křivky těchto osnovy jeden může implementovat funkci B křivka výkresu nebo pomocí funkce PolyBezier z rozhraní API systému Win32.

Křivky kvadratické křivka B jsou třídy ukazatelů křivek, které definují cestu k více segmentů křivky přes několik kontrolních bodů. Křivky kvadratické je druhý ukazatelů křivky pořadí. V rozhraní API nakreslete kvadratickou křivka přímo není žádná funkce, ale pokud Quadratic je převedena na krychlový lze stanovit pomocí rozhraní API systému Win32 fungovat pro kreslení Bezierovy křivky; nazvané PolyBezier.

Kvadratický B křivka křivky v konkrétní a ukazatelů křivky obecně jsou well-researched tématu grafiky ve vědě počítače. Také mohou být poměrně složitá. Algoritmy, které byly zveřejněny v různých textech, lze implementovat funkci nakreslete kvadratickou křivka, ale popisující takové algoritmus, který je nad rámec tohoto článku.

Funkce PolyBezier můžete nakreslit kvadratickou křivka, protože Bezierovy křivky je ukazatelů křivky krychlových nebo třetí pořadí. Kvadratický křivka, protože je druhý rovnice objednávky lze vyjádřit z hlediska vyšší pořadí krychlových rovnice. Přestože rovnici pro vyjádření quadratic jako krychlový není uveden v ukázkovém kódu, jeho odvození není popisované v tomto článku.

Ukázkový kód uvedený v tomto článku je demonstraci jak analyzovat vyrovnávací paměti glyf GGO_NATIVE vrácené funkcí GetGlyphOutline. Vyrovnávací paměti vrácené příznak GGO_NATIVE formát odpovídá struktuře TTPOLYGONHEADER. TTPOLYGONHEADER struktury a data, která následuje ihned představují jeden rozvrh TrueType glyfů. Profilu okraje je jeden úplnou cestu křivek, které je implicitně uzavřeny, pokud ji výslovně nevrátí tímto způsobem.

O TTPOLYGONHEADER a TTPOLYCURVE struktur naleznete v sadě Platform SDK pro dokumentaci.

Rozvrh glyfů se skládá z více segmentů křivky reprezentované TTPOLYCURVE struktury. V profilu okraje, TTPOLYGONHEADER následuje jeden nebo více TTPOLYCURVE struktury a data souřadnic bodu. Člen pfxStart poskytuje počáteční souřadnic bodu obrysu. Počet záznamů křivky, které následují TTPOLYGONHEADER je dána cb člena. Počátečním bodem je relativní vzhledem k původu glyf. Glyf pochází z levého dolního rohu znak na účaří na znak.

Každý záznam TTPOLYCURVE křivka (zakřivený segment) se skládá z kontrolních bodů kvadratické B křivka nebo jednoduché POLYLINE body. Počet bodů je dána členu cpfxTTPOLYCURVE. Typ křivky křivky nebo polyčáry je dána wType člen. Pole souřadnic body bezprostředně následující strukturu. Počáteční bod křivky je dána apfx členů.

Vzhledem k tomu, že glyf mohou obsahovat více než jeden profil, vyrovnávací paměť obsahuje jeden nebo více skupin TTPOLYGONHEADER struktury a data. Následné rozvrhy jsou baleny ihned po předchozímu nativní vyrovnávací paměti. Další rozvrh začíná TTPOLYGONHEADER na následující bajt za poslední bod předchozí záznam křivky.

Tento ukázkový kód nakreslí obrys TrueType glyfu ve vyrovnávací paměti GGO_NATIVE k vytvoření seznamu Bezierovy křivky segmenty čáry, které tvoří každou rozvrh analýze. Seznam segmenty čáry Bezierovy křivky je potom vykresleno pomocí PolyBezier. Kód, který analyzuje vyrovnávací paměti je v DrawT2Outline funkce.

Prvním krokem k vytvoření seznamu řádků Bezierovy křivky je určit velikost vyrovnávací paměti pro seznam. Čtyři body definujte řádky Bezierovy křivky. Funkce PolyBezier interpretuje matici body jako jeden řádek nepřetržité segmentů Bezierovy křivky, kde je na začátek dalšího řádku totožnou s koncový bod na předchozí řádek. Tedy pouze tři body jsou potřebné k popisu další segment čáry Bezierovy křivky.

Vyrovnávací paměti GGO_NATIVE mohou obsahovat buď polyčáry křivky nebo křivky kvadratické B křivka. Dva body definovat segmentu čáry, zatímco definovat tři body B křivka. Vzhledem k tomu, že každý typ se stanoví pomocí PolyBezier čárou Bezierovy křivky, nejhorší scénář případu dochází, když jeden rozvrh, který je zcela skládá ze segmentů čáry se rozbalí a více Beziers.

Všimněte si, že vyjádřit další křivky segment v B křivka znázornění křivky vyžaduje pouze jeden další bod. Tento bod explicitně definuje "B" nebo vypnout křivky bodu a implicitně definuje další na bod křivky. Na bod křivky je středního bodu k následujícímu bodu "B". Tedy buď další segmentu čáry nebo další křivky se rozbalí a tři další body řádku Bezierovy křivky.

Kód předpokládá, celý nativní vyrovnávací paměti se skládá z POINTFX struktury, proto jej může určit největšího možného počtu bodů, které jsou reprezentovány vyrovnávací paměti. Skutečné číslo je poněkud menší, protože režie struktury v popisující rozvrhy a křivky. Velikost vyrovnávací paměti pro seznam Bezierovy křivky je dána maximálního možného počtu bodů, násobí velikost dat bodu struktury a trojnásobku. Tři je počet další body, které jsou nutné pro každý další segment čáry nebo křivky kvadratické při převodu Bezierovy křivky.

Jakmile bylo přiděleno vyrovnávací paměti Bezierovy křivky kód analyzuje nativní vyrovnávací paměti podle počínaje prvním TTPOLYGONHEADER. Při iteraci smyčky kód zpracuje jeden rozvrh a nakreslí ho. Second vnitřní smyčku analyzuje každý typ křivky.

V případě polyčáry křivky (TT_PRIM_LINE), každý řádek segmentu Polyčára je převedena a přidán k seznamu Beziers pomocí funkce AppendPolyLineToBezier. Pokud křivky kvadratické křivka B (TT_PRIM_QSPLINE), AppendQuadBSplineToBezier funkce převede a připojí kvadratickou B křivka. Každá z těchto funkcí pomocí smyčky analyzovat mimo každý segment křivky do jeho nezávislý řídicí body. Potom je převeden na Bezierovy křivky a přidán k seznamu Beziers čáry nebo křivky.

Řádek Bezierovy křivky můžete snadno nakreslit přímou čáru. Počáteční a koncové vektorů jednoduše bodu na konci opačné segmentu čáry. To se provádí ve funkci MakeBezierFromLine.

Převést krychlových Bezierovy křivky kvadratické křivky vyžaduje vyjádření krychlový řídicí body z hlediska řídicích bodů quadratic. Rovnice přeložit kontrolních bodů je umístěn ve funkci MakeBezierFromQBSpline.

Před kreslení obrysu, kód řešení je zajištěno, že cesta je zavřena voláním funkce CloseContour. Funkce je volána pouze v případě, že počáteční a koncové body posloupnost Beziers není totožnou. Funkce PolyBezier je poté volána.

Poté, co je nakreslení obrysu, je najít další rozvrh TTPOLYGONHEADER uplatňování provázané lpHeader ukazatel za koncem záznamy v aktuální profil okraje. Je-li to vede k hodnotě ukazatele za konec vyrovnávací paměti nativní, má kód zpracovány všechny rozvrhy a východy.
/****************************************************************************
 *  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 );
}
				

Odkazy

Další informace o specifikaci TrueType naleznete:
Microsoft TrueType Specifications (http://www.microsoft.com/typography/tt/tt.htm)

K také dispozici na disku CD se sadou Microsoft Developer Network knihovna jeho podle specifikace.

Vlastnosti

ID článku: 243285 - Poslední aktualizace: 12. února 2007 - Revize: 1.5
Informace v tomto článku jsou určeny pro produkt:
  • Microsoft Win32 Application Programming Interface
  • Microsoft Windows XP Professional
  • the operating system: Microsoft Windows XP 64-Bit Edition
Klíčová slova: 
kbmt kbdswgdi2003swept kbdraw kbfont kbgdi kbhowto KB243285 KbMtcs
Strojově přeložený článek
Důležité: Tento článek byl přeložen pomocí software společnosti Microsoft na strojový překlad, ne profesionálním překladatelem. Společnost Microsoft nabízí jak články přeložené překladatelem, tak články přeložené pomocí software na strojový překlad, takže všechny články ve Znalostní databázi (Knowledge Base) jsou dostupné v češtině. Překlad pomocí software na strojový překlad ale není bohužel vždy dokonalý. Obsahuje chyby ve skloňování slov, skladbě vět, nebo gramatice, podobně jako když cizinci dělají chyby při mluvení v češtině. Společnost Microsoft není právně zodpovědná za nepřesnosti, chyby nebo škody vzniklé chybami v překladu, nebo při použití nepřesně přeložených instrukcí v článku zákazníkem. Společnost Microsoft aktualizuje software na strojový překlad, aby byl počet chyb omezen na minimum.
Projděte si také anglickou verzi článku:243285

Dejte nám zpětnou vazbu

 

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