Пример #1
0
        private static SimpleGlyphDescription ReadSimpleGlyph(TrueTypeDataBytes data, short contourCount, PdfRectangle bounds)
        {
            var endPointsOfContours = data.ReadUnsignedShortArray(contourCount);

            var instructionLength = data.ReadUnsignedShort();

            data.ReadByteArray(instructionLength);

            var pointCount = 0;

            if (contourCount > 0)
            {
                pointCount = endPointsOfContours[contourCount - 1] + 1;
            }

            var flags = ReadFlags(data, pointCount);

            var xCoordinates = ReadCoordinates(data, pointCount, flags, SimpleGlyphFlags.XShortVector,
                                               SimpleGlyphFlags.XSignOrSame);

            var yCoordinates = ReadCoordinates(data, pointCount, flags, SimpleGlyphFlags.YShortVector,
                                               SimpleGlyphFlags.YSignOrSame);

            return(new SimpleGlyphDescription(instructionLength, endPointsOfContours, flags, xCoordinates, yCoordinates, bounds));
        }
Пример #2
0
        public TrueTypeFontProgram Parse(TrueTypeDataBytes data)
        {
            var version        = (decimal)data.Read32Fixed();
            int numberOfTables = data.ReadUnsignedShort();

            // Read these data points to move to the correct data location.
            // ReSharper disable UnusedVariable
            int searchRange   = data.ReadUnsignedShort();
            int entrySelector = data.ReadUnsignedShort();
            int rangeShift    = data.ReadUnsignedShort();
            // ReSharper restore UnusedVariable

            var tables = new Dictionary <string, TrueTypeHeaderTable>();

            for (var i = 0; i < numberOfTables; i++)
            {
                var table = ReadTable(data);

                if (table.HasValue)
                {
                    tables[table.Value.Tag] = table.Value;
                }
            }

            var result = ParseTables(version, tables, data);

            return(result);
        }
Пример #3
0
        public static HorizontalMetricsTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table, TableRegister 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));
        }
Пример #4
0
        private static short[] ReadCoordinates(TrueTypeDataBytes data, int pointCount, SimpleGlyphFlags[] flags, SimpleGlyphFlags isByte, SimpleGlyphFlags signOrSame)
        {
            var xs = new short[pointCount];
            var x  = 0;

            for (var i = 0; i < pointCount; i++)
            {
                int dx;
                if (flags[i].HasFlag(isByte))
                {
                    var b = data.ReadByte();
                    dx = flags[i].HasFlag(signOrSame) ? b : -b;
                }
                else
                {
                    if (flags[i].HasFlag(signOrSame))
                    {
                        dx = 0;
                    }
                    else
                    {
                        dx = data.ReadSignedShort();
                    }
                }

                x += dx;

                xs[i] = (short)x;
            }

            return(xs);
        }
Пример #5
0
        private static Glyph ReadSimpleGlyph(TrueTypeDataBytes data, short contourCount, PdfRectangle bounds)
        {
            var endPointsOfContours = data.ReadUnsignedShortArray(contourCount);

            var instructionLength = data.ReadUnsignedShort();

            var instructions = data.ReadByteArray(instructionLength);

            var pointCount = 0;

            if (contourCount > 0)
            {
                pointCount = endPointsOfContours[contourCount - 1] + 1;
            }

            var flags = ReadFlags(data, pointCount);

            var xCoordinates = ReadCoordinates(data, pointCount, flags, SimpleGlyphFlags.XShortVector,
                                               SimpleGlyphFlags.XSignOrSame);

            var yCoordinates = ReadCoordinates(data, pointCount, flags, SimpleGlyphFlags.YShortVector,
                                               SimpleGlyphFlags.YSignOrSame);

            var points = new GlyphPoint[xCoordinates.Length];

            for (var i = xCoordinates.Length - 1; i >= 0; i--)
            {
                var isOnCurve = (flags[i] & SimpleGlyphFlags.OnCurve) == SimpleGlyphFlags.OnCurve;
                points[i] = new GlyphPoint(xCoordinates[i], yCoordinates[i], isOnCurve);
            }

            return(new Glyph(true, instructions, endPointsOfContours, points, bounds));
        }
