コード例 #1
0
        public static CmapTable Read(FontStreamReader reader, OffsetTable.Entry entry)
        {
            reader.Seek(entry);

            var version = reader.ReadUInt16();

            if (version != 0)
            {
                throw new FormatException($"Unexpected version number in cmap table: {version}, expecting 0");
            }

            var numberOfSubtables = reader.ReadUInt16();

            var subtables = new Dictionary <Tuple <ushort, ushort>, CmapFormat>();

            for (var i = 0; i < numberOfSubtables; i++)
            {
                var platformId         = reader.ReadUInt16();
                var platformSpecificId = reader.ReadUInt16();

                var relOffset = reader.ReadUInt32();
                var offset    = entry.Offset + relOffset;

                var subtable = ReadSubtable(reader, platformId, platformSpecificId, offset);
                subtables.Add(Tuple.Create(platformId, platformSpecificId), subtable);
            }

            return(new CmapTable(version, subtables));
        }
コード例 #2
0
        public static FpgmTable Read(FontStreamReader reader, OffsetTable.Entry entry)
        {
            reader.Seek(entry);

            var instructions = reader.ReadArray <byte>(entry.Length, r => r.ReadUInt8);

            return(new FpgmTable(instructions));
        }
コード例 #3
0
ファイル: CmapFormat0.cs プロジェクト: longshaoye/Toxon.Fonts
        public static CmapFormat Read(FontStreamReader reader, ushort platformId, ushort platformSpecificId)
        {
            var length   = reader.ReadUInt16();
            var language = reader.ReadUInt16();

            var glyphIndexArray = reader.ReadArray <byte>(256, r => r.ReadUInt8);

            return(new CmapFormat0(language, glyphIndexArray));
        }
コード例 #4
0
ファイル: GlyfTable.cs プロジェクト: longshaoye/Toxon.Fonts
        private static Glyph ReadGlyph(FontStreamReader reader)
        {
            var numberOfContours = reader.ReadInt16();
            var isCompound       = numberOfContours < 0;

            var xMin = reader.ReadFWord();
            var yMin = reader.ReadFWord();
            var xMax = reader.ReadFWord();
            var yMax = reader.ReadFWord();

            if (isCompound)
            {
                return(ReadCompoundGlyph(reader, xMin, yMin, xMax, yMax));
            }

            return(ReadSimpleGlyph(reader, numberOfContours, xMin, yMin, xMax, yMax));
        }
コード例 #5
0
ファイル: LocaTable.cs プロジェクト: longshaoye/Toxon.Fonts
        public static LocaTable Read(Font font, FontStreamReader reader, OffsetTable.Entry entry)
        {
            reader.Seek(entry);

            var length = entry.Length;
            var format = font.HeadTable.IndexToLocFormat;

            switch (format)
            {
            case IndexToLocFormat.Short:
                return(new LocaTable(reader.ReadArray <uint>(length / sizeof(ushort), r => (() => r.ReadUInt16()))));

            case IndexToLocFormat.Long:
                return(new LocaTable(reader.ReadArray <uint>(length / sizeof(uint), r => r.ReadUInt32)));

            default: throw new FormatException($"Invalid IndexToLocFormat: {format}");
            }
        }
コード例 #6
0
ファイル: HeadTable.cs プロジェクト: longshaoye/Toxon.Fonts
        public static HeadTable Read(FontStreamReader reader, OffsetTable.Entry entry)
        {
            reader.Seek(entry);

            var version      = reader.ReadFixed();
            var fontRevision = reader.ReadFixed();

            //TODO
            var checkSumAdjustment = reader.ReadUInt32();

            var magicNumber = reader.ReadUInt32(); // 0x5F0F3CF5

            if (magicNumber != 0x5F0F3CF5)
            {
                throw new FormatException($"Invalid magic number in header: 0x{magicNumber:X}, expecting 0x5F0F3CF5");
            }

            var flags = reader.ReadUInt16();      // bitflags

            var unitsPerEm = reader.ReadUInt16(); // 64-16384

            if (unitsPerEm < 64 || unitsPerEm > 16384)
            {
                throw new FormatException($"Invalid units per em in header: {unitsPerEm:X}, expecting a value between 64 and 16384");
            }

            var created  = reader.ReadLongDateTime();
            var modified = reader.ReadLongDateTime();

            var xMin = reader.ReadFWord();
            var yMin = reader.ReadFWord();
            var xMax = reader.ReadFWord();
            var yMax = reader.ReadFWord();

            var macStyle          = (MacStyle)reader.ReadUInt16(); // bitflags
            var lowestRecPPEM     = reader.ReadUInt16();
            var fontDirectionHint = reader.ReadUInt16();
            var indexToLocFormat  = (IndexToLocFormat)reader.ReadUInt16(); // 0 = short, 1 = long
            var glyphDataFormat   = (GlyphDataFormat)reader.ReadUInt16();  // 0 = current

            return(new HeadTable(version, fontRevision, flags, unitsPerEm, created, modified, xMin, yMin, xMax, yMax, macStyle, lowestRecPPEM, fontDirectionHint, indexToLocFormat, glyphDataFormat));
        }
