Exemple #1
0
        public static GlyphDataTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table, TableRegister.Builder tableRegister)
        {
            data.Seek(table.Offset);

            var indexToLocationTable = tableRegister.IndexToLocationTable;

            var offsets = indexToLocationTable.GlyphOffsets;

            var entryCount = offsets.Length;

            var glyphCount = entryCount - 1;

            var glyphs = new IGlyphDescription[glyphCount];

            var emptyGlyph = Glyph.Empty(tableRegister.HeaderTable.Bounds);

            var compositeLocations = new Dictionary <int, TemporaryCompositeLocation>();

            for (var i = 0; i < glyphCount; i++)
            {
                if (offsets[i] == offsets[i + 1])
                {
                    // empty glyph
                    glyphs[i] = emptyGlyph;
                    continue;
                }

                data.Seek(offsets[i] + table.Offset);

                var contourCount = data.ReadSignedShort();

                var minX = data.ReadSignedShort();
                var minY = data.ReadSignedShort();
                var maxX = data.ReadSignedShort();
                var maxY = data.ReadSignedShort();

                var bounds = new PdfRectangle(minX, minY, maxX, maxY);

                // If the number of contours is greater than or equal zero it's a simple glyph.
                if (contourCount >= 0)
                {
                    glyphs[i] = ReadSimpleGlyph(data, contourCount, bounds);
                }
                else
                {
                    compositeLocations.Add(i, new TemporaryCompositeLocation(data.Position, bounds, contourCount));
                }
            }

            // Build composite glyphs by combining simple and other composite glyphs.
            foreach (var compositeLocation in compositeLocations)
            {
                glyphs[compositeLocation.Key] = ReadCompositeGlyph(data, compositeLocation.Value, compositeLocations, glyphs, emptyGlyph);
            }

            return(new GlyphDataTable(table, glyphs));
        }
        public static HorizontalMetricsTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table, TableRegister.Builder tableRegister)
        {
            var glyphCount  = tableRegister.MaximumProfileTable.NumberOfGlyphs;
            var metricCount = tableRegister.HorizontalHeaderTable.NumberOfHeaderMetrics;

            data.Seek(table.Offset);

            // The number of entries in the left side bearing field per entry is number of glyphs - number of metrics
            var additionalLeftSideBearingLength = glyphCount - metricCount;

            var advancedWidths = new int[metricCount];

            // For bearings over the metric count, the width is the same as the last width in advanced widths.
            var leftSideBearings = new short[glyphCount];

            for (var i = 0; i < metricCount; i++)
            {
                advancedWidths[i]   = data.ReadUnsignedShort();
                leftSideBearings[i] = data.ReadSignedShort();
            }

            for (var i = 0; i < additionalLeftSideBearingLength; i++)
            {
                leftSideBearings[metricCount + i] = data.ReadSignedShort();
            }

            return(new HorizontalMetricsTable(table, advancedWidths, leftSideBearings, metricCount));
        }
        public static IndexToLocationTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table, TableRegister.Builder tableRegister)
        {
            const short shortFormat = 0;
            const short longFormat  = 1;

            data.Seek(table.Offset);

            var headerTable         = tableRegister.HeaderTable;
            var maximumProfileTable = tableRegister.MaximumProfileTable;

            var format = headerTable.IndexToLocFormat;

            var glyphCount = maximumProfileTable.NumberOfGlyphs + 1;

            var offsets = new long[glyphCount];

            switch (format)
            {
            case shortFormat:
            {         // The local offset divided by 2 is stored.
                for (int i = 0; i < glyphCount; i++)
                {
                    offsets[i] = data.ReadUnsignedShort() * 2;
                }
                break;
            }

            case longFormat:
            {
                // The actual offset is stored.
                data.ReadUnsignedIntArray(offsets, glyphCount);
                break;
            }

            default:
                throw new InvalidOperationException($"The format {format} was invalid for the index to location (loca) table.");
            }


            return(new IndexToLocationTable(table, offsets));
        }
Exemple #4
0
        public static GlyphDataTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table, TableRegister.Builder tableRegister)
        {
            data.Seek(table.Offset);

            var bytes = data.ReadByteArray((int)table.Length);

            return(new GlyphDataTable(table, tableRegister.IndexToLocationTable.GlyphOffsets,
                                      tableRegister.HeaderTable.Bounds,
                                      new TrueTypeDataBytes(bytes)));
        }
