Exemplo n.º 1
0
        private static TrueTypeFont ParseTables(decimal version, IReadOnlyDictionary <string, TrueTypeHeaderTable> tables, TrueTypeDataBytes data)
        {
            var isPostScript = tables.ContainsKey(TrueTypeHeaderTable.Cff);

            var tableRegister = new TableRegister();

            if (!tables.TryGetValue(TrueTypeHeaderTable.Head, out var table))
            {
                throw new InvalidOperationException($"The {TrueTypeHeaderTable.Head} table is required.");
            }

            // head
            tableRegister.HeaderTable = HeaderTable.Load(data, table);

            if (!tables.TryGetValue(TrueTypeHeaderTable.Hhea, out var hHead))
            {
                throw new InvalidOperationException("The horizontal header table is required.");
            }

            // hhea
            tableRegister.HorizontalHeaderTable = HorizontalHeaderTable.Load(data, hHead);

            if (!tables.TryGetValue(TrueTypeHeaderTable.Maxp, out var maxHeaderTable))
            {
                throw new InvalidOperationException("The maximum profile table is required.");
            }

            // maxp
            tableRegister.MaximumProfileTable = BasicMaximumProfileTable.Load(data, maxHeaderTable);

            // post
            if (tables.TryGetValue(TrueTypeHeaderTable.Post, out var postscriptHeaderTable))
            {
                tableRegister.PostScriptTable = PostScriptTable.Load(data, postscriptHeaderTable, tableRegister.MaximumProfileTable);
            }

            if (!isPostScript)
            {
                if (!tables.TryGetValue(TrueTypeHeaderTable.Loca, out var indexToLocationHeaderTable))
                {
                    throw new InvalidOperationException("The location to index table is required for non-PostScript fonts.");
                }

                // loca
                tableRegister.IndexToLocationTable =
                    IndexToLocationTable.Load(data, indexToLocationHeaderTable, tableRegister);

                if (!tables.TryGetValue(TrueTypeHeaderTable.Glyf, out var glyphHeaderTable))
                {
                    throw new InvalidOperationException("The glyph table is required for non-PostScript fonts.");
                }

                // glyf
                tableRegister.GlyphDataTable = GlyphDataTable.Load(data, glyphHeaderTable, tableRegister);

                OptionallyParseTables(tables, data, tableRegister);
            }

            return(new TrueTypeFont(version, tables, tableRegister));
        }
Exemplo n.º 2
0
        public static Font ReadFromStream(Stream stream)
        {
            var font   = new Font();
            var reader = new BinaryReader(stream);

            // Offset Table
            font.OffsetTable = OffsetTable.Read(reader);

            // Head
            var headTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == HeadTable.Tag);

            stream.Seek(headTableRecord.Offset, SeekOrigin.Begin);
            font.HeadTable = HeadTable.Read(reader);

            // Horizontal Header
            var horizontalHeaderTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == HorizontalHeaderTable.Tag);

            stream.Seek(horizontalHeaderTableRecord.Offset, SeekOrigin.Begin);
            font.HorizontalHeaderTable = HorizontalHeaderTable.Read(reader);

            // Maximum Profile
            var maximumProfileTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == MaximumProfileTableBase.Tag);

            stream.Seek(maximumProfileTableRecord.Offset, SeekOrigin.Begin);
            var maximumProfileTableVersion = Math.Round(reader.ReadFixedPointNumber(), 2);

            if (maximumProfileTableVersion == 0.5m)
            {
                font.MaximumProfileTable = MaximumProfileTableV0_5.Read(reader, maximumProfileTableVersion);
            }
            else if (maximumProfileTableVersion == 1.0m)
            {
                font.MaximumProfileTable = MaximumProfileTableV1.Read(reader, maximumProfileTableVersion);
            }

            // Horizontal Metrics
            var horizontalMetricsTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == HorizontalMetricsTable.Tag);

            stream.Seek(horizontalMetricsTableRecord.Offset, SeekOrigin.Begin);
            font.HorizontalMetricsTable = HorizontalMetricsTable.Read(reader,
                                                                      font.HorizontalHeaderTable.NumberOfHMetrics,
                                                                      font.MaximumProfileTable.NumGlyphs);

            // Glyph
            var glyphTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == GlyphTable.Tag);

            font.GlyphTable = new GlyphTable(reader, glyphTableRecord.Offset);

            // IndexLocation
            var indexLocationTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == IndexLocationTableBase.Tag);

            stream.Seek(indexLocationTableRecord.Offset, SeekOrigin.Begin);
            if (font.HeadTable.IndexToLocFormat == 0)
            {
                font.IndexLocationTable = IndexLocationShortFormatTable.Read(reader, font.MaximumProfileTable.NumGlyphs);
            }
            else
            {
                font.IndexLocationTable = IndexLocationLongFormatTable.Read(reader, font.MaximumProfileTable.NumGlyphs);
            }

            // PostScript
            var postScriptTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == PostScriptTable.Tag);

            stream.Seek(postScriptTableRecord.Offset, SeekOrigin.Begin);
            font.PostScriptTable = PostScriptTable.Read(reader);

            // OS/2 and Windows
            var os2TableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == Os2Table.Tag);

            stream.Seek(os2TableRecord.Offset, SeekOrigin.Begin);
            font.Os2Table = Os2Table.Read(reader);

            // CharacterMap
            var characterMapTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == CharacterMapTable.Tag);

            stream.Seek(characterMapTableRecord.Offset, SeekOrigin.Begin);
            font.CharacterMapTable = CharacterMapTable.Read(reader);

            return(font);
        }
