public OpenTypeFont Deserialize(BinaryReader reader)
        {
            var font = new OpenTypeFont {
                SfntVersion = DataTypeConverter.ReadFixed(reader)
            };

            if (!_supportedSfntVersions.Contains(font.SfntVersion))
            {
                throw new NotSupportedException("Bad sfnt version.");
            }

            // Table directory
            var numberOfTables = DataTypeConverter.ReadUShort(reader);

            reader.BaseStream.Position += 3 * DataTypeLength.UShort; // searchRange, entrySelector, rangeShift
            var entryList = Enumerable.Range(0, numberOfTables).Select(i =>
            {
                var entry = new TableDirectoryEntry {
                    Tag = DataTypeConverter.ReadTag(reader)
                };
                reader.BaseStream.Position += DataTypeLength.ULong; // checksum
                entry.Offset = DataTypeConverter.ReadULong(reader);
                entry.Length = DataTypeConverter.ReadULong(reader);
                return(entry);
            }).ToList();

            // Tables
            font.Tables.AddRange(
                entryList.OrderBy(entry => entry.Priority).Select <TableDirectoryEntry, IOpenTypeFontTable>(entry =>
            {
                switch (entry.Tag)
                {
                case "cmap":
                    return(CmapTable.Deserialize(reader, entry.Offset));

                case "head":
                    return(HeadTable.Deserialize(reader, entry.Offset));

                case "maxp":
                    return(MaxpTable.Deserialize(reader, entry.Offset));

                case "loca":
                    return(LocaTable.Deserialize(reader, entry.Offset,
                                                 font.Get <MaxpTable>().NumberOfGlyphs,
                                                 font.Get <HeadTable>().LocaTableVersion));

                case "glyf":
                    return(GlyfTable.Deserialize(reader, entry.Offset, entry.Length,
                                                 font.Get <LocaTable>()));

                case "hhea":
                    return(HheaTable.Deserialize(reader, entry.Offset));

                case "hmtx":
                    return(HmtxTable.Deserialize(reader, entry.Offset, font.Get <HheaTable>().NumberOfHMetrics,
                                                 font.Get <MaxpTable>().NumberOfGlyphs));

                case "post":
                    return(PostTable.Deserialize(reader, entry.Offset));

                default:
                    return(BinaryDataTable.Deserialize(reader, entry.Offset, entry.Length, entry.Tag));
                }
            }));

            return(font);
        }
        public void Serialize(BinaryWriter writer, OpenTypeFont font)
        {
            DataTypeConverter.WriteFixed(writer, font.SfntVersion);
            DataTypeConverter.WriteUShort(writer, (ushort)font.Tables.Count);

            var pow         = Math.Floor(Math.Log(font.Tables.Count, 2));
            var searchRange = Math.Pow(2, pow) * 16;

            DataTypeConverter.WriteUShort(writer, (ushort)searchRange);
            DataTypeConverter.WriteUShort(writer, (ushort)pow);
            DataTypeConverter.WriteUShort(writer, (ushort)(font.Tables.Count * 16 - searchRange));

            var tableDirectoryStartOffset = writer.BaseStream.Position;

            writer.BaseStream.Position += 4 * DataTypeLength.ULong * font.Tables.Count;

            var entryList      = new List <TableDirectoryEntry>(font.Tables.Count);
            var additionalInfo = new SerializationInfo(); // Shared info among all IOpenTypeFontSerializable class

            foreach (
                var table in font.Tables.OrderByDescending(table => TableDirectoryEntry.GetPriorityOfTag(table.Tag)))
            {
                var startOffsetOfThisTable = writer.BaseStream.Position;

                table.Serialize(writer, startOffsetOfThisTable, additionalInfo);

                entryList.Add(new TableDirectoryEntry
                {
                    Tag    = table.Tag,
                    Offset = (uint)startOffsetOfThisTable,
                    Length = (uint)(writer.BaseStream.Position - startOffsetOfThisTable)
                });

                // 4byte padding
                if (writer.BaseStream.Position % 4 != 0)
                {
                    var zeroCount = 4 - writer.BaseStream.Position % 4;
                    for (var i = 0; i < zeroCount; i++)
                    {
                        writer.Write((byte)0);
                    }
                }
            }

            // Write table directory
            var reader = new BinaryReader(writer.BaseStream);

            writer.BaseStream.Position = tableDirectoryStartOffset;
            foreach (var entry in entryList.OrderBy(entry => entry.Tag, StringComparer.Ordinal))
            {
                DataTypeConverter.WriteTag(writer, entry.Tag);
                DataTypeConverter.WriteULong(writer,
                                             EnableChecksum ? CalculateChecksum(reader, entry.Offset, entry.Length) : 0);
                DataTypeConverter.WriteULong(writer, entry.Offset);
                DataTypeConverter.WriteULong(writer, entry.Length);
            }

            // Calculate checksum for the entire font
            if (EnableChecksum)
            {
                writer.BaseStream.Position = entryList.Single(entry => entry.Tag == "head").Offset +
                                             2 * DataTypeLength.Fixed;
                DataTypeConverter.WriteULong(writer,
                                             0xB1B0AFBA - CalculateChecksum(reader, 0, (uint)reader.BaseStream.Length));
            }
        }
示例#3
0
 public void SubsetTo(out OpenTypeFont newFont, HashSet <uint> characters)
 {
     newFont = DeepCopy();
     newFont.Subset(characters);
 }