Пример #6
0
        public void ParseAndadaRegular()
        {
            var bytes = GetFileBytes("Andada-Regular");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = parser.Parse(input);

            Assert.NotNull(font.TableRegister.GlyphTable);

            var name = font.Name;

            Assert.Equal("Andada Regular", name);

            Assert.Equal(1.001999m, font.TableRegister.HeaderTable.Revision);

            Assert.Equal(11, font.TableRegister.HeaderTable.Flags);

            Assert.Equal(1000, font.TableRegister.HeaderTable.UnitsPerEm);

            Assert.Equal(2011, font.TableRegister.HeaderTable.Created.Year);
            Assert.Equal(9, font.TableRegister.HeaderTable.Created.Month);
            Assert.Equal(30, font.TableRegister.HeaderTable.Created.Day);

            Assert.Equal(2017, font.TableRegister.HeaderTable.Modified.Year);
            Assert.Equal(5, font.TableRegister.HeaderTable.Modified.Month);
            Assert.Equal(4, font.TableRegister.HeaderTable.Modified.Day);
        }
Пример #7
0
        public static BasicMaximumProfileTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table)
        {
            data.Seek(table.Offset);

            var version        = data.Read32Fixed();
            var numberOfGlyphs = data.ReadUnsignedShort();

            if (Math.Abs(version - 0.5) < float.Epsilon)
            {
                return(new BasicMaximumProfileTable(table, version, numberOfGlyphs));
            }

            var maxPoints            = data.ReadUnsignedShort();
            var maxContours          = data.ReadUnsignedShort();
            var maxCompositePoints   = data.ReadUnsignedShort();
            var maxCompositeContours = data.ReadUnsignedShort();

            var maxZones              = data.ReadUnsignedShort();
            var maxTwilightPoints     = data.ReadUnsignedShort();
            var maxStorage            = data.ReadUnsignedShort();
            var maxFunctionDefs       = data.ReadUnsignedShort();
            var maxInstructionDefs    = data.ReadUnsignedShort();
            var maxStackElements      = data.ReadUnsignedShort();
            var maxSizeOfInstructions = data.ReadUnsignedShort();
            var maxComponentElements  = data.ReadUnsignedShort();
            var maxComponentDepth     = data.ReadUnsignedShort();

            return(new MaximumProfileTable(table, version, numberOfGlyphs, maxPoints,
                                           maxContours, maxCompositePoints, maxCompositeContours, maxZones,
                                           maxTwilightPoints, maxStorage, maxFunctionDefs, maxInstructionDefs,
                                           maxStackElements, maxSizeOfInstructions, maxComponentElements,
                                           maxComponentDepth));
        }
Пример #8
0
        public NameTable Parse(TrueTypeHeaderTable header, TrueTypeDataBytes data, TableRegister.Builder register)
        {
            data.Seek(header.Offset);
            // ReSharper disable once UnusedVariable
            var format       = data.ReadUnsignedShort();
            var count        = data.ReadUnsignedShort();
            var stringOffset = data.ReadUnsignedShort();

            var names = new NameRecordBuilder[count];

            for (var i = 0; i < count; i++)
            {
                names[i] = NameRecordBuilder.Read(data);
            }

            var strings = new TrueTypeNameRecord[count];
            var offset  = header.Offset + stringOffset;

            for (var i = 0; i < count; i++)
            {
                strings[i] = GetTrueTypeNameRecord(names[i], data, offset);
            }

            return(new NameTable(header, GetName(4, strings), GetName(1, strings), GetName(2, strings), strings));
        }
