Exemplo n.º 1
0
            /// <summary>
            /// calculate Baseline-to-Baseline Distance (BTBD) for macOS
            /// </summary>
            /// <param name="typeface"></param>
            /// <returns>return 'unscaled-to-pixel' BTBD value</returns>
            static int CalculateBTBD_Mac(Typeface typeface)
            {
                //from https://www.microsoft.com/typography/otspec/recom.htm#tad

                //Ascender and Descender are metrics defined by Apple
                //and are not to be confused with the Windows ascent or descent,
                //nor should they be confused with the true typographic ascender and descender that are found in AFM files.
                //The Macintosh metrics below are returned by the Apple Advanced Typography(AAT) GetFontInfo() API.
                //
                //
                //Macintosh Metric      OpenType Metric
                //ascender                  Ascender
                //descender                 Descender
                //leading                   LineGap

                //The suggested BTBD = ascent + descent + leading
                //If pixels extend above the ascent or below the descent,
                //the character will be squashed in the vertical direction
                //so that all pixels fit within these limitations; this is true for screen display only.

                //TODO: please test this
                HorizontalHeader hhea = typeface.HheaTable;

                return(hhea.Ascent + hhea.Descent + hhea.LineGap);
            }
Exemplo n.º 2
0
        public Typeface Read(Stream stream)
        {
            var little = BitConverter.IsLittleEndian;

            using (BinaryReader input = new ByteOrderSwappingBinaryReader(stream))
            {
                UInt32 version       = input.ReadUInt32();
                UInt16 tableCount    = input.ReadUInt16();
                UInt16 searchRange   = input.ReadUInt16();
                UInt16 entrySelector = input.ReadUInt16();
                UInt16 rangeShift    = input.ReadUInt16();

                var tables = new List <TableEntry>(tableCount);
                for (int i = 0; i < tableCount; i++)
                {
                    tables.Add(TableEntry.ReadFrom(input));
                }

                var header         = Head.From(FindTable(tables, "head"));
                var maximumProfile = MaxProfile.From(FindTable(tables, "maxp"));
                var glyphLocations = new GlyphLocations(FindTable(tables, "loca"), maximumProfile.GlyphCount, header.WideGlyphLocations);
                var glyphs         = Glyf.From(FindTable(tables, "glyf"), glyphLocations);
                var cmaps          = CmapReader.From(FindTable(tables, "cmap"));

                var horizontalHeader  = HorizontalHeader.From(FindTable(tables, "hhea"));
                var horizontalMetrics = HorizontalMetrics.From(FindTable(tables, "hmtx"),
                                                               horizontalHeader.HorizontalMetricsCount, maximumProfile.GlyphCount);

                return(new Typeface(header.Bounds, header.UnitsPerEm, glyphs, cmaps, horizontalMetrics));
            }
        }
        protected double GetLineHeight(FontUnitType units, OS2Table os2, HorizontalHeader hhead, FontHeader header, double emsize)
        {
            double h;
            bool   useTypo;

            if (units == FontUnitType.UseFontPreference)
            {
                useTypo = (os2.Version >= OS2TableVersion.OpenType15) && ((os2.Selection & FontSelection.UseTypographicSizes) > 0);
            }
            else if (units == FontUnitType.UseHeadMetrics)
            {
                useTypo = false;
            }
            else if (null == os2)
            {
                useTypo = false;
            }
            else
            {
                useTypo = true;
            }

            if (useTypo)
            {
                h = ((double)(os2.TypoAscender - os2.TypoDescender + os2.TypoLineGap) / ((double)header.UnitsPerEm) * emsize);
            }
            else
            {
                h = ((double)(hhead.Ascender - hhead.Descender + hhead.LineGap) / ((double)header.UnitsPerEm) * emsize);
            }

            return(h);
        }
        public static TTFStringMeasurer Create(TrueTypeFile forfont, CMapEncoding encoding, TypeMeasureOptions options)
        {
            HorizontalMetrics table = forfont.Directories["hmtx"].Table as HorizontalMetrics;
            CMAPTable         cmap  = forfont.Directories["cmap"].Table as CMAPTable;
            OS2Table          os2   = forfont.Directories["OS/2"].Table as OS2Table;
            FontHeader        head  = forfont.Directories["head"].Table as FontHeader;
            HorizontalHeader  hhead = forfont.Directories["hhea"].Table as HorizontalHeader;

            CMAPSubTable map = cmap.GetOffsetTable(encoding);

            if (map == null)
            {
                encoding = CMapEncoding.Unicode_20;
                map      = cmap.GetOffsetTable(CMapEncoding.Unicode_20);
            }

            if (map == null)
            {
                encoding = CMapEncoding.MacRoman;
                map      = cmap.GetOffsetTable(CMapEncoding.MacRoman);
            }



            return(new TTFStringMeasurer(head.UnitsPerEm, map, os2, hhead, table.HMetrics, forfont, encoding, options));
        }
        private TTFStringMeasurer(int unitsPerEm, CMAPSubTable offsets, OS2Table oS2, HorizontalHeader hheader, List <HMetric> metrics, TrueTypeFile font, CMapEncoding encoding, TypeMeasureOptions options)
        {
            this._unitsPerEm  = unitsPerEm;
            this._offsets     = offsets;
            this._os2         = oS2;
            this._metrics     = metrics;
            this._lookup      = new Dictionary <char, HMetric>();
            this._options     = options;
            this._fontUseTypo = (oS2.Version >= OS2TableVersion.OpenType15) && ((oS2.Selection & FontSelection.UseTypographicSizes) > 0);

            this._hheader      = hheader;
            this._fontfile     = font;
            this._cMapEncoding = encoding;
        }