コード例 #7
0
        public static CmapFormat Read(FontStreamReader reader, ushort platformId, ushort platformSpecificId)
        {
            uint length   = reader.ReadUInt16();
            var  language = reader.ReadUInt16();

            length -= 3 * sizeof(ushort);

            var segCount = (ushort)(reader.ReadUInt16() / 2); // stored as 2 * segCount

            var searchRange   = reader.ReadUInt16();
            var entrySelector = reader.ReadUInt16();
            var rangeShift    = reader.ReadUInt16();

            length -= 4 * sizeof(ushort);

            var endCode = reader.ReadArray <ushort>(segCount, r => r.ReadUInt16);

            if (endCode[endCode.Length - 1] != 0xffff)
            {
                throw new FormatException($"Unexpected last endCode: 0x{endCode[endCode.Length - 1]:X}, expecting 0xffff");
            }

            var reservedPad = reader.ReadUInt16(); // 0

            if (reservedPad != 0)
            {
                throw new FormatException($"Unexpected value for reservedPad: {reservedPad}, expecting 0");
            }

            length -= (ushort)(segCount * sizeof(ushort) + 1);

            var startCode     = reader.ReadArray <ushort>(segCount, r => r.ReadUInt16);
            var idDelta       = reader.ReadArray <ushort>(segCount, r => r.ReadUInt16);
            var idRangeOffset = reader.ReadArray <ushort>(segCount, r => r.ReadUInt16);

            length -= (ushort)(3 * segCount * sizeof(ushort));

            var glyphIndexArray = reader.ReadArray <ushort>(length / sizeof(ushort), r => r.ReadUInt16);

            return(new CmapFormat4(language, startCode, endCode, idDelta, idRangeOffset, glyphIndexArray));
        }
コード例 #8
0
ファイル: GlyfTable.cs プロジェクト: longshaoye/Toxon.Fonts
        public static GlyfTable Read(FontStreamReader reader, OffsetTable.Entry entry)
        {
            reader.Seek(entry);

            var glyphs = new List <Glyph>();

            while (reader.Position < entry.Offset + entry.Length)
            {
                glyphs.Add(ReadGlyph(reader));

                while ((reader.Position & 1) != 0)
                {
                    reader.ReadUInt8();
                }
            }

            if (reader.Position > entry.Offset + entry.Length)
            {
                throw new Exception("Overflow?");
            }

            return(new GlyfTable(glyphs));
        }
コード例 #9
0
        private static CmapFormat ReadSubtable(FontStreamReader reader, ushort platformId, ushort platformSpecificId, uint offset)
        {
            reader.Push();
            reader.Seek(offset, SeekOrigin.Begin);

            var format = reader.ReadUInt16();

            CmapFormat result;

            switch (format)
            {
            case 0: result = CmapFormat0.Read(reader, platformId, platformSpecificId); break;

            case 2: result = CmapFormat2.Read(reader, platformId, platformSpecificId); break;

            case 4: result = CmapFormat4.Read(reader, platformId, platformSpecificId); break;

            case 6: result = CmapFormat6.Read(reader, platformId, platformSpecificId); break;

            case 8: result = CmapFormat8.Read(reader, platformId, platformSpecificId); break;

            case 10: result = CmapFormat10.Read(reader, platformId, platformSpecificId); break;

            case 12: result = CmapFormat12.Read(reader, platformId, platformSpecificId); break;

            case 13: result = CmapFormat13.Read(reader, platformId, platformSpecificId); break;

            case 14: result = CmapFormat14.Read(reader, platformId, platformSpecificId); break;

            default: throw new FormatException($"Unexpected cmap subtable format: {format}");
            }

            reader.Pop();

            return(result);
        }
コード例 #10
0
ファイル: CmapFormat6.cs プロジェクト: longshaoye/Toxon.Fonts
 public static CmapFormat Read(FontStreamReader reader, ushort platformId, ushort platformSpecificId)
 {
     throw new NotImplementedException();
 }
