Как нарисовать контуры TrueType глифов

Переводы статьи Переводы статьи
Код статьи: 243285 - Vizualiza?i produsele pentru care se aplic? acest articol.
Развернуть все | Свернуть все

Аннотация

В Win32 APIGetGlyphOutlineфункция может возвращать данные структуры собственный глиф из шрифтов TrueType. Чтобы нарисовать контур глифа TrueType, данные должны преобразовываться из его собственного определения сплайна B последовательность Безье определения строки. После этогоPolyBezierФункции Win32 API можно использовать для рисования контура.

Дополнительная информация

надписьюGetGlyphOutlineфункция Interface(API) программирования приложений Win32 может извлекать структуры TrueType. Параметр format GGO_NATIVE заполнение буфера кривыми второго B-сплайна для структуры TrueType. Квадратичная B-сплайны TrueType используются для описания структуры глифов в файле шрифта TrueType. Для рисования кривых эти структуры один можно реализовать функцию B сплайна рисунка или с помощьюPolyBezierфункцию из интерфейса Win32 API.

Квадратичных кривых Б сплайн — это класс параметрических кривых, которые определяют путь из нескольких сегментов кривой через несколько контрольных точек. Второго кривой является второй заказ параметрической кривой. Нет функции интерфейса API для рисования второго сплайна непосредственно, но если квадратного уравнения преобразуется кубический, могут быть нарисованы с помощью интерфейса Win32 API функции для рисования кривой Безье; названиеPolyBezier.

Кривых второго B сплайна в конкретной и параметрических кривых в целом, well-researched разделе графики в вычислительной технике. Они также могут быть весьма сложным. Алгоритмы, опубликованные в различные тексты, можно использовать для реализации функции для рисования второго сплайна, но описания такой алгоритм выходит за рамки данной статьи.

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

Образец кода в этой статье используется как для разбора буфера GGO_NATIVE глифов, возвращенныйGetGlyphOutlinefunction:. Соответствует буфера, возвращенный флаг формат GGO_NATIVETTPOLYGONHEADERСтруктура. надписьюTTPOLYGONHEADERСтруктура и данные, непосредственно следующий за составляют один профиль TrueType глифа. Профиль — это один полный путь к кривых, неявно закрывается, если оно не возвращается явно таким образом.

Обратитесь к документации пакета Platform SDK наTTPOLYGONHEADERиTTPOLYCURVEструктуры.

Глиф профиль состоит из нескольких сегментов кривой, представленныйTTPOLYCURVEструктуры. КонтурTTPOLYGONHEADERследуют одно или несколькоTTPOLYCURVEструктуры и координат точки данных. надписьюpfxStartэлемент содержит координаты начальной точки контура. Количество кривой записи, выполнитеTTPOLYGONHEADERзадаетсяcbMEMBER:. Начальной точкой является относительно начала координат глифа. Начало координат глифа является левый нижний угол символ в базовой линии символа.

КаждыйTTPOLYCURVEзапись кривой (сегмент кривой) состоит из простых точек ломаной или второго B-сплайн с контрольными точками. Число точек, заданным значениемTTPOLYCURVEcpfxMEMBER:. Задается тип кривую сплайна или ломаной линииwTypeMEMBER:. Массив координат точек сразу же следовать структуре. Задается начальной точки кривойapfxMEMBER:.

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

Этот пример кода отображает структуру знак TrueType путем разбора GGO_NATIVE буфера, чтобы создать список Безье отрезков, образующих каждый профиль. The list of Bezier line segments is then drawn usingPolyBezier. The code that parses the buffer is in theDrawT2Outlinefunction:.

The first step to create a list of Bezier lines is to determine the size of the buffer for the list. Four points define Bezier lines. надписьюPolyBezierfunction interprets an array of points as being one continuous line of Bezier segments where the start of the next line is coincident with the endpoint of the previous line. Thus, only three points are needed to describe an additional Bezier line segment.