Exemplo n.º 3
0
        /**
         * Creates a new font descriptor dictionary for the given TTF.
         */
        private FontDescriptor CreateFontDescriptor(TrueTypeFont ttf)
        {
            FontDescriptor fd = new FontDescriptor(document, new PdfDictionary());

            fd.FontName = ttf.Name;

            OS2WindowsMetricsTable os2  = ttf.OS2Windows;
            PostScriptTable        post = ttf.PostScript;

            // Flags
            var flags = (FlagsEnum)0;

            flags |= (post.IsFixedPitch > 0 || ttf.HorizontalHeader.NumberOfHMetrics == 1) ? FlagsEnum.FixedPitch : 0;

            int fsSelection = os2.FsSelection;

            flags |= ((fsSelection & (ITALIC | OBLIQUE)) != 0) ? FlagsEnum.Italic : 0;

            switch (os2.FamilyClass)
            {
            case OS2WindowsMetricsTable.FAMILY_CLASS_CLAREDON_SERIFS:
            case OS2WindowsMetricsTable.FAMILY_CLASS_FREEFORM_SERIFS:
            case OS2WindowsMetricsTable.FAMILY_CLASS_MODERN_SERIFS:
            case OS2WindowsMetricsTable.FAMILY_CLASS_OLDSTYLE_SERIFS:
            case OS2WindowsMetricsTable.FAMILY_CLASS_SLAB_SERIFS:
                flags |= FlagsEnum.Serif;
                break;

            case OS2WindowsMetricsTable.FAMILY_CLASS_SCRIPTS:
                flags |= FlagsEnum.Script;
                break;

            default:
                break;
            }

            fd.FontWeight = os2.WeightClass;

            flags |= FlagsEnum.Symbolic;
            flags &= ~FlagsEnum.Nonsymbolic;

            fd.Flags = flags;
            // ItalicAngle
            fd.ItalicAngle = post.ItalicAngle;

            // FontBBox
            HeaderTable header  = ttf.Header;
            float       scaling = 1000f / header.UnitsPerEm;
            var         skRect  = new SKRect(
                header.XMin * scaling,
                header.YMin * scaling,
                header.XMax * scaling,
                header.YMax * scaling
                );


            Rectangle rect = new Rectangle(skRect);

            fd.FontBBox = rect;

            // Ascent, Descent
            HorizontalHeaderTable hHeader = ttf.HorizontalHeader;

            fd.Ascent  = hHeader.Ascender * scaling;
            fd.Descent = hHeader.Descender * scaling;

            // CapHeight, XHeight
            if (os2.Version >= 1.2)
            {
                fd.CapHeight = os2.CapHeight * scaling;
                fd.XHeight   = os2.Height * scaling;
            }
            else
            {
                var capHPath = ttf.GetPath("H");
                if (capHPath != null)
                {
                    fd.CapHeight = (float)Math.Round(capHPath.Bounds.Bottom * scaling);
                }
                else
                {
                    // estimate by summing the typographical +ve ascender and -ve descender
                    fd.CapHeight = os2.TypoAscender + (os2.TypoDescender * scaling);
                }
                var xPath = ttf.GetPath("x");
                if (xPath != null)
                {
                    fd.XHeight = (float)Math.Round(xPath.Bounds.Bottom * scaling);
                }
                else
                {
                    // estimate by halving the typographical ascender
                    fd.XHeight = os2.TypoAscender / (2.0f * scaling);
                }
            }

            // StemV - there's no true TTF equivalent of this, so we estimate it
            fd.StemV = skRect.Width * .13f;

            return(fd);
        }