OiO.lk Blog C# TrueType Font Parsing issue in plain C
C#

TrueType Font Parsing issue in plain C


I’m having an issue when parsing TrueType Fonts.

Below is the function responsible for parsing a simple glyph, but it has a problem that I can’t find. I have attached an image that visualises the contours of the glyph. The X and Y coordinates of the glyph points don’t seem to be quite correct. I have checked with many online resources but cannot find a problem.

Yes, I’m aware that TTF’s are big endian.
What am I doing wrong?

#define ON_CURVE_POINT_BIT 0
#define X_SHORT_VECTOR_BIT 1
#define Y_SHORT_VECTOR_BIT 2
#define REPEAT_FLAG_BIT 3
#define X_IS_SAME_OR_POSITIVE_SHORT_VECTOR 4
#define Y_IS_SAME_OR_POSITIVE_SHORT_VECTOR 5

typedef struct
{
    short X;
    short Y;
    bool OnCurve;
} GlyphPoint;
typedef struct
{
    bool IsCompound;
    short NumOfContours;
    short MinX;
    short MinY;
    short MaxX;
    short MaxY;
    short unsigned* ContourEndIndices;
    short unsigned NumOfPoints;
    GlyphPoint* Points;
    char unsigned* Flags;
    short unsigned NumOfInstructions;
    char unsigned* Instructions;
} Glyph;

void Font_ReadSimpleGlyphInternal(FILE* File, Glyph* Result)
{
    if (Result->NumOfContours == 0)
    {
        return;
    }

    Result->ContourEndIndices = (short unsigned*)Memory_Alloc(Result->NumOfContours * sizeof(short unsigned), 0);
    FileReader_ReadUInt16Array(File, true, Result->ContourEndIndices, (int unsigned)Result->NumOfContours);

    Result->NumOfPoints = Result->ContourEndIndices[Result->NumOfContours - 1U] + 1U;
    Result->Points = (GlyphPoint*)Memory_Alloc(Result->NumOfPoints * sizeof(GlyphPoint), 0);
    Result->Flags = (char unsigned*)Memory_Alloc(Result->NumOfPoints, 0);

    Result->NumOfInstructions = FileReader_ReadUInt16(File, true);
    Result->Instructions = (char unsigned*)Memory_Alloc(Result->NumOfInstructions, 0);
    FileReader_ReadUInt8Array(File, Result->Instructions, Result->NumOfInstructions);

    for (short unsigned PointIndex = 0; PointIndex < Result->NumOfPoints; PointIndex++)
    {
        Result->Flags[PointIndex] = FileReader_ReadUInt8(File);
        if (IS_BIT_SET(Result->Flags[PointIndex], REPEAT_FLAG_BIT))
        {
            char unsigned RepeatCount = FileReader_ReadUInt8(File);
            for (char unsigned RepeatIndex = 0; RepeatIndex < RepeatCount; RepeatIndex++)
            {
                Result->Flags[++PointIndex] = Result->Flags[PointIndex - 1];
            }
        }
    }

    short CoordX = 0;
    short CoordY = 0;

    for (short unsigned PointIndex = 0; PointIndex < Result->NumOfPoints; PointIndex++)
    {
        if (IS_BIT_SET(Result->Flags[PointIndex], X_SHORT_VECTOR_BIT))
        {
            char CoordOffset = FileReader_ReadInt8(File);
            CoordX += IS_BIT_SET(Result->Flags[PointIndex], X_IS_SAME_OR_POSITIVE_SHORT_VECTOR) ? CoordOffset : -CoordOffset;
        }
        else if (IS_BIT_NOT_SET(Result->Flags[PointIndex], X_IS_SAME_OR_POSITIVE_SHORT_VECTOR))
        {
            CoordX += FileReader_ReadInt16(File, true);
        }

        Result->Points[PointIndex].X = CoordX;
        Result->Points[PointIndex].OnCurve = IS_BIT_SET(Result->Flags[PointIndex], ON_CURVE_POINT_BIT);
    }

    for (short unsigned PointIndex = 0; PointIndex < Result->NumOfPoints; PointIndex++)
    {
        if (IS_BIT_SET(Result->Flags[PointIndex], Y_SHORT_VECTOR_BIT))
        {
            char CoordOffset = FileReader_ReadInt8(File);
            CoordY += IS_BIT_SET(Result->Flags[PointIndex], Y_IS_SAME_OR_POSITIVE_SHORT_VECTOR) ? CoordOffset : -CoordOffset;
        }
        else if (IS_BIT_NOT_SET(Result->Flags[PointIndex], Y_IS_SAME_OR_POSITIVE_SHORT_VECTOR))
        {
            CoordY += FileReader_ReadInt16(File, true);
        }

        Result->Points[PointIndex].Y = CoordY;
        Result->Points[PointIndex].OnCurve = IS_BIT_SET(Result->Flags[PointIndex], ON_CURVE_POINT_BIT);
    }
}



You need to sign in to view this answers

Exit mobile version