The GGO_NATIVE buffer may contain either a polyline curve or a Quadratic B-Spline curve. Two points define a line segment while three points define a B-Spline. Since each type is to be drawn with a Bezier line using PolyBezier, the worst case scenario occurs when one contour that is entirely composed of line segments expands to multiple Beziers.

Note that to express an additional curve segment in a B-Spline curve representation requires only one additional point. That point explicitly defines the "B" or off curve point and implicitly defines the additional on curve point. The on curve point is the midpoint to the next "B" point. Thus either an additional line segment or an additional curve segment will expand to three additional points of a Bezier line.

The code assumes that the entire native buffer will consist ofPOINTFXstructures so it can determine the largest possible number of points represented by the buffer. The actual number is slightly smaller since there is structure overhead in describing the contours and curves. The size of the buffer for the Bezier list is given by the maximum possible number of points multiplied by the data size of aPOINTstructure and multiplied by three. Three is the number of additional points that are needed for each additional line segment or quadratic spline segment when converted to a Bezier.

Once the Bezier buffer has been allocated the code parses the native buffer by starting at the firstTTPOLYGONHEADER. During an iteration of the loop the code processes one contour and draws it. A Second inner loop parses each curve type.

In the case of a polyline curve (TT_PRIM_LINE), each line segment of the polyline is converted and appended to the list of Beziers with theAppendPolyLineToBezierfunction:. If the curve is a Quadratic B-Spline (TT_PRIM_QSPLINE), theAppendQuadBSplineToBezierfunction converts and appends the Quadratic B-Spline. Each of these functions uses a loop to parse out each segment of the curve into its independent control points. Then the line or spline is converted to a Bezier and appended to the list of Beziers.

A Bezier line can draw a straight line easily. The start and ending vectors simply point at the opposite end of the line segment. This is done in theMakeBezierFromLinefunction:.

To convert a quadratic spline into a cubic Bezier spline requires expressing the cubic's control points in terms of the quadratic's control points. The equation to translate the control points is located in theMakeBezierFromQBSplinefunction:.

Before drawing the contour, the code ensures that the path is closed by calling theCloseContourfunction:. The function is called only if the start and end points of the sequence of Beziers are not coincident. Then thePolyBezierфункция вызывается.

After the contour is drawn, the next contour'sTTPOLYGONHEADERis found by advancing the lpHeader pointer beyond the end of the records in the current contour. If this results in a pointer value beyond the end of the native buffer, the code has processed all of the contours and exits.
/****************************************************************************
 *  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 );
}
				

Ссылки

For more information on the TrueType specification please see:
Microsoft TrueType Specifications (http://www.microsoft.com/typography/tt/tt.htm)

Also available on the Microsoft Developer Network Library CD's under Specifications.

Свойства

Код статьи: 243285 - Последний отзыв: 18 ноября 2010 г. - Revision: 2.0
Информация в данной статье относится к следующим продуктам.
  • Microsoft Win32 Application Programming Interface
  • Microsoft Windows XP Professional
Ключевые слова: 
kbdswgdi2003swept kbdraw kbfont kbgdi kbhowto kbmt KB243285 KbMtru
Переведено с помощью машинного перевода
ВНИМАНИЕ! Перевод данной статьи был выполнен не человеком, а с помощью программы машинного перевода, разработанной корпорацией Майкрософт. Корпорация Майкрософт предлагает вам статьи, переведенные как людьми, так и средствами машинного перевода, чтобы у вас была возможность ознакомиться со статьями базы знаний KB на родном языке. Однако машинный перевод не всегда идеален. Он может содержать смысловые, синтаксические и грамматические ошибки, подобно тому как иностранец делает ошибки, пытаясь говорить на вашем языке. Корпорация Майкрософт не несет ответственности за неточности, ошибки и возможный ущерб, причиненный в результате неправильного перевода или его использования. Корпорация Майкрософт также часто обновляет средства машинного перевода.
Эта статья на английском языке:243285

Отправить отзыв

 

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