Пример #9
0
        public static KerningTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable headerTable)
        {
            data.Seek(headerTable.Offset);

            var version = data.ReadUnsignedShort();

            var numberOfSubtables = data.ReadUnsignedShort();

            var subTables = new KerningSubTable[numberOfSubtables];

            for (var i = 0; i < numberOfSubtables; i++)
            {
                var currentOffset = data.Position;

                var subtableVersion = data.ReadUnsignedShort();
                var subtableLength  = data.ReadUnsignedShort();
                var coverage        = data.ReadUnsignedShort();

                var kernCoverage = (KernCoverage)coverage;
                var format       = ((coverage & 255) >> 8);

                switch (format)
                {
                case 0:
                    subTables[i] = ReadFormat0Table(subtableVersion, data, kernCoverage);
                    break;

                case 2:
                    subTables[i] = ReadFormat2Table(subtableVersion, data, kernCoverage, currentOffset);
                    break;
                }
            }

            return(new KerningTable(subTables));
        }
Пример #10
0
        public GlyphDataTable(TrueTypeHeaderTable directoryTable, IReadOnlyList <uint> glyphOffsets,
                              PdfRectangle maxGlyphBounds,
                              TrueTypeDataBytes tableBytes)
        {
            this.glyphOffsets   = glyphOffsets;
            this.maxGlyphBounds = maxGlyphBounds;
            this.tableBytes     = tableBytes;
            DirectoryTable      = directoryTable;
            if (tableBytes == null)
            {
                throw new ArgumentNullException(nameof(tableBytes));
            }

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

            if (tableBytes.Length != directoryTable.Length)
            {
                throw new ArgumentException($"glyf table data should match length of directory entry. Expected: {directoryTable.Length}. Actual: {tableBytes.Length}.");
            }

            glyphs = new Lazy <IReadOnlyList <IGlyphDescription> >(ReadGlyphs);
        }
Пример #11
0
        public NameTable GetNameTable(TrueTypeDataBytes data)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            // Read these data points to move to the correct data location.
            data.Read32Fixed();
            int numberOfTables = data.ReadUnsignedShort();

            data.ReadUnsignedShort();
            data.ReadUnsignedShort();
            data.ReadUnsignedShort();

            TrueTypeHeaderTable?name = null;

            for (var i = 0; i < numberOfTables; i++)
            {
                var tableHeader = ReadTable(data);

                if (tableHeader.HasValue && tableHeader.Value.Tag == TrueTypeHeaderTable.Name)
                {
                    name = tableHeader;
                    break;
                }
            }

            if (!name.HasValue)
            {
                return(null);
            }

            return(TableParser.Parse <NameTable>(name.Value, data, new TableRegister.Builder()));
        }
Пример #12
0
        private ICidFontProgram ReadDescriptorFile(FontDescriptor descriptor)
        {
            if (descriptor?.FontFile == null)
            {
                return(null);
            }

            var fontFileStream = DirectObjectFinder.Get <StreamToken>(descriptor.FontFile.ObjectKey, pdfScanner);

            if (fontFileStream == null)
            {
                return(null);
            }

            var fontFile = fontFileStream.Decode(filterProvider);

            switch (descriptor.FontFile.FileType)
            {
            case DescriptorFontFile.FontFileType.TrueType:
                var input = new TrueTypeDataBytes(new ByteArrayInputBytes(fontFile));
                return(trueTypeFontParser.Parse(input));

            default:
                throw new NotSupportedException("Currently only TrueType fonts are supported.");
            }
        }
Пример #13
0
        private ICidFontProgram ReadDescriptorFile(FontDescriptor descriptor)
        {
            if (descriptor?.FontFile == null)
            {
                return(null);
            }

            var fontFileStream = DirectObjectFinder.Get <StreamToken>(descriptor.FontFile.ObjectKey, pdfScanner);

            if (fontFileStream == null)
            {
                return(null);
            }

            var fontFile = fontFileStream.Decode(filterProvider);

            switch (descriptor.FontFile.FileType)
            {
            case DescriptorFontFile.FontFileType.TrueType:
                var input = new TrueTypeDataBytes(new ByteArrayInputBytes(fontFile));
                return(trueTypeFontParser.Parse(input));

            case DescriptorFontFile.FontFileType.FromSubtype:
            {
                if (!DirectObjectFinder.TryGet(descriptor.FontFile.ObjectKey, pdfScanner, out StreamToken str))
                {
                    throw new NotSupportedException("Cannot read CID font from subtype.");
                }

                if (!str.StreamDictionary.TryGet(NameToken.Subtype, out NameToken subtypeName))
                {
                    throw new PdfDocumentFormatException($"The font file stream did not contain a subtype entry: {str.StreamDictionary}.");
                }

                if (subtypeName == NameToken.CidFontType0C)
                {
                    var bytes = str.Decode(filterProvider);
                    var font  = compactFontFormatParser.Parse(new CompactFontFormatData(bytes));
                    return(font);
                }

                if (subtypeName == NameToken.Type1C)
                {
                }
                else if (subtypeName == NameToken.OpenType)
                {
                }
                else
                {
                    throw new PdfDocumentFormatException($"Unexpected subtype for CID font: {subtypeName}.");
                }

                throw new NotSupportedException("Cannot read CID font from subtype.");
            }

            default:
                throw new NotSupportedException("Currently only TrueType fonts are supported.");
            }
        }