Exemplo n.º 6
0
            /// <summary>
            /// calculate Baseline-to-Baseline Distance (BTBD) for Windows
            /// </summary>
            /// <param name="typeface"></param>
            /// <returns>return 'unscaled-to-pixel' BTBD value</returns>
            static int Calculate_BTBD_Windows(Typeface typeface)
            {
                //from https://www.microsoft.com/typography/otspec/recom.htm#tad

                //Baseline to Baseline Distances
                //The 'OS/2' table fields sTypoAscender, sTypoDescender, and sTypoLineGap
                //free applications from Macintosh-or Windows - specific metrics
                //which are constrained by backward compatibility requirements.
                //
                //The following discussion only pertains to the platform-specific metrics.
                //The suggested Baseline to Baseline Distance(BTBD) is computed differently for Windows and the Macintosh,
                //and it is based on different OpenType metrics.
                //However, if the recommendations below are followed, the BTBD will be the same for both Windows and the Mac.

                //Windows Metric         OpenType Metric
                //ascent                    usWinAscent
                //descent                   usWinDescent
                //internal leading          usWinAscent + usWinDescent - unitsPerEm
                //external leading          MAX(0, LineGap - ((usWinAscent + usWinDescent) - (Ascender - Descender)))

                //The suggested BTBD = ascent + descent + external leading

                //It should be clear that the “external leading” can never be less than zero.
                //Pixels above the ascent or below the descent will be clipped from the character;
                //this is true for all output devices.

                //The usWinAscent and usWinDescent are values
                //from the 'OS/2' table.
                //The unitsPerEm value is from the 'head' table.
                //The LineGap, Ascender and Descender values are from the 'hhea' table.

                HorizontalHeader hhea = typeface.HheaTable;
                int usWinAscent       = typeface.OS2Table.usWinAscent;
                int usWinDescent      = typeface.OS2Table.usWinDescent;
                int internal_leading  = usWinAscent + usWinDescent - typeface.UnitsPerEm;

                int external_leading = System.Math.Max(0, hhea.LineGap - ((usWinAscent + usWinDescent) - (hhea.Ascent - hhea.Descent)));

                return(usWinAscent + usWinDescent + external_leading);
            }
        private TrueTypeFontTable ReadHorizontalHeader(uint length, TrueTypeTableEntryList list, BigEndianReader reader)
        {
            HorizontalHeader hhead = new HorizontalHeader(reader.Position);

            hhead.TableVersion            = reader.ReadFixedVersion();
            hhead.Ascender                = reader.ReadInt16();
            hhead.Descender               = reader.ReadInt16();
            hhead.LineGap                 = reader.ReadInt16();
            hhead.AdvanceWidthMax         = reader.ReadUInt16();
            hhead.MinimumLeftSideBearing  = reader.ReadInt16();
            hhead.MinimumRightSideBearing = reader.ReadInt16();
            hhead.XMaxExtent              = reader.ReadInt16();
            hhead.CaretSlopeRise          = reader.ReadInt16();
            hhead.CaretSlopeRun           = reader.ReadInt16();
            hhead.CaretOffset             = reader.ReadInt16();
            hhead.Reserved1               = reader.ReadInt16();
            hhead.Reserved2               = reader.ReadInt16();
            hhead.Reserved3               = reader.ReadInt16();
            hhead.Reserved4               = reader.ReadInt16();
            hhead.MetricDataFormat        = reader.ReadInt16();
            hhead.NumberOfHMetrics        = reader.ReadUInt16();

            return(hhead);
        }
