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);
            }
        }
Example #2
0
        private void DoWriteWoffToTTF(MemoryStream ms)
        {
            var dirs = this.Directories.ToArray();

            BigEndianWriter writer = new BigEndianWriter(ms);

            writer.Write(TypefaceVersionReader.TrueTypeHeaderBytes);
            writer.WriteUInt16((ushort)dirs.Length);

            var checkOffset = ms.Position;

            ushort max2 = 2;

            while (max2 * 2 <= this.Directories.Count)
            {
                max2 *= 2;
            }

            ushort search = (ushort)(max2 * 16);
            ushort entry  = (ushort)Math.Log(max2, 2);
            ushort range  = (ushort)((dirs.Length * 16) - search);

            writer.WriteUInt16(search);
            writer.WriteUInt16(entry);
            writer.WriteUInt16(range);

            var offset       = writer.Position;
            var dirOffsets   = new long[dirs.Length];
            var tableOffsets = new long[dirs.Length];

            for (int i = 0; i < dirs.Length; i++)
            {
                var dir = dirs[i] as WoffTableEntry;

                if (dir.DecompressedData == null)
                {
                    throw new InvalidOperationException("The directrory " + dir.Tag + " does not have any decompressed data");
                }

                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.Length; i++)
            {
                var dir = dirs[i] as WoffTableEntry;

                //pad to 4 bytes
                while (writer.Position % 4 != 0)
                {
                    writer.WriteByte(Zero);
                }

                //remember the position and write the decompressed data
                tableOffsets[i] = writer.Position;
                writer.Write(dir.DecompressedData);
            }

            //Now go back and update the positions

            for (int i = 0; i < dirs.Length; i++)
            {
                writer.Position = dirOffsets[i];
                writer.WriteUInt32((uint)tableOffsets[i]);
            }
        }