示例#1
0
        private bool SerializeGlyf(ushort indexFormat)
        {
            Debug.Assert(_glyphs != null && _glyphs.Length != 0);
            Debug.Assert(indexFormat == 0 || indexFormat == 1);

            uint locaOffset  = 0;
            var  glyphWriter = new WoffWriter();

            uint maxCapacity  = 5 * _maxNumPoints;                 // Size without the application of packing.
            var  pointsWriter = new WoffIndexer((int)maxCapacity); // Created here for reuse

            int glyphCount = _glyphs.Length;

            for (ushort i = 0; i < glyphCount; i++)
            {
                var  glyph     = _glyphs[i];
                uint glyphSize = 0;
                pointsWriter.Offset = 0; // Reset the offset, it is non-resizable buffer (size is fixed).
                if (glyph.Serialize(glyphWriter, pointsWriter, out glyphSize) == false)
                {
                    Trace.TraceError("Glyph Serialization Error: Glyph Index = {0}.", glyph.GlyphIndex);
                    return(false);
                }
                _glyphsLocations.Add(locaOffset);
                locaOffset += glyphSize;
            }

            var glyphBuffer = glyphWriter.GetBuffer();

            _woffDir.OrigTable  = glyphBuffer;
            _woffDir.OrigLength = (uint)glyphBuffer.Length;

            return(true);
        }
示例#2
0
 private void Dispose(bool disposing)
 {
     if (!_isDisposed)
     {
         if (disposing)
         {
             if (_writer != null)
             {
                 _writer.Dispose();
                 _writer = null;
             }
         }
         _isDisposed = true;
     }
 }
示例#3
0
        private bool SerializeHmtx(IList <ushort> advanceWidths, IList <short> lsbs, int numOfHMetrics, int numOfGlyphs)
        {
            var hmtxBufferSize = 2 * numOfGlyphs + 2 * numOfHMetrics;

            var writer = new WoffWriter(hmtxBufferSize);

            for (int i = 0; i < numOfGlyphs; i++)
            {
                if (i < numOfHMetrics)
                {
                    writer.WriteUInt16(advanceWidths[i]);
                }
                writer.WriteInt16(lsbs[i]);
            }

            var tableBuffer = writer.GetBuffer();
            var hmtxBuffer  = new WoffBuffer(tableBuffer);

            _woffDir.OrigTable  = tableBuffer;
            _woffDir.OrigLength = (uint)tableBuffer.Length;

            return(true);
        }
示例#4
0
        private bool SerializeLoca()
        {
            var glyfTable = _woffFont.Tables[_glyfIndex] as WoffTableGlyf;

            Debug.Assert(glyfTable != null);
            if (glyfTable == null)
            {
                return(false);
            }

            // indexToLocFormat	0 for short offsets (Offset16), 1 for long (Offset32).
            ushort indexFormat = glyfTable.IndexFormat;

            if (indexFormat != 0 && indexFormat != 1)
            {
                return(false);
            }

            var glyphs          = glyfTable.Glyphs;
            var glyphsLocations = glyfTable.GlyphsLocations;

            var  locaWriter = new WoffWriter();
            uint locaOffset = 0;

            int glyphCount = glyphs.Length;

            for (ushort i = 0; i < glyphCount; i++)
            {
                locaOffset = glyphsLocations[i];

                // indexToLocFormat	0 for short offsets (Offset16), 1 for long (Offset32).
                if (indexFormat == 1)
                {
                    locaWriter.WriteUInt32(locaOffset);
                }
                else
                {
                    var shortOffset = (ushort)(locaOffset >> 1);
                    locaWriter.WriteUInt16(shortOffset);
                }
            }

            //if (locaOffset != glyfDir.OrigLength) //TODO: Needed?
            locaOffset = glyfTable.Length;
            if (indexFormat == 1)
            {
                locaWriter.WriteUInt32(locaOffset);
            }
            else
            {
                var shortOffset = (ushort)(locaOffset >> 1);
                locaWriter.WriteUInt16(shortOffset);
            }

            var locaBuffer = locaWriter.GetBuffer();

            _woffDir.OrigTable  = locaBuffer;
            _woffDir.OrigLength = (uint)locaBuffer.Length;

            return(true);
        }