Exemplo n.º 8
0
        internal Typeface ReadTableEntryCollection(TableEntryCollection tables, BinaryReader input)
        {
            OS2Table  os2Table  = ReadTableIfExists(tables, input, new OS2Table());
            NameEntry nameEntry = ReadTableIfExists(tables, input, new NameEntry());

            Head              header            = ReadTableIfExists(tables, input, new Head());
            MaxProfile        maximumProfile    = ReadTableIfExists(tables, input, new MaxProfile());
            HorizontalHeader  horizontalHeader  = ReadTableIfExists(tables, input, new HorizontalHeader());
            HorizontalMetrics horizontalMetrics = ReadTableIfExists(tables, input, new HorizontalMetrics(horizontalHeader.HorizontalMetricsCount, maximumProfile.GlyphCount));

            //---
            PostTable postTable = ReadTableIfExists(tables, input, new PostTable());
            CFFTable  ccf       = ReadTableIfExists(tables, input, new CFFTable());

            //--------------
            Cmap           cmaps          = ReadTableIfExists(tables, input, new Cmap());
            GlyphLocations glyphLocations = ReadTableIfExists(tables, input, new GlyphLocations(maximumProfile.GlyphCount, header.WideGlyphLocations));

            Glyf glyf = ReadTableIfExists(tables, input, new Glyf(glyphLocations));
            //--------------
            Gasp gaspTable             = ReadTableIfExists(tables, input, new Gasp());
            VerticalDeviceMetrics vdmx = ReadTableIfExists(tables, input, new VerticalDeviceMetrics());
            //--------------


            Kern kern = ReadTableIfExists(tables, input, new Kern());
            //--------------
            //advanced typography
            GDEF           gdef      = ReadTableIfExists(tables, input, new GDEF());
            GSUB           gsub      = ReadTableIfExists(tables, input, new GSUB());
            GPOS           gpos      = ReadTableIfExists(tables, input, new GPOS());
            BASE           baseTable = ReadTableIfExists(tables, input, new BASE());
            COLR           colr      = ReadTableIfExists(tables, input, new COLR());
            CPAL           cpal      = ReadTableIfExists(tables, input, new CPAL());
            VerticalHeader vhea      = ReadTableIfExists(tables, input, new VerticalHeader());

            if (vhea != null)
            {
                VerticalMetrics vmtx = ReadTableIfExists(tables, input, new VerticalMetrics(vhea.NumOfLongVerMetrics));
            }



            //test math table
            MathTable mathtable    = ReadTableIfExists(tables, input, new MathTable());
            EBLCTable fontBmpTable = ReadTableIfExists(tables, input, new EBLCTable());
            //---------------------------------------------
            //about truetype instruction init

            //---------------------------------------------
            Typeface typeface            = null;
            bool     isPostScriptOutline = false;

            if (glyf == null)
            {
                //check if this is cff table ?
                if (ccf == null)
                {
                    //TODO: review here
                    throw new NotSupportedException();
                }
                //...
                //PostScript outline font
                isPostScriptOutline = true;
                typeface            = new Typeface(
                    nameEntry,
                    header.Bounds,
                    header.UnitsPerEm,
                    ccf,
                    horizontalMetrics,
                    os2Table);
            }
            else
            {
                typeface = new Typeface(
                    nameEntry,
                    header.Bounds,
                    header.UnitsPerEm,
                    glyf.Glyphs,
                    horizontalMetrics,
                    os2Table);
            }

            //----------------------------
            typeface.CmapTable  = cmaps;
            typeface.KernTable  = kern;
            typeface.GaspTable  = gaspTable;
            typeface.MaxProfile = maximumProfile;
            typeface.HheaTable  = horizontalHeader;
            //----------------------------

            if (!isPostScriptOutline)
            {
                FpgmTable fpgmTable = ReadTableIfExists(tables, input, new FpgmTable());
                //control values table
                CvtTable cvtTable = ReadTableIfExists(tables, input, new CvtTable());
                if (cvtTable != null)
                {
                    typeface.ControlValues = cvtTable._controlValues;
                }
                if (fpgmTable != null)
                {
                    typeface.FpgmProgramBuffer = fpgmTable._programBuffer;
                }
                PrepTable propProgramTable = ReadTableIfExists(tables, input, new PrepTable());
                if (propProgramTable != null)
                {
                    typeface.PrepProgramBuffer = propProgramTable._programBuffer;
                }
            }
            //-------------------------
            typeface.LoadOpenFontLayoutInfo(
                gdef,
                gsub,
                gpos,
                baseTable,
                colr,
                cpal);

            //------------


            //test
            {
                SvgTable svgTable = ReadTableIfExists(tables, input, new SvgTable());
                if (svgTable != null)
                {
                    typeface._svgTable = svgTable;
                }
            }

            typeface.PostTable = postTable;
            if (mathtable != null)
            {
                var mathGlyphLoader = new MathGlyphLoader();
                mathGlyphLoader.LoadMathGlyph(typeface, mathtable);
            }
#if DEBUG
            //test
            //int found = typeface.GetGlyphIndexByName("Uacute");
            if (typeface.IsCffFont)
            {
                //optional
                typeface.UpdateAllCffGlyphBounds();
            }
#endif
            return(typeface);
        }
