如何繪製 TrueType 圖像 (Glyph) 輪廓

文章翻譯 文章翻譯
文章編號: 243285 - 檢視此文章適用的產品。
全部展開 | 全部摺疊

結論

Win32 API GetGlyphOutline 函數可以傳回原生的圖像 (Glyph) 大綱資料從 TrueType 字型。若要繪製 TrueType 圖像 (Glyph) 外框,資料必須轉換從原生的 B 曲線定義成一連串的貝茲行定義。然後 PolyBezier Win32 API 函式可用來繪製外框。

其他相關資訊

在 Win32 應用程式發展 Interface(API) GetGlyphOutline 函式可擷取 TrueType 大綱。GGO_NATIVE 格式選項會填滿與 TrueType 大綱的二次方的 B 曲線曲線緩衝區。二次方的 B 曲線是由 TrueType 用來描述圖像 (Glyph) 大綱 TrueType 字型檔案中。若要繪製這些大綱曲線其中一個可以實作 B 曲線繪圖函式,或者使用 PolyBezier 函數從 Win32 API。

二次方曲線 B 曲線是 parametric 定義多個曲線的線段透過幾個控制點路徑的曲線的類別。二次方曲線是第二個的順序 parametric 曲線。API 來直接繪製二次方曲線中沒有任何的功能,但如果 [Quadratic 會轉換成使用 Win32 API 來繪製一個立方繪製貝茲曲線的功能 ; 呼叫 PolyBezier

在特定和 parametric 曲線的二次方 B 曲線曲線一般而言會 well-researched 主題在電腦科學領域中的圖形。它們也可以是相當複雜。各種文字中已發佈的演算法,可用來實作函式來繪製二次方曲線,但描述這類的演算法已超出本文範圍。

因為貝茲曲線是三次方或第三個順序 parametric 曲線 PolyBezier 函式可以繪製二次方曲線。因為二次方曲線第二個順序方程式可以表示較高的順序立方方程式的角度。雖然表示為一個立方 quadratic 方程式提供範例程式碼中,不是本文中討論其衍生。

範例程式碼,在本文中是如何剖析 GetGlyphOutline 函數所傳回的 GGO_NATIVE 圖像 (Glyph) 緩衝區的示範。TTPOLYGONHEADER 結構符合 GGO_NATIVE 格式旗標所傳回的緩衝區。TTPOLYGONHEADER 結構與緊接它的資料會構成一個分佈的 TrueType 圖像 (Glyph)。分佈是一個完整路徑的曲線,如果它不明確地傳回如此一來隱含地關閉。

請在 TTPOLYGONHEADERTTPOLYCURVE 結構上,參閱平台 SDK 的文件。

圖像 (Glyph) 分佈是由多個曲線的線段,由 TTPOLYCURVE 結構代表所組成。在一個分佈 TTPOLYGONHEADER 跟著一或多個 TTPOLYCURVE 結構和座標點的資料。pfxStart 成員提供起始座標點的作業分佈。cb 成員會提供遵循 TTPOLYGONHEADER 的曲線記錄計數。起始點是相對於圖像原點。圖像 (Glyph) 的來源是在字元的比較基準字元的左下角。

每個 TTPOLYCURVE 曲線記錄 (曲線的線段) 是由二次方的 B 曲線的控制點或簡單的聚合線條點所組成。由 TTPOLYCURVEcpfx 成員所提供的點計數。曲線] 或 [多線條的曲線類型是由 wType 成員所提供。座標點陣列緊接結構。曲線的起始點是由 apfx 成員所提供。

因為圖像 (Glyph) 可能包含一個以上的作業分佈,緩衝區包含一或多個 TTPOLYGONHEADER 結構與資料群組。後續的作業分佈是緊接在原生緩衝區中前一個封裝中。在下一個位元組超過前一個曲線記錄的最後一個時間點的 TTPOLYGONHEADER 開頭下一個作業分佈。

這個範例程式碼剖析 GGO_NATIVE 緩衝區以建立一份貝茲線段構成每個作業分佈繪製 TrueType 圖像 (Glyph) 的外框。貝茲線段的清單然後使用 PolyBezier 繪製。程式碼剖析緩衝區處於 DrawT2Outline 函式。

若要建立的貝茲行清單第一個步驟是緩衝區的判斷清單大小。四個點定義貝茲線條。PolyBezier 函式會解譯為連續一行的下一行的開頭是同一與前一行端點的貝茲線段的點的陣列。因此,只有三個點所需說明其他的貝茲線段。

GGO_NATIVE 緩衝區可能包含聚合線條曲線或二次方的 B 曲線曲線。兩個點定義直線線段,但三個點定義 B 曲線。由於每個型別是以使用 PolyBezier 貝茲線條繪製,糟的狀況會發生於一個是完全由直線線段的分佈展開以多個 Beziers。

請注意來表達額外的曲線線段 B 曲線曲線表示中的需要只能有一個額外的點。該點明確定義 「 B 」 或關閉曲線點並隱含定義曲線點中的 [在其他。在曲線點是到下一個"B"點中間點。因此貝茲線條的三個額外的點將會展開額外的線段或額外的曲線線段。

程式碼假設整個的原生緩衝區會包含 POINTFX 結構的它可以判斷數量最多的緩衝區所代表的點。實際的編號是稍微變小,因為結構負荷會在描述分佈和曲線。貝茲清單的緩衝區大小是由點乘以 指向 結構的資料大小和乘以三個最大可能數目所提供。三個是其他所需的每個額外的線條或二次方曲線區段轉換成一個貝茲時的點數目。

一旦貝茲緩衝區配置程式碼會由起始於第一個 TTPOLYGONHEADER 剖析原生的緩衝區。迴圈的反覆項目期間程式碼會處理一個作業分佈,並將它繪製。第二的內部迴圈會剖析每一種曲線類型。

聚合線條曲線 (TT_PRIM_LINE) 的情況下每個線段的多線條是轉換,而且附加至清單 Beziers AppendPolyLineToBezier 函式。如果該曲線一條二次方曲線 B (TT_PRIM_QSPLINE) AppendQuadBSplineToBezier 函式轉換,並將附加至二次方的 B 曲線。這些函式的每個使用迴圈來剖析出曲線的每個段落為其獨立的控制點。然後線條或曲線轉換成一個貝茲,附加到 Beziers 清單。

貝茲一行可以輕易地繪製直線。開始和結束的向量只需點的直線線段相反的結尾。這是 MakeBezierFromLine 函式中。

若要將二次方曲線轉換成三次方貝茲曲線,需要表達 quadratic 的控點的角度的立方的控點。平移控點方程式] 位於 [MakeBezierFromQBSpline 函式。

在前繪圖分佈,程式碼會確認路徑已關閉藉由呼叫 CloseContour 函式。只有如果開始和結束點 Beziers 序列的不同一,會呼叫此函式。然後就會呼叫 PolyBezier 函式。

作業分佈繪製之後是透過前進 lpHeader 指標中目前的作業分佈記錄結尾之外找到下一個分佈 TTPOLYGONHEADER。如果這會導致指標值,原生緩衝區結尾之外,程式碼已處理所有的作業分佈和結束。
/****************************************************************************
 *  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 );
}
				

?考

如需有關 TrueType 規格的詳細資訊請參閱:
Microsoft TrueType Specifications (http://www.microsoft.com/typography/tt/tt.htm)

能也使用 Microsoft 開發 o 人 h 員 ? 工 u 具 ? 網路程式庫 CD 上的 [規格。

屬性

文章編號: 243285 - 上次校閱: 2007年2月12日 - 版次: 1.5
這篇文章中的資訊適用於:
  • Microsoft Win32 Application Programming Interface
  • Microsoft Windows XP Professional
  • the operating system: Microsoft Windows XP 64-Bit Edition
關鍵字:?
kbmt kbdswgdi2003swept kbdraw kbfont kbgdi kbhowto KB243285 KbMtzh
機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:243285
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。

提供意見

 

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