Пример #14
0
        public void ParsePMingLiU()
        {
            var bytes = GetFileBytes("PMingLiU");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = parser.Parse(input);
        }
Пример #15
0
        public void ParseEmbeddedSimpleGoogleDocssGautmi()
        {
            var bytes = GetFileBytes("google-simple-doc");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            parser.Parse(input);
        }
Пример #16
0
        /// <summary>
        /// Read the header table from the data stream.
        /// </summary>
        public static HeaderTable Load(TrueTypeDataBytes data, TrueTypeHeaderTable table)
        {
            data.Seek(table.Offset);
            var version            = data.Read32Fixed();
            var fontRevision       = data.Read32Fixed();
            var checkSumAdjustment = data.ReadUnsignedInt();
            var magicNumber        = data.ReadUnsignedInt();

            if (magicNumber != 0x5F0F3CF5)
            {
                throw new InvalidOperationException("The magic number for this TrueType font was incorrect. Value was: " + magicNumber);
            }

            var flags      = data.ReadUnsignedShort();
            var unitsPerEm = data.ReadUnsignedShort();

            if (unitsPerEm < 16 || unitsPerEm > 16384)
            {
                throw new InvalidOperationException($"The units per em for this TrueType font was incorrect, value should be between 16 and 16384 but found {unitsPerEm} istead.");
            }

            DateTime created;

            try
            {
                created = data.ReadInternationalDate();
            }
            catch (InvalidFontFormatException)
            {
                created = DateTime.MinValue;
            }

            DateTime modified;

            try
            {
                modified = data.ReadInternationalDate();
            }
            catch (InvalidFontFormatException)
            {
                modified = DateTime.MinValue;
            }

            var xMin              = data.ReadSignedShort();
            var yMin              = data.ReadSignedShort();
            var xMax              = data.ReadSignedShort();
            var yMax              = data.ReadSignedShort();
            var macStyle          = data.ReadUnsignedShort();
            var lowestRecPpem     = data.ReadUnsignedShort();
            var fontDirectionHint = data.ReadSignedShort();
            var indexToLocFormat  = (IndexToLocationTable.EntryFormat)data.ReadSignedShort();
            var glyphDataFormat   = data.ReadSignedShort();

            return(new HeaderTable(table, version, fontRevision, checkSumAdjustment,
                                   magicNumber, flags, unitsPerEm, created, modified,
                                   xMin, yMin, xMax, yMax, macStyle, lowestRecPpem,
                                   fontDirectionHint, indexToLocFormat, glyphDataFormat));
        }