Exemplo n.º 9
0
        public TtfTypeface Read(Stream stream, ReadFlags readFlags = ReadFlags.Full)
        {
            var little = BitConverter.IsLittleEndian;

            using (var input = new ByteOrderSwappingBinaryReader(stream))
            {
                ushort majorVersion  = input.ReadUInt16();
                ushort minorVersion  = input.ReadUInt16();
                ushort tableCount    = input.ReadUInt16();
                ushort searchRange   = input.ReadUInt16();
                ushort entrySelector = input.ReadUInt16();
                ushort rangeShift    = input.ReadUInt16();
                var    tables        = new TableEntryCollection();
                for (int i = 0; i < tableCount; i++)
                {
                    tables.AddEntry(new UnreadTableEntry(ReadTableHeader(input)));
                }
                //------------------------------------------------------------------
                OS2Table  os2Table  = ReadTableIfExists(tables, input, new OS2Table());
                NameEntry nameEntry = ReadTableIfExists(tables, input, new NameEntry());


                Head              header            = ReadTableIfExists(tables, input, new Head());
                MaxProfile        maximumProfile    = ReadTableIfExists(tables, input, new MaxProfile());
                HorizontalHeader  horizontalHeader  = ReadTableIfExists(tables, input, new HorizontalHeader());
                HorizontalMetrics horizontalMetrics = ReadTableIfExists(tables, input, new HorizontalMetrics(horizontalHeader.HorizontalMetricsCount, maximumProfile.GlyphCount));

                //--------------
                Cmap           cmaps          = ReadTableIfExists(tables, input, new Cmap());
                GlyphLocations glyphLocations = ReadTableIfExists(tables, input, new GlyphLocations(maximumProfile.GlyphCount, header.WideGlyphLocations));
                Glyf           glyf           = ReadTableIfExists(tables, input, new Glyf(glyphLocations));
                //--------------
                Gasp gaspTable             = ReadTableIfExists(tables, input, new Gasp());
                VerticalDeviceMetrics vdmx = ReadTableIfExists(tables, input, new VerticalDeviceMetrics());
                //--------------
                PostTable postTable = ReadTableIfExists(tables, input, new PostTable());
                Kern      kern      = ReadTableIfExists(tables, input, new Kern());
                //--------------
                //advanced typography
                GDEF           gdef      = ReadTableIfExists(tables, input, new GDEF());
                GSUB           gsub      = ReadTableIfExists(tables, input, new GSUB());
                GPOS           gpos      = ReadTableIfExists(tables, input, new GPOS());
                BASE           baseTable = ReadTableIfExists(tables, input, new BASE());
                COLR           colr      = ReadTableIfExists(tables, input, new COLR());
                CPAL           cpal      = ReadTableIfExists(tables, input, new CPAL());
                VerticalHeader vhea      = ReadTableIfExists(tables, input, new VerticalHeader());
                if (vhea != null)
                {
                    VerticalMatric vmtx = ReadTableIfExists(tables, input, new VerticalMatric(vhea.NumOfLongVerMetrics));
                }

                EBLCTable fontBmpTable = ReadTableIfExists(tables, input, new EBLCTable());
                //---------------------------------------------
                //about truetype instruction init

                //---------------------------------------------
                var typeface = new TtfTypeface(
                    nameEntry,
                    header.Bounds,
                    header.UnitsPerEm,
                    glyf.Glyphs,
                    horizontalMetrics,
                    os2Table);
                //----------------------------
                typeface.CmapTable  = cmaps;
                typeface.KernTable  = kern;
                typeface.GaspTable  = gaspTable;
                typeface.MaxProfile = maximumProfile;
                typeface.HheaTable  = horizontalHeader;
                //----------------------------
                FpgmTable fpgmTable = ReadTableIfExists(tables, input, new FpgmTable());
                //control values table
                CvtTable cvtTable = ReadTableIfExists(tables, input, new CvtTable());
                if (cvtTable != null)
                {
                    typeface.ControlValues = cvtTable.controlValues;
                }
                if (fpgmTable != null)
                {
                    typeface.FpgmProgramBuffer = fpgmTable.programBuffer;
                }
                PrepTable propProgramTable = ReadTableIfExists(tables, input, new PrepTable());
                if (propProgramTable != null)
                {
                    typeface.PrepProgramBuffer = propProgramTable.programBuffer;
                }
                //-------------------------
                typeface.LoadOpenFontLayoutInfo(
                    gdef,
                    gsub,
                    gpos,
                    baseTable,
                    colr,
                    cpal);
                return(typeface);
            }
        }