示例#5
0
        public bool Serialize(WoffWriter writer, WoffIndexer pointsWriter, out uint glyphSize)
        {
            glyphSize = 0;
            if (writer == null)
            {
                return(false);
            }

            uint startOffset = writer.Offset;

            // 1. Write the Glyph Header
            writer.WriteInt16(_numContours); // int16 numberOfContours for number of contours:  >= 0 is simple glyph, < 0 composite glyph.
            writer.WriteInt16(_xMin);        // int16 xMin Minimum x for coordinate data.
            writer.WriteInt16(_yMin);        // int16 yMin Minimum y for coordinate data.
            writer.WriteInt16(_xMax);        // int16 xMax Maximum x for coordinate data.
            writer.WriteInt16(_yMax);        // int16 yMax Maximum y for coordinate data.

            // 2. Write the Simple Glyph Description, if applicable
            if (_glyphType == WoffGlyphType.Simple)
            {
                // uint16	endPtsOfContours[numberOfContours]
                // Array of point indices for the last point of each contour, in increasing numeric order.
                Debug.Assert(_endPtsOfContours != null && _endPtsOfContours.Length == _numContours);
                if (_endPtsOfContours == null || _endPtsOfContours.Length != _numContours)
                {
                    Debug.Assert(false, "Invalid condition.");
                    return(false);
                }
                for (short i = 0; i < _numContours; i++)
                {
                    writer.WriteUInt16(_endPtsOfContours[i]);
                }

                // uint16	instructionLength	Total number of bytes for instructions.
                // If instructionLength is zero, no instructions are present for this glyph,
                // and this field is followed directly by the flags field.instructionLength
                writer.WriteUInt16(_instructionLength);

                // uint8	instructions[instructionLength]	Array of instruction byte code for the glyph.
                if (_instructionLength != 0)
                {
                    Debug.Assert(_instructions != null && _instructions.Length == _instructionLength);
                    if (_instructions == null || _instructions.Length != _instructionLength)
                    {
                        Debug.Assert(false, "Invalid condition.");
                        return(false);
                    }

                    writer.Write(_instructions);
                }

                // Pack the points
                Debug.Assert(_numPoints == _contours.Count);
                int pointsCapacity = 5 * _numPoints; // Size without the application of packing.
                if (pointsWriter == null)
                {
                    pointsWriter = new WoffIndexer(pointsCapacity);
                }
                else
                {
                    pointsWriter.Offset = 0;
                }
                uint pointsLength = 0;

                if (PackPoints(pointsWriter, (uint)pointsCapacity, ref pointsLength) == false)
                {
                    Debug.Assert(false, "Invalid condition.");
                    return(false);
                }

                // Serialize the points...
                writer.Write(pointsWriter.GetBuffer(), 0, (int)pointsLength);
            }
            // Write the Simple Glyph Description, if applicable
            else if (_glyphType == WoffGlyphType.Composite)
            {
                Debug.Assert(_componentLength != 0);
                Debug.Assert(_components != null && _componentLength == _components.Length);
                if (_componentLength == 0 || _components == null || _componentLength != _components.Length)
                {
                    Debug.Assert(false, "Invalid condition.");
                    return(false);
                }

                // Serialize the Composite Glyph data...
                writer.Write(_components, 0, _componentLength);
            }

            // NOTE: Without the padding the serialization of the glyph fails!
            var padBytesLength = WoffBuffer.CalcPadBytes((int)writer.Offset, 4);

            if (padBytesLength > 0)
            {
                var paddingBuffer = new byte[4];
                writer.Write(paddingBuffer, 0, padBytesLength);
            }

            uint endOffset = writer.Offset;

            if (endOffset <= startOffset)
            {
                Debug.Assert(false, "Invalid condition.");
                return(false);
            }
            glyphSize = endOffset - startOffset;

            return(true);
        }