Пример #17
0
        private static void ReadSimpleGlyph(TrueTypeDataBytes data, int numberOfContours)
        {
            bool HasFlag(SimpleGlyphFlags flags, SimpleGlyphFlags value)
            {
                return((flags & value) != 0);
            }

            if (numberOfContours == 0)
            {
                return;
            }

            var endPointsOfContours = new ushort[numberOfContours];

            for (var i = 0; i < numberOfContours; i++)
            {
                endPointsOfContours[i] = data.ReadUnsignedShort();
            }

            var instructionLength = data.ReadUnsignedShort();

            var instructions = new byte[instructionLength];

            for (var i = 0; i < instructionLength; i++)
            {
                instructions[i] = data.ReadByte();
            }

            var lastPointIndex = endPointsOfContours[numberOfContours - 1];

            var pointCount = lastPointIndex + 1;

            var perPointFlags = new SimpleGlyphFlags[pointCount];

            for (var i = 0; i < pointCount; i++)
            {
                var flags = (SimpleGlyphFlags)data.ReadByte();

                perPointFlags[i] = flags;
                if (!HasFlag(flags, SimpleGlyphFlags.Repeat))
                {
                    continue;
                }

                var numberOfRepeats = data.ReadByte();
                for (var r = 0; r < numberOfRepeats; r++)
                {
                    i++;
                    perPointFlags[i] = flags;
                }
            }

            // ReSharper disable UnusedVariable
            var xCoordinates = ReadCoordinates(perPointFlags, data, SimpleGlyphFlags.XSingleByte, SimpleGlyphFlags.ThisXIsTheSame);

            var yCoordinates = ReadCoordinates(perPointFlags, data, SimpleGlyphFlags.YSingleByte, SimpleGlyphFlags.ThisYIsTheSame);
            // ReSharper restore UnusedVariable
        }
Пример #18
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));
        }
Пример #19
0
 public static NameRecordBuilder Read(TrueTypeDataBytes data)
 {
     return(new NameRecordBuilder(data.ReadUnsignedShort(),
                                  data.ReadUnsignedShort(),
                                  data.ReadUnsignedShort(),
                                  data.ReadUnsignedShort(),
                                  data.ReadUnsignedShort(),
                                  data.ReadUnsignedShort()));
 }
Пример #20
0
        public static Format4CMapTable Load(TrueTypeDataBytes data, int platformId, int encodingId)
        {
            // Length in bytes.
            var length = data.ReadUnsignedShort();

            // Used for sub-tables with a Macintosh platform ID.
            var version = data.ReadUnsignedShort();

            var doubleSegmentCount = data.ReadUnsignedShort();

            // Defines the number of contiguous segments.
            var segmentCount = doubleSegmentCount / 2;

            // Some crazy sum.
            var searchRange   = data.ReadUnsignedShort();
            var entrySelector = data.ReadUnsignedShort();
            var rangeShift    = data.ReadUnsignedShort();

            // End character codes for each segment.
            var endCounts = data.ReadUnsignedShortArray(segmentCount);

            // Should be zero.
            var reservedPad = data.ReadUnsignedShort();

            // Start character codes for each segment.
            var startCounts = data.ReadUnsignedShortArray(segmentCount);

            // Delta for all character codes in the segment. Contrary to the spec this is actually a short[].
            var idDeltas = data.ReadShortArray(segmentCount);

            var idRangeOffsets = data.ReadUnsignedShortArray(segmentCount);

            const int singleIntsRead = 8;
            const int intArraysRead  = 8;

            // ReSharper disable once ArrangeRedundantParentheses
            var remainingBytes = length - ((singleIntsRead * 2) + intArraysRead * segmentCount);

            var remainingInts = remainingBytes / 2;

            var glyphIndices = data.ReadUnsignedShortArray(remainingInts);

            var segments = new Segment[endCounts.Length];

            for (int i = 0; i < endCounts.Length; i++)
            {
                var start = startCounts[i];
                var end   = endCounts[i];

                var delta   = idDeltas[i];
                var offsets = idRangeOffsets[i];

                segments[i] = new Segment(start, end, delta, offsets);
            }

            return(new Format4CMapTable(platformId, encodingId, version, segments, glyphIndices));
        }
Пример #21
0
        public static ByteEncodingCMapTable Load(TrueTypeDataBytes data, TrueTypeCMapPlatform platformId, ushort encodingId)
        {
            var length   = data.ReadUnsignedShort();
            var language = data.ReadUnsignedShort();

            var glyphMapping = data.ReadByteArray(length - (SizeOfShort * 3));

            return(new ByteEncodingCMapTable(platformId, encodingId, language, glyphMapping));
        }
