public static byte[] ExtractTTFfromTTC(System.IO.Stream ttc, int ttfHeadOffset) { using (System.IO.MemoryStream ttf = new System.IO.MemoryStream()) { BigEndianReader reader = new BigEndianReader(ttc); reader.Position = ttfHeadOffset; TrueTypeHeader header; if (TrueTypeHeader.TryReadHeader(reader, out header) == false) { throw new NotSupportedException("The current stream is not a supported OpenType or TrueType font file"); } List <TrueTypeTableEntry> dirs; try { dirs = new List <TrueTypeTableEntry>(); for (int i = 0; i < header.NumberOfTables; i++) { TrueTypeTableEntry dir = new TrueTypeTableEntry(); dir.Read(reader); dirs.Add(dir); } } catch (TypefaceReadException) { throw; } catch (Exception ex) { throw new TypefaceReadException("Could not read the TTF File", ex); } BigEndianWriter writer = new BigEndianWriter(ttf); writer.Write(header.Version.HeaderData); writer.WriteUInt16((ushort)header.NumberOfTables); writer.WriteUInt16((ushort)header.SearchRange); writer.WriteUInt16((ushort)header.EntrySelector); writer.WriteUInt16((ushort)header.RangeShift); long[] dirOffsets = new long[dirs.Count]; //Set to the byte position of the Offset32 in the header to point to the table long[] tableOffsets = new long[dirs.Count]; //Set to the byte position of the table in the file for (var i = 0; i < dirs.Count; i++) { var dir = dirs[i]; writer.WriteASCIIChars(dir.Tag); writer.WriteUInt32(dir.CheckSum); //Write zero as the offset initially and then we will come back and update dirOffsets[i] = writer.Position; writer.WriteUInt32(0); writer.WriteUInt32(dir.Length); } for (var i = 0; i < dirs.Count; i++) { var dir = dirs[i]; while (writer.Position % 4 != 0) { writer.WriteByte(Zero); } //Remember the start position of the table tableOffsets[i] = writer.Position; reader.Position = dir.Offset; //we can improve this var data = reader.Read((int)dir.Length); writer.Write(data); } for (int i = 0; i < dirs.Count; i++) { writer.Position = dirOffsets[i]; writer.WriteUInt32((uint)tableOffsets[i]); } writer.Position = 0; var fileData = ttf.ToArray(); return(fileData); } }
/// <summary> /// Performs the actual reading and loading of the file with the BigEndian reader /// </summary> /// <param name="reader"></param> /// <param name="fullpath"></param> /// <returns></returns> private static TTFRef DoLoadRef(BigEndianReader reader, string fullpath) { TrueTypeHeader head; if (TrueTypeHeader.TryReadHeader(reader, out head) == false) { return(null); } TrueTypeTableEntryList list = new TrueTypeTableEntryList(); bool hasOs2 = false; bool hasFHead = false; bool hasName = false; for (int i = 0; i < head.NumberOfTables; i++) { TrueTypeTableEntry dir = new TrueTypeTableEntry(); dir.Read(reader); list.Add(dir); if (dir.Tag == TrueTypeTableNames.WindowsMetrics) { hasOs2 = true; } else if (dir.Tag == TrueTypeTableNames.FontHeader) { hasFHead = true; } else if (dir.Tag == TrueTypeTableNames.NamingTable) { hasName = true; } } TrueTypeTableFactory fact = (head.Version as TrueTypeVersionReader).GetTableFactory(); SubTables.NamingTable ntable = null; if (hasName) { ntable = fact.ReadTable(TrueTypeTableNames.NamingTable, list, reader) as SubTables.NamingTable; } else { throw new ArgumentNullException("The required '" + TrueTypeTableNames.NamingTable + "' is not present in this font file. The OpenType file is corrupt"); } //if (fhead == null) // throw new ArgumentNullException("The required '" + FontHeaderTable + "' is not present in this font file. The OpenType file is corrupt"); TTFRef ttfref = new TTFRef(fullpath); NameEntry entry; int FamilyNameID = 1; if (ntable.Names.TryGetEntry(FamilyNameID, out entry)) { ttfref.FamilyName = entry.ToString(); } if (hasOs2) { SubTables.OS2Table os2table = fact.ReadTable(TrueTypeTableNames.WindowsMetrics, list, reader) as SubTables.OS2Table; ttfref.FontRestrictions = os2table.FSType; ttfref.FontWidth = os2table.WidthClass; ttfref.FontWeight = os2table.WeightClass; ttfref.FontSelection = os2table.Selection; } else if (hasFHead) { SubTables.FontHeader fhead = fact.ReadTable(TrueTypeTableNames.FontHeader, list, reader) as SubTables.FontHeader; var mac = fhead.MacStyle; ttfref.FontRestrictions = FontRestrictions.InstallableEmbedding; ttfref.FontWeight = WeightClass.Normal; if ((mac & FontStyleFlags.Condensed) > 0) { ttfref.FontWidth = WidthClass.Condensed; } else if ((mac & FontStyleFlags.Extended) > 0) { ttfref.FontWidth = WidthClass.Expanded; } ttfref.FontSelection = 0; if ((mac & FontStyleFlags.Italic) > 0) { ttfref.FontSelection |= FontSelection.Italic; } if ((mac & FontStyleFlags.Bold) > 0) { ttfref.FontSelection |= FontSelection.Bold; ttfref.FontWeight = WeightClass.Bold; } if ((mac & FontStyleFlags.Outline) > 0) { ttfref.FontSelection |= FontSelection.Outlined; } if ((mac & FontStyleFlags.Underline) > 0) { ttfref.FontSelection |= FontSelection.Underscore; } } else { throw new ArgumentNullException("The required '" + TrueTypeTableNames.WindowsMetrics + "' or '" + TrueTypeTableNames.FontHeader + " are not present in this font file. The OpenType file is corrupt"); } return(ttfref); }