示例#6
0
        /// <summary>
        /// This writes the transformed WOFF2 font collection data to the TTC OpenType.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        /// <remarks>
        /// The strategy is to produce a layout similar to the simple layout used in the WOFF2 data structure and
        /// still confirm to the OpenType format.
        /// <code>
        /// <![CDATA[
        ///  +---------------------+
        ///  |      TTC Header     |
        ///  +---------------------+
        ///  | All TTC Directories |
        ///  +---------------------+
        ///  |  All the Table Data |
        ///  +---------------------+
        /// ]]>
        /// </code>
        /// </remarks>
        private bool WriteWoff2Collection(Stream stream)
        {
            if (stream == null || _woffHeader == null || _woffDirs == null || _woffDirs.Count == 0)
            {
                return(false);
            }

            var numFonts = _collectionHeader.NumFonts;

            //-------------------------------------------------------------------------------------------------
            // 1. Compute the checksums, the paddings of the tables will be recalculated after the transformations.
            for (int i = 0; i < _woffDirs.Count; i++)
            {
                _woffDirs[i].RecalculateChecksum();
            }

            // Compute the sizes of the data structures to determine the offsets...
            // 2. Compute the font collection header size
            int collectionOffset = 0;

            collectionOffset += WoffBuffer.SizeOfUInt;            // TAG	  ttcTag
            collectionOffset += WoffBuffer.SizeOfUShort;          // uint16	  majorVersion
            collectionOffset += WoffBuffer.SizeOfUShort;          // uint16	  minorVersion
            collectionOffset += WoffBuffer.SizeOfUInt;            // uint32	  numFonts
            collectionOffset += WoffBuffer.SizeOfUInt * numFonts; // Offset32 tableDirectoryOffsets[numFonts]
            if (_collectionHeader.IsVersion(2))
            {
                collectionOffset += WoffBuffer.SizeOfUInt;        // uint32	dsigTag
                collectionOffset += WoffBuffer.SizeOfUInt;        // uint32	dsigLength
                collectionOffset += WoffBuffer.SizeOfUInt;        // uint32	dsigOffset
            }

            var headerOffset = (uint)collectionOffset;

            // 3. Compute for each for in the collection the (Header + Directories) size
            // and sum all to get the size/offset of the fonts
            var  directoryOffsets = new uint[numFonts];
            uint directoryOffset  = headerOffset;

            for (ushort i = 0; i < numFonts; i++)
            {
                directoryOffsets[i] = directoryOffset;
                // TableDirectory = HeaderSize + Total Table Records
                var HeaderDirSize = HeaderSize + _collectionEntries[i].NumTables * TableSize;
                directoryOffset += HeaderDirSize;
            }

            // 4. Compute for each directory in the collection the offsets
            uint[] tablesOffsets = new uint[_woffDirs.Count];
            uint   tablesOffset  = directoryOffset;

            for (ushort i = 0; i < _woffDirs.Count; i++)
            {
                var woffDir = _woffDirs[i];
                tablesOffsets[i] = tablesOffset;

                tablesOffset += woffDir.OrigLength;
                if (tablesOffset % 4 != 0)
                {
                    tablesOffset += 4 - (tablesOffset % 4);
                }
            }

            //-------------------------------------------------------------------------------------------------
            // Build the smaller headers + directories data in memory...
            var writer = new WoffWriter();

            // 1. The Font Collection File Structure
            // A font collection file consists of a single TTC Header table, one or more Table Directories
            // (each corresponding to a different font resource), and a number of OpenType tables.
            // The TTC Header must be located at the beginning of the TTC file.
            // TAG	     ttcTag	- Font Collection ID string: 'ttcf'
            writer.WriteUInt32(_collectionHeader.TtcTag);
            // uint16	majorVersion - Major version of the TTC Header.
            writer.WriteUInt16(_collectionHeader.MajorVersion);
            // uint16	minorVersion - Minor version of the TTC Header.
            writer.WriteUInt16(_collectionHeader.MinorVersion);
            // uint32	numFonts - Number of fonts in TTC
            writer.WriteUInt32(_collectionHeader.NumFonts);

            // Offset32	tableDirectoryOffsets[numFonts]	Array of offsets to the TableDirectory for each font from the beginning of the file
            for (ushort i = 0; i < numFonts; i++)
            {
                writer.WriteUInt32(directoryOffsets[i]);
            }

            // For the version 2.0 only add the empty DSIG information.
            if (_collectionHeader.IsVersion(2))
            {
                // uint32	dsigTag - Tag indicating that a DSIG table exists, 0x44534947 ('DSIG') (null if no signature)
                writer.WriteUInt32(_collectionHeader.DsigTag);
                // uint32	dsigLength - The length (in bytes) of the DSIG table (null if no signature)
                writer.WriteUInt32(_collectionHeader.DsigLength);
                // uint32	dsigOffset - The offset (in bytes) of the DSIG table from the beginning of the TTC file (null if no signature)
                writer.WriteUInt32(_collectionHeader.DsigOffset);
            }

            // Write out the header for each font
            uint fontHeaderOffset  = writer.Offset;
            var  fontHeaderOffsets = new List <uint>(numFonts + 1);

            for (ushort j = 0; j < numFonts; j++)
            {
                fontHeaderOffsets.Add(fontHeaderOffset);
                var collectionEntry = _collectionEntries[j];
                var numTables       = collectionEntry.NumTables;

                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(collectionEntry.Flavor);
                // uint16:	numTables	Number of tables.
                writer.WriteUInt16(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);

                var sortedIndices = collectionEntry.SortedIndices;
                for (ushort i = 0; i < numTables; i++)
                {
                    var dirIndex = sortedIndices[i];
                    var woffDir  = _woffDirs[dirIndex];
                    // 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(tablesOffsets[dirIndex]);
                    // uint32	length	Length of this table.
                    writer.WriteUInt32(woffDir.OrigLength);
                }

                fontHeaderOffset += writer.Offset;
            }
            fontHeaderOffsets.Add(fontHeaderOffset);

            // 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
            for (ushort i = 0; i < numFonts; i += 2)
            {
                uint fontOffset = fontHeaderOffsets[i];
                uint fontLength = fontHeaderOffsets[i + 1] - fontOffset;

                _woffFonts[i].ChecksumAdjustment(fontBuffer, fontOffset, fontLength);
            }

            //-------------------------------------------------------------------------------------------------
            // 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 < _woffDirs.Count; i++)
            {
                var woffDir = _woffDirs[i];

                stream.Write(woffDir.OrigTable, 0, (int)woffDir.OrigLength);
                stream.Write(paddingBuffer, 0, (int)woffDir.Padding);
            }

            return(true);
        }