Пример #22
0
        private static KerningSubTable ReadFormat2Table(int version, TrueTypeDataBytes data, KernCoverage coverage, long tableStartOffset)
        {
            // TODO: Implement and test this;
            return(null);

#pragma warning disable 162
            var rowWidth = data.ReadUnsignedShort();

            var leftClassTableOffset  = data.ReadUnsignedShort();
            var rightClassTableOffset = data.ReadUnsignedShort();

            var kerningArrayOffset = data.ReadUnsignedShort();

            data.Seek(tableStartOffset + leftClassTableOffset);

            var leftTableFirstGlyph = data.ReadUnsignedShort();
            var numberOfLeftGlyphs  = data.ReadUnsignedShort();

            var leftGlyphClassValues = new int[numberOfLeftGlyphs];

            for (var i = 0; i < numberOfLeftGlyphs; i++)
            {
                leftGlyphClassValues[i] = data.ReadUnsignedShort();
            }

            data.Seek(tableStartOffset + rightClassTableOffset);

            var rightTableFirstGlyph = data.ReadUnsignedShort();
            var numberOfRightGlyphs  = data.ReadUnsignedShort();

            var rightGlyphClassValues = new int[numberOfRightGlyphs];

            for (var i = 0; i < numberOfRightGlyphs; i++)
            {
                rightGlyphClassValues[i] = data.ReadUnsignedShort();
            }

            data.Seek(tableStartOffset + kerningArrayOffset);

            var pairs = new List <KernPair>(numberOfRightGlyphs * numberOfLeftGlyphs);

            // Data is a [left glyph count, right glyph count] array:
            for (int i = 0; i < numberOfLeftGlyphs; i++)
            {
                var leftClassValue = leftGlyphClassValues[i];
                for (int j = 0; j < numberOfRightGlyphs; j++)
                {
                    var rightClassValue = rightGlyphClassValues[j];

                    pairs.Add(new KernPair(leftClassValue, rightClassValue, data.ReadSignedShort()));
                }
            }

            return(new KerningSubTable(version, coverage, pairs));

#pragma warning restore 162
        }
Пример #23
0
        private static GlyphRecord[] GetGlyphRecordsInFont(TrueTypeFont font, TrueTypeDataBytes data)
        {
            var indexToLocationTable = font.TableRegister.IndexToLocationTable;

            var numGlyphs = indexToLocationTable.GlyphOffsets.Count - 1;

            var glyphDirectory = font.TableRegister.GlyphTable.DirectoryTable;

            data.Seek(glyphDirectory.Offset);

            var glyphRecords = new GlyphRecord[numGlyphs];

            for (var i = 0; i < numGlyphs; i++)
            {
                var glyphOffset = (int)(glyphDirectory.Offset + indexToLocationTable.GlyphOffsets[i]);

                if (indexToLocationTable.GlyphOffsets[i + 1] <= indexToLocationTable.GlyphOffsets[i])
                {
                    glyphRecords[i] = new GlyphRecord(glyphOffset);
                    continue;
                }

                data.Seek(glyphOffset);

                if (glyphOffset >= glyphDirectory.Offset + glyphDirectory.Length)
                {
                    throw new InvalidOperationException($"Failed to read expected number of glyphs {numGlyphs}, only got to index {i} before reaching end of input.");
                }

                var numberOfContours = data.ReadSignedShort();
                var type             = numberOfContours >= 0 ? GlyphType.Simple : GlyphType.Composite;

                // Read bounds.
                data.ReadSignedShort();
                data.ReadSignedShort();
                data.ReadSignedShort();
                data.ReadSignedShort();

                if (type == GlyphType.Simple)
                {
                    ReadSimpleGlyph(data, numberOfContours);
                    glyphRecords[i] = new GlyphRecord(glyphOffset, type, (int)(data.Position - glyphOffset));
                }
                else
                {
                    var glyphIndices = ReadCompositeGlyph(data);

                    // Skip hinting instructions but include them in the output.
                    var next = indexToLocationTable.GlyphOffsets[i + 1];
                    data.Seek(glyphDirectory.Offset + next - 1);

                    glyphRecords[i] = new GlyphRecord(glyphOffset, type, (int)(data.Position - glyphOffset), glyphIndices);
                }
            }

            return(glyphRecords);
        }
