protected int _locaIndex; // Index = 11 #region Constructors and Destructor public WoffTable(WoffFont woffFont, WoffTableDirectory woffDir) { if (woffFont == null) { throw new ArgumentNullException(nameof(woffFont), "The font object is required by the font table object."); } if (woffDir == null) { throw new ArgumentNullException(nameof(woffDir), "The font directory object is required by the font table object."); } _headIndex = -1; _hheaIndex = -1; _hmtxIndex = -1; _maxpIndex = -1; _nameIndex = -1; _glyfIndex = -1; _locaIndex = -1; _index = ushort.MaxValue; _length = woffDir.OrigLength; _checksum = woffDir.OrigChecksum; _woffDir = woffDir; _woffFont = woffFont; if (!woffFont.IsCollection) { _index = woffDir.WoffIndex; } }
public WoffTableHead(WoffFont woffFont, WoffTableDirectory woffDir) : base(woffFont, woffDir) { var buffer = woffDir.OrigTable; if (buffer != null && buffer.Length >= SizeOfTable) { var length = buffer.Length; _tableBuffer = new WoffBuffer((uint)length); _tableBuffer.Copy(buffer); } }
public WoffTableName(WoffFont woffFont, WoffTableDirectory woffDir) : base(woffFont, woffDir) { var buffer = woffDir.OrigTable; if (buffer != null && buffer.Length >= 6) { var length = buffer.Length; _tableBuffer = new WoffBuffer((uint)length); _tableBuffer.Copy(buffer); } _unicodeNoBOM = new UnicodeEncoding(true, false); }
public WoffTableHhea(WoffFont woffFont, WoffTableDirectory woffDir) : base(woffFont, woffDir) { }
public void AddDirectory(WoffTableDirectory woffDir) { if (woffDir == null) { throw new ArgumentNullException(nameof(woffDir), "The font directory object is required by the font table object."); } if (_woffVersion == WoffUtils.Woff1Version) { _woffDirs.Add(woffDir); if (string.Equals(woffDir.Name, "name", StringComparison.OrdinalIgnoreCase)) { _nameIndex = woffDir.WoffIndex; _woffTables.Add(new WoffTableName(this, woffDir)); } else { _woffTables.Add(new WoffTable(this, woffDir)); } // For WOFF1, not further processing or transformation is required. return; } if (woffDir.IsTransformed) { _isTransformed = true; } var tableIndex = _woffDirs.Count; _woffDirs.Add(woffDir); if (!this.IsCollection) { tableIndex = woffDir.WoffIndex; } var tagIndex = woffDir.Flags & 0x3F; if (_headIndex == -1 || _hheaIndex == -1) { if (_headIndex == -1 && tagIndex == WoffUtils.HeadIndex) // 1 for head { _headIndex = tableIndex; } if (_hheaIndex == -1 && tagIndex == WoffUtils.HheaIndex) // 2 for hhea { _hheaIndex = tableIndex; } } if (_hmtxIndex == -1 || _maxpIndex == -1 || _nameIndex == -1) { if (_hmtxIndex == -1 && tagIndex == WoffUtils.HmtxIndex) // 3 for hmtx { _hmtxIndex = tableIndex; } if (_maxpIndex == -1 && tagIndex == WoffUtils.MaxpIndex) // 4 for hmtx { _maxpIndex = tableIndex; } if (_nameIndex == -1 && tagIndex == WoffUtils.NameIndex) // 5 for name { _nameIndex = tableIndex; } } if (_glyfIndex == -1 || _locaIndex == -1) { if (_glyfIndex == -1 && tagIndex == WoffUtils.GlyfIndex) // 10 for glyf { _glyfIndex = tableIndex; } if (_locaIndex == -1 && tagIndex == WoffUtils.LocaIndex) // 11 for loca { _locaIndex = tableIndex; } } switch (tagIndex) { case WoffUtils.HeadIndex: // head = 1 _woffTables.Add(new WoffTableHead(this, woffDir)); break; case WoffUtils.HheaIndex: // hhea = 2 _woffTables.Add(new WoffTableHhea(this, woffDir)); break; case WoffUtils.HmtxIndex: // hmtx = 3 _woffTables.Add(new WoffTableHmtx(this, woffDir)); break; case WoffUtils.MaxpIndex: // maxp = 4 _woffTables.Add(new WoffTableMaxp(this, woffDir)); break; case WoffUtils.NameIndex: // name = 5 _woffTables.Add(new WoffTableName(this, woffDir)); break; case WoffUtils.GlyfIndex: // glyf = 10 _woffTables.Add(new WoffTableGlyf(this, woffDir)); break; case WoffUtils.LocaIndex: // loca = 11 _woffTables.Add(new WoffTableLoca(this, woffDir)); break; default: // All others _woffTables.Add(new WoffTable(this, woffDir)); break; } }
public WoffTableGlyf(WoffFont woffFont, WoffTableDirectory woffDir) : base(woffFont, woffDir) { _maxNumPoints = 0; _indexFormat = ushort.MaxValue; }
private bool WriteWoff2(Stream stream) { if (_woffHeader.IsCollection) { return(WriteWoff2Collection(stream)); } if (stream == null || _woffHeader == null || _woffDirs == null || _woffDirs.Count == 0) { return(false); } var numTables = _woffHeader.NumTables; // Re-order tables in output order (by the OpenType Specifications) var sortedDirs = _woffDirs.ToArray(); Array.Sort(sortedDirs, WoffTableDirectory.GetComparer()); //------------------------------------------------------------------------------------------------- // 1. Compute the checksums, the paddings of the tables will be recalculated after the transformations. uint tablesChecksum = 0; // We have only one font here... for (int i = 0; i < numTables; i++) { tablesChecksum += sortedDirs[i].RecalculateChecksum(); } //------------------------------------------------------------------------------------------------- // Build the smaller headers + directories data in memory... var writer = new WoffWriter(); var searchRange = (ushort)(WoffUtils.MaxPower2LE(numTables) * TableSize); var entrySelector = WoffUtils.Log2(WoffUtils.MaxPower2LE(numTables)); var rangeShift = (ushort)(numTables * TableSize - searchRange); // Write the font offset table... // uint32: sfntVersion 0x00010000 or 0x4F54544F ('OTTO') writer.WriteUInt32(_woffHeader.Flavor); // uint16: numTables Number of tables. writer.WriteUInt16(_woffHeader.NumTables); // uint16 searchRange (Maximum power of 2 <= numTables) x 16. writer.WriteUInt16(searchRange); // uint16: entrySelector Log2(maximum power of 2 <= numTables). writer.WriteUInt16(entrySelector); // uint16: rangeShift NumTables x 16-searchRange. writer.WriteUInt16(rangeShift); uint tablesOffset = HeaderSize + numTables * TableSize; for (int i = 0; i < numTables; i++) { var woffDir = sortedDirs[i]; // Tag: tableTag Table identifier. writer.WriteUInt32(woffDir.Tag); // uint32: checkSum CheckSum for this table. writer.WriteUInt32(woffDir.OrigChecksum); // Offset32 offset Offset from beginning of TrueType font file. writer.WriteUInt32(tablesOffset); // uint32 length Length of this table. writer.WriteUInt32(woffDir.OrigLength); tablesOffset += woffDir.OrigLength; if (tablesOffset % 4 != 0) { tablesOffset += 4 - (tablesOffset % 4); } } // Get the buffer of the collection header and font headers... var fontBuffer = writer.GetBuffer(); // For the font headers, calculate the checksum to create the font checksum _woffFonts[0].ChecksumAdjustment(fontBuffer, 0, (uint)fontBuffer.Length, tablesChecksum); //------------------------------------------------------------------------------------------------- // Write the actual tables data to the stream, with the required offsets... stream.Write(fontBuffer, 0, fontBuffer.Length); var paddingBuffer = new byte[4]; for (int i = 0; i < numTables; i++) { var woffDir = sortedDirs[i]; stream.Write(woffDir.OrigTable, 0, (int)woffDir.OrigLength); stream.Write(paddingBuffer, 0, (int)woffDir.Padding); } return(true); }
private bool ReadWoff2(Stream stream) { _woffVersion = WoffUtils.Woff2Version; uint sizeRead = 0; // 1. WOFF2Header: File header with basic font type and version, along with offsets // to metadata and private data blocks. _woffHeader = new WoffHeader(WoffUtils.Woff2Version); _woffDirs = null; sizeRead = _woffHeader.HeaderSize; Debug.Assert(sizeRead == WoffUtils.Woff2HeaderSize); if (!_woffHeader.Read(stream)) { return(false); } // 2. TableDirectory: Directory of font tables, containing size and other info. uint offset = 0; _woffDirs = new List <WoffTableDirectory>(_woffHeader.NumTables); for (ushort i = 0; i < _woffHeader.NumTables; i++) { var woffDir = new WoffTableDirectory(i, _woffVersion, offset); if (woffDir.Read(stream, _woffHeader.IsTrueType)) { if (woffDir.IsTransformed) { _isTransformed = true; } _woffDirs.Add(woffDir); offset += woffDir.CompLength; } } // 3. CollectionDirectory: An optional table containing the font fragment descriptions // of font collection entries. if (_woffHeader.IsCollection) { var isLoaded = this.ReadWoff2Fonts(stream); } else { var isLoaded = this.ReadWoff2Font(stream); } // 5. ExtendedMetadata: An optional block of extended metadata, represented in XML format // and compressed for storage in the WOFF2 file. _metadata = new WoffMetadata(_woffHeader.MetaOffset, _woffHeader.MetaLength, _woffHeader.MetaOrigLength); if (_woffHeader.HasMetadata) { stream.Seek(_woffHeader.MetaOffset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)_woffHeader.MetaLength; var metaBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _metadata.Data = metaBuffer; _metadata.OrigData = metaBuffer; if (_woffHeader.MetaLength != _woffHeader.MetaOrigLength) { bytesCount = (int)_woffHeader.MetaOrigLength; using (var brotliStream = new BrotliInputStream(new MemoryStream(metaBuffer))) { var origBuffer = WoffBuffer.ReadBytes(brotliStream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _metadata.OrigData = origBuffer; } } } // 6. PrivateData: An optional block of private data for the font designer, foundry, or vendor to use. _privateData = new WoffPrivateData(_woffHeader.PrivateOffset, _woffHeader.PrivateLength); if (_woffHeader.HasPrivateData) { stream.Seek(_woffHeader.PrivateOffset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)_woffHeader.PrivateLength; var privateBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _privateData.Data = privateBuffer; } return(true); }
private bool ReadWoff1(Stream stream) { _woffVersion = WoffUtils.Woff1Version; var woffFont = new WoffFont(_woffHeader); _woffFonts.Add(woffFont); woffFont.BeginDirectory(_woffVersion); _woffHeader = new WoffHeader(WoffUtils.Woff1Version); _woffDirs = null; int sizeRead = 0; sizeRead = _woffHeader.HeaderSize; Debug.Assert(sizeRead == WoffUtils.Woff1HeaderSize); if (!_woffHeader.Read(stream)) { return(false); } _woffDirs = new List <WoffTableDirectory>(_woffHeader.NumTables); // 2. TableDirectory: Directory of font tables, containing size and other info. for (ushort i = 0; i < _woffHeader.NumTables; i++) { var woffDir = new WoffTableDirectory(i, _woffVersion); if (woffDir.Read(stream)) { _woffDirs.Add(woffDir); woffFont.AddDirectory(woffDir); } } for (int i = 0; i < _woffHeader.NumTables; i++) { var woffDir = _woffDirs[i]; stream.Seek(woffDir.Offset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)woffDir.CompLength; if (bytesCount == 0) { continue; } var tableBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } woffDir.CompTable = tableBuffer; if (woffDir.CompLength == woffDir.OrigLength) { // table data is not compressed woffDir.OrigTable = tableBuffer; } else { bytesCount = (int)woffDir.OrigLength; var origBuffer = new byte[bytesCount]; using (var zlibStream = new ZLibStream(new MemoryStream(tableBuffer), CompressionMode.Decompress, false)) { int bytesStart = 0; do { bytesRead = zlibStream.Read(origBuffer, bytesStart, bytesCount); if (bytesRead == 0) { break; } bytesStart += bytesRead; bytesCount -= bytesRead; } while (bytesCount > 0); } woffDir.OrigTable = origBuffer; } } _metadata = new WoffMetadata(_woffHeader.MetaOffset, _woffHeader.MetaLength, _woffHeader.MetaOrigLength); if (_woffHeader.HasMetadata) { stream.Seek(_woffHeader.MetaOffset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)_woffHeader.MetaLength; var metaBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _metadata.Data = metaBuffer; _metadata.OrigData = metaBuffer; if (_woffHeader.MetaLength != _woffHeader.MetaOrigLength) { bytesCount = (int)_woffHeader.MetaOrigLength; var origBuffer = new byte[bytesCount]; using (var zlibStream = new ZLibStream(new MemoryStream(metaBuffer), CompressionMode.Decompress, false)) { int bytesStart = 0; do { bytesRead = zlibStream.Read(origBuffer, bytesStart, bytesCount); if (bytesRead == 0) { break; } bytesStart += bytesRead; bytesCount -= bytesRead; } while (bytesCount > 0); } _metadata.OrigData = origBuffer; } } _privateData = new WoffPrivateData(_woffHeader.PrivateOffset, _woffHeader.PrivateLength); if (_woffHeader.HasPrivateData) { stream.Seek(_woffHeader.PrivateOffset, SeekOrigin.Begin); int bytesRead = 0; int bytesCount = (int)_woffHeader.PrivateLength; var privateBuffer = WoffBuffer.ReadBytes(stream, bytesCount, out bytesRead); Debug.Assert(bytesRead == bytesCount); if (bytesRead != bytesCount) { return(false); } _privateData.Data = privateBuffer; } woffFont.EndDirectory(); return(true); }