Exemplo n.º 10
0
        //------------------------------------------------------------------------------------------xx.02.2005
        /// <summary>Reads the font data from the file.</summary>
        /// <param name="openTypeReader">Open Type Reader</param>
        private void ReadFontDataFromFile(OpenTypeReader openTypeReader)
        {
            #region TrueType Collection
            if (bTrueTypeCollection)
            {
                String sTTCTag = openTypeReader.sReadTag();
                if (sTTCTag != "ttcf")
                {
                    throw new ReportException("'" + sFontName + " is not a valid TTC font file.");
                }
                UInt32 uVersion  = openTypeReader.uReadULONG();
                Int32  iNumFonts = (Int32)openTypeReader.uReadULONG();
                if (iTrueTypeCollectionIndex >= iNumFonts)
                {
                    throw new ReportException("'" + sFontName + " has invalid TrueType collection index.");
                }
                openTypeReader.Skip(iTrueTypeCollectionIndex * 4);
                Int32 iOffset = (Int32)openTypeReader.uReadULONG();
                openTypeReader.Seek(iOffset);
            }
            #endregion

            #region Offset Table
            UInt32 uSfntVersion = openTypeReader.uReadULONG();
            if (uSfntVersion == 0x4F54544F /* 'OTTO' */)
            {
                fontDataType = FontDataType.CFFdata;
            }
      #if DEBUG
            else if (uSfntVersion == 0x00010000 /* Version 1.0 */)
            {
                fontDataType = FontDataType.TrueTypeOutlines;
            }
            else
            {
                throw new ReportException("'" + sFontName + " is not a valid TTF, OTF or TTC font file.");
            }
      #endif

            iNumTables     = (Int32)openTypeReader.iReadUSHORT();
            iSearchRange   = (Int32)openTypeReader.iReadUSHORT();
            iEntrySelector = (Int32)openTypeReader.iReadUSHORT();
            iRangeShift    = (Int32)openTypeReader.iReadUSHORT();
            #endregion

            #region Table Directory
            for (Int32 iTable = 0; iTable < iNumTables; iTable++)
            {
                TableDirectory tableDirectory_New = new TableDirectory();
                tableDirectory_New.sTag      = openTypeReader.sReadTag();
                tableDirectory_New.uCheckSum = openTypeReader.uReadULONG();
                tableDirectory_New.iOffset   = (Int32)openTypeReader.uReadULONG();
                tableDirectory_New.iLength   = (Int32)openTypeReader.uReadULONG();
                dict_TableDirectory.Add(tableDirectory_New.sTag, tableDirectory_New);
            }
            Boolean bCFF = dict_TableDirectory.ContainsKey("CFF");
            if ((bCFF && fontDataType == FontDataType.TrueTypeOutlines) || (!bCFF && fontDataType == FontDataType.CFFdata))
            {
                throw new ReportException("'" + sFontName + " is not a valid TTC font file.");
            }
            #endregion

            #region Font Header
            TableDirectory tableDirectory = dict_TableDirectory["head"];
            fontHeader = new FontHeader();
            openTypeReader.Seek(tableDirectory.iOffset);
            fontHeader.uTableVersionNumber = openTypeReader.uReadULONG();
            Debug.Assert(fontHeader.uTableVersionNumber == 0x00010000 /* Version 1.0 */);
            openTypeReader.Skip(12);
            fontHeader.iFlags      = openTypeReader.iReadUSHORT();
            fontHeader.iUnitsPerEm = openTypeReader.iReadUSHORT();
            openTypeReader.Skip(16);
            fontHeader.iXMin              = openTypeReader.int16_ReadSHORT();
            fontHeader.iYMin              = openTypeReader.int16_ReadSHORT();
            fontHeader.iXMax              = openTypeReader.int16_ReadSHORT();
            fontHeader.iYMax              = openTypeReader.int16_ReadSHORT();
            fontHeader.iMacStyle          = openTypeReader.iReadUSHORT();
            fontHeader.iLowestRecPPEM     = openTypeReader.iReadUSHORT();
            fontHeader.iFontDirectionHint = openTypeReader.int16_ReadSHORT();
            fontHeader.iIndexToLocFormat  = openTypeReader.int16_ReadSHORT();
            fontHeader.iGlyphDataFormat   = openTypeReader.int16_ReadSHORT();
            #endregion

            #region Horizontal Header
            tableDirectory   = dict_TableDirectory["hhea"];
            horizontalHeader = new HorizontalHeader();
            openTypeReader.Seek(tableDirectory.iOffset);
            horizontalHeader.uTableVersionNumber = openTypeReader.uReadULONG();
            Debug.Assert(horizontalHeader.uTableVersionNumber == 0x00010000 /* Version 1.0 */);
            horizontalHeader.iAscender            = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iDescender           = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iLineGap             = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iAdvanceWidthMax     = openTypeReader.iReadUFWORD();
            horizontalHeader.iMinLeftSideBearing  = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iMinRightSideBearing = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iXMaxExtent          = openTypeReader.int16_ReadFWORD();
            horizontalHeader.iCaretSlopeRise      = openTypeReader.int16_ReadSHORT();
            horizontalHeader.iCaretSlopeRun       = openTypeReader.int16_ReadSHORT();
            horizontalHeader.iCaretOffset         = openTypeReader.int16_ReadSHORT();
            openTypeReader.Skip(10);
            horizontalHeader.iNumberOfHMetrics = openTypeReader.iReadUSHORT();
            #endregion

            #region Windows Metrics (OS/2)
            tableDirectory = dict_TableDirectory["OS/2"];
            winMetrics     = new WinMetrics();
            openTypeReader.Seek(tableDirectory.iOffset);
            winMetrics.iVersion             = openTypeReader.iReadUSHORT();
            winMetrics.iXAvgCharWidth       = openTypeReader.int16_ReadSHORT();
            winMetrics.iUsWeightClass       = openTypeReader.iReadUSHORT();
            winMetrics.iUsWidthClass        = openTypeReader.iReadUSHORT();
            winMetrics.iFsType              = openTypeReader.iReadUSHORT();
            winMetrics.iYSubscriptXSize     = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSubscriptYSize     = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSubscriptXOffset   = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSubscriptYOffset   = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSuperscriptXSize   = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSuperscriptYSize   = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSuperscriptXOffset = openTypeReader.int16_ReadSHORT();
            winMetrics.iYSuperscriptYOffset = openTypeReader.int16_ReadSHORT();
            winMetrics.iYStrikeoutSize      = openTypeReader.int16_ReadSHORT();
            winMetrics.iYStrikeoutPosition  = openTypeReader.int16_ReadSHORT();
            winMetrics.iSFamilyClass        = openTypeReader.int16_ReadSHORT();
            winMetrics.aByte_Panose         = openTypeReader.aByte_ReadBYTE(10);
            if (winMetrics.iVersion == 0)
            {
                openTypeReader.Skip(4); // skip ulCharRange
            }
            else
            {
                winMetrics.uUlUnicodeRange1 = openTypeReader.uReadULONG();
                winMetrics.uUlUnicodeRange2 = openTypeReader.uReadULONG();
                winMetrics.uUlUnicodeRange3 = openTypeReader.uReadULONG();
                winMetrics.uUlUnicodeRange4 = openTypeReader.uReadULONG();
            }
            winMetrics.sAchVendID        = openTypeReader.sReadTag();
            winMetrics.iFsSelection      = openTypeReader.iReadUSHORT();
            winMetrics.iUsFirstCharIndex = openTypeReader.iReadUSHORT();
            winMetrics.iUsLastCharIndex  = openTypeReader.iReadUSHORT();
            winMetrics.iSTypoAscender    = openTypeReader.int16_ReadSHORT();
            winMetrics.iSTypoDescender   = openTypeReader.int16_ReadSHORT();
            winMetrics.iSTypoLineGap     = openTypeReader.int16_ReadSHORT();
            winMetrics.iUsWinAscent      = openTypeReader.iReadUSHORT();
            winMetrics.iUsWinDescent     = openTypeReader.iReadUSHORT();
            if (winMetrics.iVersion > 0)
            {
                winMetrics.iUlCodePageRange1 = openTypeReader.uReadULONG();
                winMetrics.iUlCodePageRange2 = openTypeReader.uReadULONG();
                if (winMetrics.iVersion > 1)
                {
                    winMetrics.iSXHeight      = openTypeReader.int16_ReadSHORT();
                    winMetrics.iSCapHeight    = openTypeReader.int16_ReadSHORT();
                    winMetrics.uUsDefaultChar = openTypeReader.uReadULONG();
                    winMetrics.uUsBreakChar   = openTypeReader.uReadULONG();
                    winMetrics.uUsMaxContext  = openTypeReader.uReadULONG();
                }
            }
            #endregion

            #region Post
            tableDirectory = dict_TableDirectory["post"];
            openTypeReader.Seek(tableDirectory.iOffset + 4);
            Double r1 = openTypeReader.int16_ReadSHORT();
            Double r0 = openTypeReader.iReadUSHORT();
            rItalicAngle        = r1 + r0 / 16384.0;
            iUnderlinePosition  = openTypeReader.int16_ReadFWORD();
            iUnderlineThickness = openTypeReader.int16_ReadFWORD();
            bFixedPitch         = (openTypeReader.uReadULONG() != 0);
            #endregion

            ReadTable_name(openTypeReader);
            ReadTable_hmtx(openTypeReader);
        }
        public LineSize MeasureString(CMapEncoding encoding, string s, int startOffset, double emsize, double available, bool wordboundary, out int charsfitted, FontUnitType useUnits = FontUnitType.UseFontPreference)
        {
            HorizontalMetrics table = this.Directories["hmtx"].Table as HorizontalMetrics;
            CMAPTable         cmap  = this.Directories["cmap"].Table as CMAPTable;
            OS2Table          os2   = this.Directories["OS/2"].Table as OS2Table;


            CMAPSubTable mac = cmap.GetOffsetTable(encoding);

            if (mac == null)
            {
                mac = cmap.GetOffsetTable(CMapEncoding.MacRoman);
            }

            HorizontalHeader hhead = this.Directories["hhea"].Table as HorizontalHeader;
            FontHeader       head  = this.Directories["head"].Table as FontHeader;

            available = (available * head.UnitsPerEm) / emsize;

            double len           = 0.0;
            double lastwordlen   = 0.0;
            int    lastwordcount = 0;

            charsfitted = 0;


            for (int i = startOffset; i < s.Length; i++)
            {
                char c = s[i];
                if (char.IsWhiteSpace(c))
                {
                    lastwordlen   = len;
                    lastwordcount = charsfitted;
                }

                int moffset = (int)mac.GetCharacterGlyphOffset(c);
                //System.Diagnostics.Debug.WriteLine("Character '" + chars[i].ToString() + "' (" + ((byte)chars[i]).ToString() + ") has offset '" + moffset.ToString() + "' in mac encoding and '" + woffset + "' in windows encoding");

                if (moffset >= table.HMetrics.Count)
                {
                    moffset = table.HMetrics.Count - 1;
                }
                Scryber.OpenType.SubTables.HMetric metric;
                metric = table.HMetrics[moffset];
                if (i == 0)
                {
                    len = -metric.LeftSideBearing;
                }
                len += metric.AdvanceWidth;

                //check if we can fit more
                if (len > available)
                {
                    len -= metric.AdvanceWidth;
                    break;
                }
                charsfitted++;
            }

            bool isboundary = false;

            if ((charsfitted + startOffset < s.Length) && wordboundary && lastwordlen > 0)
            {
                len         = lastwordlen;
                charsfitted = lastwordcount;
                isboundary  = true;
            }

            len = len / (double)head.UnitsPerEm;
            len = len * emsize;
            double h = GetLineHeight(useUnits, os2, hhead, head, emsize);

            return(new LineSize((float)len, (float)h, charsfitted, startOffset, isboundary));
        }
        /// <summary>
        /// Measures the size of the provided string at the specified font size (starting at a specific offset),
        /// stopping when the available space is full and returning the number of characters fitted.
        /// </summary>
        /// <param name="encoding">The encoding to use to map the characters</param>
        /// <param name="s">The string to measure the size of</param>
        /// <param name="startOffset">The starting (zero based) offset in that string to start measuring from</param>
        /// <param name="emsize">The M size in font units</param>
        /// <param name="availablePts">The max width allowed for this string</param>
        /// <param name="wordspace">The spacing between words in font units. Default 0</param>
        /// <param name="charspace">The spacing between characters in font units. Default 0</param>
        /// <param name="hscale">The horizontal scaling of all characters. Default 100</param>
        /// <param name="vertical">If true then this is vertical writing</param>
        /// <param name="wordboundary">If True the measuring will stop at a boundary to a word rather than character.</param>
        /// <param name="charsfitted">Set to the number of characters that can be renered at this size within the width.</param>
        /// <returns></returns>
        public LineSize MeasureString(CMapEncoding encoding, string s, int startOffset, double emsize, double availablePts, double?wordspacePts, double charspacePts, double hscale, bool vertical, bool wordboundary, out int charsfitted, FontUnitType useUnits = FontUnitType.UseFontPreference)
        {
            HorizontalMetrics table = this.Directories["hmtx"].Table as HorizontalMetrics;
            CMAPTable         cmap  = this.Directories["cmap"].Table as CMAPTable;
            OS2Table          os2   = this.Directories["OS/2"].Table as OS2Table;

            CMAPSubTable mac = cmap.GetOffsetTable(encoding);

            if (mac == null)
            {
                mac = cmap.GetOffsetTable(CMapEncoding.MacRoman);
            }

            HorizontalHeader hhead = this.Directories["hhea"].Table as HorizontalHeader;
            FontHeader       head  = this.Directories["head"].Table as FontHeader;

            double availableFU = availablePts * ((double)head.UnitsPerEm / emsize);
            double charspaceFU = NoCharacterSpace;

            if (charspacePts != NoCharacterSpace)
            {
                charspaceFU = charspacePts * ((double)head.UnitsPerEm / emsize);
            }

            double wordspaceFU = NoWordSpace;

            if (wordspacePts.HasValue)
            {
                wordspaceFU = (wordspacePts.Value * ((double)head.UnitsPerEm / emsize));
            }
            else if (charspacePts != NoCharacterSpace)
            {
                //If we dont have explicit wordspacing then we use the character spacing
                wordspaceFU = charspaceFU;
            }


            double len           = 0.0;
            double lastwordlen   = 0.0;
            int    lastwordcount = 0;

            charsfitted = 0;


            for (int i = startOffset; i < s.Length; i++)
            {
                char c = s[i];
                if (char.IsWhiteSpace(c))
                {
                    lastwordlen   = len;
                    lastwordcount = charsfitted;
                }

                int moffset = (int)mac.GetCharacterGlyphOffset(c);

                if (moffset >= table.HMetrics.Count)
                {
                    moffset = table.HMetrics.Count - 1;
                }

                Scryber.OpenType.SubTables.HMetric metric;
                metric = table.HMetrics[moffset];
                double w = metric.AdvanceWidth;

                if (i == 0)
                {
                    w -= metric.LeftSideBearing;
                }

                if (c == ' ')
                {
                    if (wordspaceFU != NoWordSpace)
                    {
                        w += wordspaceFU;
                    }
                }
                else if (charspaceFU != NoCharacterSpace)
                {
                    w += charspaceFU;
                }



                if (hscale != NoHorizontalScale)
                {
                    w *= hscale;
                }

                len += w;

                //check if we can fit more
                if (len > availableFU)
                {
                    len -= w;
                    break;
                }
                charsfitted++;
            }
            bool isboundary = false;

            if ((charsfitted + startOffset < s.Length) && wordboundary && lastwordlen > 0)
            {
                len         = lastwordlen;
                charsfitted = lastwordcount;
                isboundary  = true;
            }

            len = len * emsize;
            len = len / (double)head.UnitsPerEm;
            double h = GetLineHeight(useUnits, os2, hhead, head, emsize);

            return(new LineSize(len, h, charsfitted, startOffset, isboundary));
        }