示例#7
0
        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);
        }
示例#8
0
 /// <summary>
 /// Initializes a new non-resizable instance of the <see cref="WoffIndexer"/> class
 /// based on the specified region (index) of a byte array.
 /// </summary>
 /// <param name="buffer">The array of unsigned bytes from which to create this stream.</param>
 /// <param name="index">The index into buffer at which the stream begins.</param>
 /// <param name="count">The length of the stream in bytes.</param>
 public WoffIndexer(byte[] buffer, int index, int count)
 {
     _writer = new WoffWriter(buffer, index, count);
 }
示例#9
0
 ///  Initializes a new non-resizable instance of the <see cref="WoffIndexer"/> class
 ///  based on the specified byte array.
 /// </summary>
 /// <param name="buffer">The array of unsigned bytes from which to create the current stream.</param>
 public WoffIndexer(byte[] buffer)
 {
     _writer = new WoffWriter(buffer);
 }
示例#10
0
 /// <summary>
 /// Initializes a new instance of the <see cref="WoffIndexer"/> class with a non-resizable
 /// capacity initialized as specified.
 /// </summary>
 /// <param name="capacity">The initial size of the internal array in bytes.</param>
 public WoffIndexer(int capacity)
 {
     _writer = new WoffWriter(capacity);
 }
示例#11
0
 /// <summary>
 /// Initializes a new instance of the <see cref="WoffIndexer"/> class with an expandable
 /// capacity initialized to zero.
 /// </summary>
 public WoffIndexer()
 {
     _writer = new WoffWriter();
 }