コード例 #11
0
ファイル: GlyfTable.cs プロジェクト: longshaoye/Toxon.Fonts
        private static Glyph ReadCompoundGlyph(FontStreamReader reader, ushort xMin, ushort yMin, ushort xMax, ushort yMax)
        {
            var components = new List <CompoundGlyph.Component>();

            var flags = GlyphComponentFlags.MoreComponents;

            while (flags.HasFlag(GlyphComponentFlags.MoreComponents))
            {
                flags = (GlyphComponentFlags)reader.ReadUInt16();
                var glyphIndex = reader.ReadInt16();

                if (flags.HasFlag(GlyphComponentFlags.WeHaveInstructions) && flags.HasFlag(GlyphComponentFlags.MoreComponents))
                {
                    throw new NotImplementedException();
                }

                var arg1 = flags.HasFlag(GlyphComponentFlags.Arg12AreWords) ? reader.ReadInt16() : reader.ReadUInt8();
                var arg2 = flags.HasFlag(GlyphComponentFlags.Arg12AreWords) ? reader.ReadInt16() : reader.ReadUInt8();

                var matrix = new decimal[] {
                    1, 0,
                    0, 1,
                    0, 0
                };

                short?destPointIndex = null;
                short?srcPointIndex  = null;

                if (flags.HasFlag(GlyphComponentFlags.ArgsAreXYValues))
                {
                    matrix[4] = arg1;
                    matrix[5] = arg2;
                }
                else
                {
                    destPointIndex = arg1;
                    srcPointIndex  = arg1;
                }

                if (flags.HasFlag(GlyphComponentFlags.WeHaveAScale))
                {
                    matrix[0] = matrix[3] = reader.ReadF2Dot14();
                }
                else if (flags.HasFlag(GlyphComponentFlags.WeHaveAnXYScale))
                {
                    matrix[0] = reader.ReadF2Dot14();
                    matrix[3] = reader.ReadF2Dot14();
                }
                else if (flags.HasFlag(GlyphComponentFlags.WeHave2By2))
                {
                    matrix[0] = reader.ReadF2Dot14();
                    matrix[1] = reader.ReadF2Dot14();
                    matrix[2] = reader.ReadF2Dot14();
                    matrix[3] = reader.ReadF2Dot14();
                }

                components.Add(new CompoundGlyph.Component(glyphIndex, matrix, destPointIndex, srcPointIndex));
            }

            var instructions = new byte[0];

            if (flags.HasFlag(GlyphComponentFlags.WeHaveInstructions))
            {
                var instructionLength = reader.ReadUInt16();
                instructions = reader.ReadArray <byte>(instructionLength, r => r.ReadUInt8);
            }

            return(new CompoundGlyph(components, instructions));
        }
コード例 #12
0
ファイル: GlyfTable.cs プロジェクト: longshaoye/Toxon.Fonts
        private static Glyph ReadSimpleGlyph(FontStreamReader reader, short numberOfContours, ushort xMin, ushort yMin, ushort xMax, ushort yMax)
        {
            var endPoints = reader.ReadArray <ushort>((ushort)numberOfContours, r => r.ReadUInt16);

            var instructionLength = reader.ReadUInt16();
            var instructions      = reader.ReadArray <byte>(instructionLength, r => r.ReadUInt8);

            if (numberOfContours == 0)
            {
                return(new SimpleGlyph(xMin, yMin, xMax, yMax, endPoints, instructions, new Point[0]));
            }

            var numberOfPoints = endPoints.Max() + 1;

            var flags  = new SimpleGlyphFlags[numberOfPoints];
            var points = new Point[numberOfPoints];

            for (var i = 0; i < numberOfPoints; i++)
            {
                var flag = (SimpleGlyphFlags)reader.ReadUInt8();
                flags[i]  = flag;
                points[i] = new Point {
                    OnCurve = flag.HasFlag(SimpleGlyphFlags.OnCurve)
                };

                if (flag.HasFlag(SimpleGlyphFlags.Repeat))
                {
                    var count = reader.ReadUInt8();
                    while (count-- > 0)
                    {
                        flags[++i] = flag;
                        points[i]  = new Point {
                            OnCurve = flag.HasFlag(SimpleGlyphFlags.OnCurve)
                        };
                    }
                }
            }

            // read X
            short value = 0;

            for (var i = 0; i < numberOfPoints; i++)
            {
                var flag = flags[i];

                if (flag.HasFlag(SimpleGlyphFlags.XShort))
                {
                    if (flag.HasFlag(SimpleGlyphFlags.XSame))
                    {
                        value += reader.ReadUInt8();
                    }
                    else
                    {
                        value -= reader.ReadUInt8();
                    }
                }
                else if (!flag.HasFlag(SimpleGlyphFlags.XSame))
                {
                    value += reader.ReadInt16();
                }

                points[i].X = value;
            }

            // read Y
            value = 0;
            for (var i = 0; i < numberOfPoints; i++)
            {
                var flag = flags[i];

                if (flag.HasFlag(SimpleGlyphFlags.YShort))
                {
                    if (flag.HasFlag(SimpleGlyphFlags.YSame))
                    {
                        value += reader.ReadUInt8();
                    }
                    else
                    {
                        value -= reader.ReadUInt8();
                    }
                }
                else if (!flag.HasFlag(SimpleGlyphFlags.YSame))
                {
                    value += reader.ReadInt16();
                }

                points[i].Y = value;
            }

            return(new SimpleGlyph(xMin, yMin, xMax, yMax, endPoints, instructions, points));
        }