Exemple #5
0
        /// <summary>
        /// Load the index to location (loca) table from the TrueType font. Requires the maximum profile (maxp) and header (head) table
        /// to have been parsed.
        /// </summary>
        internal static IndexToLocationTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table, TableRegister.Builder tableRegister)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            if (tableRegister == null)
            {
                throw new ArgumentNullException(nameof(tableRegister));
            }

            data.Seek(table.Offset);

            var headerTable         = tableRegister.HeaderTable;
            var maximumProfileTable = tableRegister.MaximumProfileTable;

            if (headerTable == null)
            {
                throw new InvalidFontFormatException("No header (head) table was defined in this font.");
            }

            if (maximumProfileTable == null)
            {
                throw new InvalidFontFormatException("No maximum profile (maxp) table was defined in this font.");
            }

            var format = (EntryFormat)headerTable.IndexToLocFormat;

            var glyphCount = maximumProfileTable.NumberOfGlyphs + 1;

            uint[] offsets;

            switch (format)
            {
            case EntryFormat.Short:
            {
                // The local offset divided by 2 is stored.
                offsets = new uint[glyphCount];
                for (var i = 0; i < glyphCount; i++)
                {
                    offsets[i] = (uint)(data.ReadUnsignedShort() * 2);
                }
                break;
            }

            case EntryFormat.Long:
            {
                // The actual offset is stored.
                offsets = data.ReadUnsignedIntArray(glyphCount);
                break;
            }

            default:
                throw new InvalidOperationException($"The format {format} was invalid for the index to location (loca) table.");
            }


            return(new IndexToLocationTable(table, format, offsets));
        }
Exemple #6
0
        public static CMapTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table, TableRegister.Builder tableRegister)
        {
            data.Seek(table.Offset);

            var tableVersionNumber = data.ReadUnsignedShort();

            var numberOfEncodingTables = data.ReadUnsignedShort();

            var subTableHeaders = new SubTableHeaderEntry[numberOfEncodingTables];

            for (int i = 0; i < numberOfEncodingTables; i++)
            {
                var platformId = data.ReadUnsignedShort();
                var encodingId = data.ReadUnsignedShort();
                var offset     = data.ReadUnsignedInt();

                subTableHeaders[i] = new SubTableHeaderEntry(platformId, encodingId, offset);
            }

            var tables = new List <ICMapSubTable>(numberOfEncodingTables);

            var numberofGlyphs = tableRegister.MaximumProfileTable.NumberOfGlyphs;

            for (var i = 0; i < subTableHeaders.Length; i++)
            {
                var header = subTableHeaders[i];

                data.Seek(table.Offset + header.Offset);

                var format = data.ReadUnsignedShort();

                /*
                 * There are 9 currently available formats:
                 * 0: Character code and glyph indices are restricted to a single byte. Rare.
                 * 2: Suitable for CJK characters. Contain mixed 8/16 byte encoding.
                 * 4: 2 byte encoding format. Used when character codes fall into (gappy) contiguous ranges.
                 * 6: 'Trimmed table mapping', used when character codes fall into a single contiguous range. This is dense mapping.
                 * 8: 16/32 bit coverage. Uses mixed length character codes.
                 * 10: Similar to format 6, trimmed table/array for 32 bits.
                 * 12: Segmented coverage, similar to format 4 but for 32 bit/4 byte.
                 * 13: Many to one mappings. Used by Apple for the LastResort font.
                 * 14: Unicode variation sequences.
                 *
                 * Many of the formats are obsolete or not really used. Modern fonts will tend to use formats 4, 6 and 12.
                 * For PDF we will support 0, 2 and 4 since these are in the original TrueType spec.
                 */
                switch (format)
                {
                case 0:
                {
                    // Simple 1 to 1 mapping of character codes to glyph codes.
                    var item = ByteEncodingCMapTable.Load(data, header.PlatformId, header.EncodingId);
                    tables.Add(item);
                    break;
                }

                case 2:
                {
                    // Useful for CJK characters. Use mixed 8/16 bit encoding.
                    var item = HighByteMappingCMapTable.Load(data, numberofGlyphs, header.PlatformId, header.EncodingId);
                    tables.Add(item);
                    break;
                }

                case 4:
                {
                    // Microsoft's standard mapping table.
                    var item = Format4CMapTable.Load(data, header.PlatformId, header.EncodingId);
                    tables.Add(item);
                    break;
                }

                case 6:
                {
                    var item = TrimmedTableMappingCMapTable.Load(data, header.PlatformId, header.EncodingId);
                    tables.Add(item);
                    break;
                }
                }
            }

            return(new CMapTable(tableVersionNumber, table, tables));
        }