private static uint CalculateChecksum(BinaryReader reader, long startOffset, uint length) { uint checksum = 0; var restorePosition = reader.BaseStream.Position; reader.BaseStream.Position = startOffset; var checkCount = (length + 3) / 4; for (var i = 0; i < checkCount; i++) { checksum += DataTypeConverter.ReadULong(reader); } reader.BaseStream.Position = restorePosition; return(checksum); }
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); }
/// <summary> /// Convert sfnt file to woff file. /// </summary> /// <param name="reader">BinaryReader to read the sfnt data stream.</param> /// <param name="writer">BinaryWriter to write the woff data.</param> /// <param name="compression">Set to true to compress data.</param> public static void SfntToWoff(BinaryReader reader, BinaryWriter writer, bool compression = false) { reader.BaseStream.Position = 0; writer.BaseStream.Position = 0; // Header DataTypeConverter.WriteULong(writer, 0x774F4646); // signature writer.Write(reader.ReadBytes(DataTypeLength.Fixed)); // flavor writer.BaseStream.Position += DataTypeLength.ULong; // length var numberOfTables = DataTypeConverter.ReadUShort(reader); DataTypeConverter.WriteUShort(writer, numberOfTables); // numTables DataTypeConverter.WriteUShort(writer, 0); // reserved DataTypeConverter.WriteULong(writer, (uint)reader.BaseStream.Length); // totalSfntSize DataTypeConverter.WriteUShort(writer, 1); // majorVision DataTypeConverter.WriteUShort(writer, 0); // minorVision DataTypeConverter.WriteULong(writer, 0); // metaOffset DataTypeConverter.WriteULong(writer, 0); // metaLength DataTypeConverter.WriteULong(writer, 0); // metaOriLength DataTypeConverter.WriteULong(writer, 0); // privOffset DataTypeConverter.WriteULong(writer, 0); // privLength // Read original table directory reader.BaseStream.Position += 3 * DataTypeLength.UShort; var tags = new uint[numberOfTables]; var offsets = new uint[numberOfTables]; var compLengths = new uint[numberOfTables]; var origLengths = new uint[numberOfTables]; var origChecksum = new uint[numberOfTables]; var origOffsets = new uint[numberOfTables]; var startOffsetOfTableDirectory = writer.BaseStream.Position; for (var i = 0; i < numberOfTables; i++) { tags[i] = DataTypeConverter.ReadULong(reader); origChecksum[i] = DataTypeConverter.ReadULong(reader); origOffsets[i] = DataTypeConverter.ReadULong(reader); origLengths[i] = DataTypeConverter.ReadULong(reader); } // Table data writer.BaseStream.Position += numberOfTables * 5 * DataTypeLength.ULong; for (var i = 0; i < numberOfTables; i++) { offsets[i] = (uint)writer.BaseStream.Position; reader.BaseStream.Position = origOffsets[i]; var tableData = reader.ReadBytes((int)origLengths[i]); if (compression) { using (var compressedStream = new MemoryStream()) { var zOutputStream = new ZOutputStream(compressedStream, zlibConst.Z_DEFAULT_COMPRESSION); zOutputStream.Write(tableData, 0, (int)origLengths[i]); zOutputStream.finish(); if (compressedStream.Length >= origLengths[i]) { writer.Write(tableData); } else { compressedStream.WriteTo(writer.BaseStream); } } } else { writer.Write(tableData); } compLengths[i] = (uint)(writer.BaseStream.Position - offsets[i]); // 4byte padding if (writer.BaseStream.Position % 4 != 0) { var zeroCount = 4 - writer.BaseStream.Position % 4; for (var j = 0; j < zeroCount; j++) { writer.Write((byte)0); } } } // Write table directory writer.BaseStream.Position = startOffsetOfTableDirectory; for (var i = 0; i < numberOfTables; i++) { DataTypeConverter.WriteULong(writer, tags[i]); DataTypeConverter.WriteULong(writer, offsets[i]); DataTypeConverter.WriteULong(writer, compLengths[i]); DataTypeConverter.WriteULong(writer, origLengths[i]); DataTypeConverter.WriteULong(writer, origChecksum[i]); } // Write length in header writer.BaseStream.Position = 2 * DataTypeLength.ULong; DataTypeConverter.WriteULong(writer, (uint)writer.BaseStream.Length); }