Exemplo n.º 13
0
        internal bool ReadTableEntryCollection(Typeface typeface, RestoreTicket ticket, TableEntryCollection tables, BinaryReader input)
        {
            if (ticket != null)
            {
                return(ReadTableEntryCollectionOnRestoreMode(typeface, ticket, tables, input));
            }

            typeface.SetTableEntryCollection(tables.CloneTableHeaders());

            var rd = new EntriesReaderHelper(tables, input);
            //PART 1: basic information
            OS2Table          os2Table          = rd.Read(new OS2Table());
            Meta              meta              = rd.Read(new Meta());
            NameEntry         nameEntry         = rd.Read(new NameEntry());
            Head              head              = rd.Read(new Head());
            MaxProfile        maxProfile        = rd.Read(new MaxProfile());
            HorizontalHeader  horizontalHeader  = rd.Read(new HorizontalHeader());
            HorizontalMetrics horizontalMetrics = rd.Read(new HorizontalMetrics(horizontalHeader.NumberOfHMetrics, maxProfile.GlyphCount));
            VerticalHeader    vhea              = rd.Read(new VerticalHeader());

            if (vhea != null)
            {
                VerticalMetrics vmtx = rd.Read(new VerticalMetrics(vhea.NumOfLongVerMetrics));
            }

            Cmap cmaps = rd.Read(new Cmap());
            VerticalDeviceMetrics vdmx = rd.Read(new VerticalDeviceMetrics());
            Kern kern = rd.Read(new Kern());
            //------------------------------------
            //PART 2: glyphs detail
            //2.1 True type font

            GlyphLocations glyphLocations = rd.Read(new GlyphLocations(maxProfile.GlyphCount, head.WideGlyphLocations));
            Glyf           glyf           = rd.Read(new Glyf(glyphLocations));
            Gasp           gaspTable      = rd.Read(new Gasp());
            COLR           colr           = rd.Read(new COLR());
            CPAL           cpal           = rd.Read(new CPAL());

            //2.2 Cff font
            PostTable postTable = rd.Read(new PostTable());
            CFFTable  cff       = rd.Read(new CFFTable());

            //additional math table (if available)
            MathTable mathtable = rd.Read(new MathTable());
            //------------------------------------

            //PART 3: advanced typography
            GDEF gdef      = rd.Read(new GDEF());
            GSUB gsub      = rd.Read(new GSUB());
            GPOS gpos      = rd.Read(new GPOS());
            BASE baseTable = rd.Read(new BASE());
            JSTF jstf      = rd.Read(new JSTF());

            STAT stat = rd.Read(new STAT());

            if (stat != null)
            {
                //variable font
                FVar fvar = rd.Read(new FVar());
                if (fvar != null)
                {
                    GVar gvar = rd.Read(new GVar());
                    CVar cvar = rd.Read(new CVar());
                    HVar hvar = rd.Read(new HVar());
                    MVar mvar = rd.Read(new MVar());
                    AVar avar = rd.Read(new AVar());
                }
            }

            bool isPostScriptOutline = false;
            bool isBitmapFont        = false;

            typeface.SetBasicTypefaceTables(os2Table, nameEntry, head, horizontalMetrics);
            if (glyf == null)
            {
                //check if this is cff table ?
                if (cff == null)
                {
                    //check  cbdt/cblc ?
                    CBLC cblcTable = rd.Read(new CBLC());
                    if (cblcTable != null)
                    {
                        CBDT cbdtTable = rd.Read(new CBDT());
                        //read cbdt
                        //bitmap font

                        BitmapFontGlyphSource bmpFontGlyphSrc = new BitmapFontGlyphSource(cblcTable);
                        bmpFontGlyphSrc.LoadCBDT(cbdtTable);
                        Glyph[] glyphs = bmpFontGlyphSrc.BuildGlyphList();
                        typeface.SetBitmapGlyphs(glyphs, bmpFontGlyphSrc);
                        isBitmapFont = true;
                    }
                    else
                    {
                        //TODO:
                        EBLC fontBmpTable = rd.Read(new EBLC());
                        throw new NotSupportedException();
                    }
                }
                else
                {
                    isPostScriptOutline = true;
                    typeface.SetCffFontSet(cff.Cff1FontSet);
                }
            }
            else
            {
                typeface.SetTtfGlyphs(glyf.Glyphs);
            }

            //----------------------------
            typeface.CmapTable  = cmaps;
            typeface.KernTable  = kern;
            typeface.MaxProfile = maxProfile;
            typeface.HheaTable  = horizontalHeader;
            //----------------------------
            typeface.GaspTable = gaspTable;

            if (!isPostScriptOutline && !isBitmapFont)
            {
                //for true-type font outline
                FpgmTable fpgmTable = rd.Read(new FpgmTable());
                //control values table
                CvtTable  cvtTable         = rd.Read(new CvtTable());
                PrepTable propProgramTable = rd.Read(new PrepTable());

                typeface.ControlValues     = cvtTable?._controlValues;
                typeface.FpgmProgramBuffer = fpgmTable?._programBuffer;
                typeface.PrepProgramBuffer = propProgramTable?._programBuffer;
            }

            //-------------------------
            typeface.LoadOpenFontLayoutInfo(
                gdef,
                gsub,
                gpos,
                baseTable,
                colr,
                cpal);
            //------------

            typeface.SetSvgTable(rd.Read(new SvgTable()));
            typeface.PostTable = postTable;

            if (mathtable != null)
            {
                MathGlyphLoader.LoadMathGlyph(typeface, mathtable);
            }
#if DEBUG
            //test
            //int found = typeface.GetGlyphIndexByName("Uacute");
            if (typeface.IsCffFont)
            {
                //optional
                typeface.UpdateAllCffGlyphBounds();
            }
#endif
            typeface.UpdateLangs(meta);
            typeface.UpdateFrequentlyUsedValues();
            return(true);
        }