Пример #24
0
        private bool TryReadFile(string fileName, bool readNameFirst, string fontName, out TrueTypeFont font)
        {
            font = null;

            var bytes = File.ReadAllBytes(fileName);

            var data = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            if (readNameFirst)
            {
                var name = TrueTypeFontParser.GetNameTable(data);

                if (name == null)
                {
                    lock (readFilesLock)
                    {
                        readFiles.Add(fileName);
                    }

                    return(false);
                }

                var fontNameFromFile = name.GetPostscriptName() ?? name.FontName;

                nameToFileNameMap.TryAdd(fontNameFromFile, fileName);

                if (!string.Equals(fontNameFromFile, fontName, StringComparison.OrdinalIgnoreCase))
                {
                    lock (readFilesLock)
                    {
                        readFiles.Add(fileName);
                    }

                    return(false);
                }
            }

            data.Seek(0);
            font = TrueTypeFontParser.Parse(data);
            var psName = font.TableRegister.NameTable?.GetPostscriptName() ?? font.Name;

            lock (CacheLock)
            {
                if (!Cache.ContainsKey(psName))
                {
                    Cache[psName] = font;
                }
            }

            lock (readFilesLock)
            {
                readFiles.Add(fileName);
            }

            return(true);
        }
Пример #25
0
        public void ParsePMingLiU()
        {
            var bytes = TrueTypeTestHelper.GetFileBytes("PMingLiU");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            Assert.NotNull(font);
        }
Пример #26
0
        public void ParseSimpleGoogleDocssGautmi()
        {
            var bytes = TrueTypeTestHelper.GetFileBytes("google-simple-doc");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            Assert.NotNull(font.TableRegister.HeaderTable);
        }
Пример #27
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)));
        }
Пример #28
0
        public void ParseAndadaRegular()
        {
            var bytes = GetFileBytes("Andada-Regular");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = parser.Parse(input);

            Assert.NotNull(font.TableRegister.GlyphTable);
        }
Пример #29
0
        public void RobotoHeaderReadCorrectly()
        {
            var data = new[]
            {
                // key, offset, length, checksum
                "DSIG 158596 8 1",
                "GDEF 316 72 408950881",
                "GPOS 388 35744 355098641",
                "GSUB 36132 662 3357985284",
                "OS/2 36796 96 3097700805",
                "cmap 36892 1750 298470964",
                "cvt  156132 38 119085513",
                "fpgm 156172 2341 2494100564",
                "gasp 156124 8 16",
                "glyf 38644 88820 3302131736",
                "head 127464 54 346075833",
                "hhea 127520 36 217516755",
                "hmtx 127556 4148 1859679943",
                "kern 131704 12306 2002873469",
                "loca 144012 2076 77421448",
                "maxp 146088 32 89459325",
                "name 146120 830 44343214",
                "post 146952 9171 3638780613",
                "prep 158516 77 251381919"
            };

            var bytes = TrueTypeTestHelper.GetFileBytes("Roboto-Regular");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            foreach (var s in data)
            {
                var parts = s.Split(' ', StringSplitOptions.RemoveEmptyEntries);

                var name = parts[0];

                if (name == "cvt")
                {
                    name = "cvt ";
                }

                var match = font.TableHeaders[name];

                var offset   = long.Parse(parts[1], CultureInfo.InvariantCulture);
                var length   = long.Parse(parts[2], CultureInfo.InvariantCulture);
                var checksum = long.Parse(parts[3], CultureInfo.InvariantCulture);

                Assert.Equal(offset, match.Offset);
                Assert.Equal(length, match.Length);
                Assert.Equal(checksum, match.CheckSum);
            }
        }
Пример #30
0
        private static SimpleGlyphFlags[] ReadFlags(TrueTypeDataBytes data, int pointCount)
        {
            var result = new SimpleGlyphFlags[pointCount];

            for (var i = 0; i < pointCount; i++)
            {
                result[i] = (SimpleGlyphFlags)data.ReadByte();
            }

            return(result);
        }