Esempio n. 1
0
        public FontMetric(XDocument fontXDoc)
        {
            m_fontName       = fontXDoc.Descendants("fontname").FirstOrDefault().Value;
            m_fullName       = fontXDoc.Descendants("fullname").FirstOrDefault().Value;
            m_family         = fontXDoc.Descendants("fontfamily").FirstOrDefault().Value;
            m_weight         = fontXDoc.Descendants("weight").FirstOrDefault().Value;
            m_boundingBox[0] = fontXDoc.Descendants("fontbbox").Where(x => x.Name == "xmin").Select(x => double.Parse(x.Value)).FirstOrDefault();
            m_boundingBox[1] = fontXDoc.Descendants("fontbbox").Where(x => x.Name == "ymin").Select(x => double.Parse(x.Value)).FirstOrDefault();
            m_boundingBox[2] = fontXDoc.Descendants("fontbbox").Where(x => x.Name == "xmax").Select(x => double.Parse(x.Value)).FirstOrDefault();
            m_boundingBox[3] = fontXDoc.Descendants("fontbbox").Where(x => x.Name == "ymax").Select(x => double.Parse(x.Value)).FirstOrDefault();
            m_capHeight      = (double)fontXDoc.Descendants("capheight").FirstOrDefault().Value.DoubleOrNull();
            m_xHeight        = (double)fontXDoc.Descendants("xheight").FirstOrDefault().Value.DoubleOrNull();
            m_ascender       = (double)fontXDoc.Descendants("ascender").FirstOrDefault().Value.DoubleOrNull();
            m_descender      = (double)fontXDoc.Descendants("descender").FirstOrDefault().Value.DoubleOrNull();
            m_ruleWidth      = fontXDoc.Descendants("rulewidth").FirstOrDefault().Value.DoubleOrNull();
            m_vGap           = double.Parse(fontXDoc.Descendants("vgap").FirstOrDefault().Value);
            // m_stdHw = (double) fontXDoc.Descendants("stdhw").FirstOrDefault().Value.DoubleOrNull();
            m_stdVw              = (double)fontXDoc.Descendants("stdvw").FirstOrDefault().Value.DoubleOrNull();
            m_undelinePosition   = (double)fontXDoc.Descendants("underlineposition").FirstOrDefault().Value.DoubleOrNull();
            m_underlineThickness = (double)fontXDoc.Descendants("underlinethickness").FirstOrDefault().Value.DoubleOrNull();
            m_italicAngle        = (double)fontXDoc.Descendants("italicangle").FirstOrDefault().Value.DoubleOrNull();
            m_charWidth          = (double)fontXDoc.Descendants("charwidth").FirstOrDefault().Value.DoubleOrNull();
            m_axisPosition       = (double)fontXDoc.Descendants("axisposition").FirstOrDefault().Value.DoubleOrNull();

            CharData = fontXDoc.Descendants("char")
                       .Select(x => new KeyValuePair <int, CharMetric>(
                                   int.Parse(x.Element("charid").Value.Substring(2), NumberStyles.HexNumber),
                                   new CharMetric(
                                       charName: x.Element("name").Value,
                                       codes: x.Descendants("charid").Select(z => (uint)int.Parse(z.Value.Substring(2), NumberStyles.HexNumber)).ToList(),
                                       width: double.Parse(x.Element("w").Value),
                                       bbox: new double[]
            {
                double.Parse(x.Element("b").Element("xmin").Value),
                double.Parse(x.Element("b").Element("ymin").Value),
                double.Parse(x.Element("b").Element("xmax").Value),
                double.Parse(x.Element("b").Element("ymax").Value)
            }))).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            XElement mg = fontXDoc.Descendants("missingglyph").FirstOrDefault();

            m_missingGlyph = new CharMetric(
                charName: mg.Element("name").Value,
                width: double.Parse(mg.Element("w").Value),
                codes: mg.Descendants("charid").Select(x => (uint)int.Parse(x.Value)).ToList(),
                bbox: new double[]
            {
                double.Parse(mg.Element("b").Element("xmin").Value),
                double.Parse(mg.Element("b").Element("ymin").Value),
                double.Parse(mg.Element("b").Element("xmax").Value),
                double.Parse(mg.Element("b").Element("ymax").Value)
            });
        }
Esempio n. 2
0
		//To Do: Implement. (/fonts/metric)
		public FontMetric(XDocument fontXDoc)
		{
            FontName = fontXDoc.Descendants("fontname").FirstOrDefault().Value;
            FullName = fontXDoc.Descendants("fullname").FirstOrDefault().Value;
            Family = fontXDoc.Descendants("fontfamily").FirstOrDefault().Value;
            Weight = fontXDoc.Descendants("weight").FirstOrDefault().Value;
            BBox[0] = fontXDoc.Descendants("fontbbox").Where(x=>x.Name=="xmin").Select(x=> double.Parse(x.Value)).FirstOrDefault();
            BBox[1] = fontXDoc.Descendants("fontbbox").Where(x => x.Name == "ymin").Select(x => double.Parse(x.Value)).FirstOrDefault();
            BBox[2] = fontXDoc.Descendants("fontbbox").Where(x => x.Name == "xmax").Select(x => double.Parse(x.Value)).FirstOrDefault();
            BBox[3] = fontXDoc.Descendants("fontbbox").Where(x => x.Name == "ymax").Select(x => double.Parse(x.Value)).FirstOrDefault();
            CapHeight = DoubleOrNull(fontXDoc.Descendants("capheight").FirstOrDefault().Value);
            XHeight = DoubleOrNull(fontXDoc.Descendants("xheight").FirstOrDefault().Value);
            Ascender= DoubleOrNull(fontXDoc.Descendants("ascender").FirstOrDefault().Value);
            Descender = DoubleOrNull(fontXDoc.Descendants("descender").FirstOrDefault().Value);
            RuleWidth = DoubleOrNull(fontXDoc.Descendants("rulewidth").FirstOrDefault().Value);
            VGap = double.Parse(fontXDoc.Descendants("vgap").FirstOrDefault().Value);
            StdHw = DoubleOrNull(fontXDoc.Descendants("stdhw").FirstOrDefault().Value);
            StdVw = DoubleOrNull(fontXDoc.Descendants("stdvw").FirstOrDefault().Value);
            UndelinePosition = DoubleOrNull(fontXDoc.Descendants("underlineposition").FirstOrDefault().Value);
            UnderlineThickness = DoubleOrNull(fontXDoc.Descendants("underlinethickness").FirstOrDefault().Value);
            ItalicAngle = DoubleOrNull(fontXDoc.Descendants("italicangle").FirstOrDefault().Value);
            CharWidth = DoubleOrNull(fontXDoc.Descendants("charwidth").FirstOrDefault().Value);
            AxisPosition = DoubleOrNull(fontXDoc.Descendants("axisposition").FirstOrDefault().Value);
            CharData = fontXDoc.Descendants("char").Select(x => new KeyValuePair<int, CharMetric>(int.Parse(x.Element("charid").Value.Substring(2), NumberStyles.HexNumber),
                new CharMetric()
                {
                    GlyphName = x.Element("name").Value,
                    Width = double.Parse(x.Element("w").Value),
                    Codes = x.Descendants("charid").Select(z => int.Parse(z.Value.Substring(2), NumberStyles.HexNumber)).ToList(),
                    BBox = new double[]
                        {
                            double.Parse(x.Element("b").Element("xmin").Value),
                            double.Parse(x.Element("b").Element("ymin").Value),
                            double.Parse(x.Element("b").Element("xmax").Value),
                            double.Parse(x.Element("b").Element("ymax").Value)
                        }
                })).ToDictionary(kvp => kvp.Key, kvp=> kvp.Value);
            XElement mg = fontXDoc.Descendants("missingglyph").FirstOrDefault();
            MissingGlyph = new CharMetric()
            {
                GlyphName = mg.Element("name").Value,
                Width = double.Parse(mg.Element("w").Value),
                Codes = mg.Descendants("charid").Select(x => int.Parse(x.Value)).ToList(),
                BBox = new double[]
                    {
                            double.Parse(mg.Element("b").Element("xmin").Value),
                            double.Parse(mg.Element("b").Element("ymin").Value),
                            double.Parse(mg.Element("b").Element("xmax").Value),
                            double.Parse(mg.Element("b").Element("ymax").Value)
                    }
            };
        }
Esempio n. 3
0
 public object[] FindChar(int ch)
 {
     foreach (FontMetricRecord fd in FontPool())
     {
         if (fd.Metric.CharData.ContainsKey(ch))
         {
             CharMetric cm = fd.Metric.CharData[ch];
             return(new object[] { cm, fd });
         }
         else
         {
             if (0 < ch && ch < 0xFFFF && MathDefaults.SpecialChars.ContainsKey(ch))
             {
                 return(FindChar(MathDefaults.SpecialChars[ch])); //ToDo: Verify correct working
             }
             return(null);                                        // new object[] { null, null };
         }
     }
     return(null);// new object[] { null, null }; //ToDo: verify correct working
 }
Esempio n. 4
0
        private void ReadFontMetrics()
        {
            SkipTo(0);
            // TTF version
            m_reader.ReadUInt32();
            // Number of tables
            int numTables = numTables = m_reader.ReadUInt16();

            numTables = BitConverter.ToInt16(BitConverter.GetBytes(numTables), 1);
            // searchRange
            m_reader.ReadUInt16();
            // entrySelector
            m_reader.ReadUInt16();
            // rangeShift
            m_reader.ReadUInt16();

            m_fontType = c_ttfAbbreviation;

            for (int i = 0; i < numTables; i++)
            {
                string tag      = Encoding.UTF8.GetString(BitConverter.GetBytes(m_reader.ReadUInt32()));
                uint   checksum = ReadUInt32Bytes();
                uint   offset   = ReadUInt32Bytes();
                uint   length   = ReadUInt32Bytes();
                m_tables.Add(tag, new Tuple <uint, uint>(offset, length));
            }

            SwitchTables("head");
            SkipTo(m_currentOffset + 12);
            uint magic = ReadUInt32Bytes();

            if (magic != 0x5F0F3CF5)
            {
                throw new Exception("Magic number in 'head' table does not match the spec");
            }

            Skip(2);
            m_unitsPerEm = ReadUInt16Bytes();
            m_eMScale    = 1.0 / Convert.ToDouble(m_unitsPerEm);

            Skip(16);
            double xMin = ReadInt16Bytes() * m_eMScale;
            double yMin = ReadInt16Bytes() * m_eMScale;
            double xMax = ReadInt16Bytes() * m_eMScale;
            double yMax = ReadInt16Bytes() * m_eMScale;

            m_boundingBox = new double[] { xMin, yMin, xMax, yMax };

            Skip(6);
            m_indexToLocFormat = ReadInt16Bytes();

            SwitchTables("maxp");
            SkipTo(m_currentOffset);
            Skip(4);
            m_numGlyphs = ReadUInt16Bytes();

            SwitchTables("name");
            SkipTo(m_currentOffset);
            Skip(2);
            uint numRecords = ReadUInt16Bytes();

            m_storageOffset = ReadUInt16Bytes() + m_currentOffset;

            for (int i = 0; i < numRecords; i++)
            {
                uint platformId = ReadUInt16Bytes();
                uint encodingId = ReadUInt16Bytes();
                uint languageId = ReadUInt16Bytes();
                uint nameId     = ReadUInt16Bytes();
                uint nameLength = ReadUInt16Bytes();
                uint nameOffset = ReadUInt16Bytes();

                if (platformId == 3 && encodingId == 1)
                {
                    if (englishCodes.Contains(languageId) || !m_uniNames.ContainsKey(nameId))
                    {
                        m_uniNames[nameId] = new Tuple <uint, uint>(nameOffset, nameLength);
                    }
                }
                else if (platformId == 1 && encodingId == 0)
                {
                    if (languageId == 0 || !m_macNames.ContainsKey(nameId))
                    {
                        m_macNames[nameId] = new Tuple <uint, uint>(nameOffset, nameLength);
                    }
                }
            }

            m_family   = GetName(1);
            m_fullName = GetName(4);
            m_fontName = GetName(6);

            SwitchTables("OS/2");
            SkipTo(m_currentOffset);
            uint tableVersion      = ReadUInt16Bytes();
            int  os2_xAvgCharWidth = ReadInt16Bytes();

            if (os2_xAvgCharWidth > 0)
            {
                m_charWidth = os2_xAvgCharWidth * EmScale;
            }

            uint wght = ReadUInt16Bytes();

            if (wght < 150)
            {
                m_weight = "Thin";
            }
            else if (wght < 250)
            {
                m_weight = "Extra-Light";
            }
            else if (wght < 350)
            {
                m_weight = "Light";
            }
            else if (wght < 450)
            {
                m_weight = "Regular";
            }
            else if (wght < 550)
            {
                m_weight = "Medium";
            }
            else if (wght < 650)
            {
                m_weight = "Demi-Bold";
            }
            else if (wght < 750)
            {
                m_weight = "Bold";
            }
            else if (wght < 850)
            {
                m_weight = "Extra-Bold";
            }
            else
            {
                m_weight = "Black";
            }

            Skip(62);
            m_ascender  = ReadInt16Bytes() * EmScale;
            m_descender = ReadInt16Bytes() * EmScale;

            if (tableVersion == 2)
            {
                Skip(14);
                int xh = ReadInt16Bytes();
                if (xh > 0)
                {
                    m_xHeight = xh * EmScale;
                }
                int ch = ReadInt16Bytes();
                if (ch > 0)
                {
                    m_capHeight = ch * EmScale;
                }
            }

            SwitchTables("post");
            SkipTo(m_currentOffset);
            Skip(4);
            m_italicAngle        = Convert.ToDouble(ReadFixed32());
            m_undelinePosition   = ReadInt16Bytes() * EmScale;
            m_underlineThickness = ReadInt16Bytes() * EmScale;

            SwitchTables("hhea");
            SkipTo(m_currentOffset);
            Skip(34);
            uint numHmtx = ReadUInt16Bytes();

            SwitchTables("hmtx");
            SkipTo(m_currentOffset);
            List <CharMetric> glyphArray = new List <CharMetric>();
            double            w          = 0;

            for (int i = 0; i < m_numGlyphs; i++)
            {
                if (i < numHmtx)
                {
                    w = ReadUInt16Bytes() * EmScale;
                    Skip(2);
                }
                glyphArray.Add(new CharMetric(w));
            }

            SwitchTables("cmap");
            SkipTo(m_currentOffset);
            Skip(2);
            Dictionary <Tuple <uint, uint>, uint> cmapEncodings = new Dictionary <Tuple <uint, uint>, uint>();
            uint numSubTables = ReadUInt16Bytes();

            for (int i = 0; i < numSubTables; i++)
            {
                uint platformId     = ReadUInt16Bytes();
                uint encodingId     = ReadUInt16Bytes();
                uint subTableoffset = ReadUInt32Bytes();
                cmapEncodings.Add(new Tuple <uint, uint>(platformId, encodingId), subTableoffset);
            }
            string             encodingScheme = "Unicode";
            uint               subtableOffset;
            Tuple <uint, uint> preferedSubTable = new Tuple <uint, uint>(3, 1);
            Tuple <uint, uint> symbolSubTable   = new Tuple <uint, uint>(3, 0);

            if (!cmapEncodings.ContainsKey(preferedSubTable))
            {
                if (!cmapEncodings.ContainsKey(symbolSubTable))
                {
                    throw new NotSupportedException(string.Format("Cannot use font {0}: no known subtable in 'cmap' table", m_fontName));
                }

                encodingScheme = "Symbol";
                subtableOffset = cmapEncodings[symbolSubTable];
            }
            else
            {
                subtableOffset = cmapEncodings[preferedSubTable];
            }

            SkipTo(m_currentOffset + subtableOffset);
            uint subTableFormat = ReadUInt16Bytes();

            if (subTableFormat != 4)
            {
                throw new NotSupportedException(string.Format("Unsupported format in 'cmap' table: {0}", subtableOffset));
            }

            uint subtableLength = ReadUInt16Bytes();

            Skip(2);
            uint segCount = ReadUInt16Bytes() / 2;

            Skip(6);
            List <uint> endCounts = Enumerable.Range(0, (int)segCount).Select(x => ReadUInt16Bytes()).ToList();

            Skip(2);
            List <uint> startCounts     = Enumerable.Range(0, (int)segCount).Select(x => ReadUInt16Bytes()).ToList();
            List <int>  idDeltas        = Enumerable.Range(0, (int)segCount).Select(x => ReadInt16Bytes()).ToList();
            List <uint> rangeOffsets    = Enumerable.Range(0, (int)segCount).Select(x => ReadUInt16Bytes()).ToList();
            uint        remainingLength = subtableLength - (8 * segCount) - 16;

            if (remainingLength <= 0)
            {
                remainingLength += 0x10000;
            }

            List <uint> glyphIdArray = Enumerable.Range(0, (int)remainingLength / 2).Select(x => ReadUInt16Bytes()).ToList();

            for (int i = 0; i < segCount; i++)
            {
                for (uint c = startCounts[i]; c < endCounts[i] + 1; c++)
                {
                    if (c == 0xFFFF)
                    {
                        continue;
                    }

                    uint gid;
                    if (rangeOffsets[i] > 0)
                    {
                        uint idx = (c - startCounts[i]) + (rangeOffsets[i] / 2) - (segCount - (uint)i);
                        gid = glyphIdArray[(int)idx];
                    }
                    else
                    {
                        gid = c + ((uint)idDeltas[i]);
                    }
                    if (gid >= 0x10000)
                    {
                        gid -= 0x10000;
                    }
                    else if (gid < 0)
                    {
                        gid += 0x10000;
                    }

                    CharMetric cm = glyphArray[(int)gid];
                    cm.Codes.Add(c);
                    if (encodingScheme == "Symbol" && (0xF020 <= c && c <= 0xF07F))
                    {
                        cm.Codes.Add(c - 0xF000);
                    }

                    if (string.IsNullOrEmpty(cm.GlyphName))
                    {
                        cm.GlyphName = string.Format("u{0:X4}", c);
                    }
                }
            }

            SwitchTables("loca");
            SkipTo(m_currentOffset);
            List <uint> glyphIndex  = new List <uint>();
            int         scalefactor = m_indexToLocFormat + 1;

            if (m_indexToLocFormat == 0)
            {
                glyphIndex.AddRange(Enumerable.Range(0, (int)m_numGlyphs + 1).Select(x => ReadUInt16Bytes() * 2));
            }
            else if (m_indexToLocFormat == 1)
            {
                glyphIndex.AddRange(Enumerable.Range(0, (int)m_numGlyphs + 1).Select(x => ReadUInt32Bytes()));
            }
            else
            {
                throw new InvalidDataException(string.Format("Invalid indexToLocFormat value ({0}) in 'head' table", m_indexToLocFormat));
            }

            SwitchTables("glyf");
            for (int i = 0; i < m_numGlyphs; i++)
            {
                CharMetric cm = glyphArray[i];
                if (glyphIndex[i] == glyphIndex[i + 1])
                {
                    cm.SetBBox(0, 0, 0, 0); // empty glyph
                }
                else
                {
                    SkipTo(m_currentOffset + glyphIndex[i] + 2);
                    double xMinc = ReadInt16Bytes() * EmScale;
                    double yMinc = ReadInt16Bytes() * EmScale;
                    double xMaxc = ReadInt16Bytes() * EmScale;
                    double yMaxc = ReadInt16Bytes() * EmScale;
                    cm.SetBBox(xMinc, yMinc, xMaxc, yMaxc);
                }
                cm.Codes.ForEach(x =>
                {
                    CharMetric ccm = new CharMetric(
                        charName: cm.GlyphName,
                        codes: cm.Codes.Select(y => (uint)y).ToList(),
                        width: cm.Width,
                        bbox: cm.BBox);
                    CharData.Add((int)x, ccm);
                });
            }
        }
Esempio n. 5
0
        public void MeasureText()
        {
            if (Text.Length == 0)
            {
                IsSpace = true;
                return;
            }

            CharMetric cm0 = null;
            CharMetric cm1 = null;
            CharMetric cm  = null;

            int[] ucstext = GetUCSText();
            foreach (int chcode in ucstext)
            {
                object[] chardesc = FindChar(chcode);
                if (chardesc == null)
                {
                    Width += Metric().MissingGlyph.Width;
                }
                else
                {
                    cm = (CharMetric)chardesc[0];
                    FontMetricRecord fd = (FontMetricRecord)chardesc[1];
                    fd.Used = true;
                    if (chcode == ucstext.First())  //ToDo: Verify correct translation
                    {
                        cm0 = cm;
                    }
                    if (chcode == ucstext.Last()) //ToDo: Verify correct translation
                    {
                        cm1 = cm;
                    }
                    Width += cm.Width;
                    if (Height + Depth == 0)
                    {
                        Height = cm.BBox[3];
                        Depth  = -(cm.BBox[1]);
                    }
                    else if (cm.BBox[3] != cm.BBox[1])
                    {
                        Height = Math.Max(Height, cm.BBox[3]);
                        Depth  = Math.Max(Depth, -(cm.BBox[1]));
                    }
                }
            }
            // Normalize to the font size
            Width  *= FontSize;
            Depth  *= FontSize;
            Height *= FontSize;

            // Add ascender/ descender values
            Ascender  = NominalAscender();
            Descender = NominalDescender();

            // Shape correction
            if (cm0 != null)
            {
                LeftBearing = Math.Max(0, -cm0.BBox[0]) * FontSize;
            }
            if (cm1 != null)
            {
                RightBearing = Math.Max(0, cm1.BBox[2] - cm.Width) * FontSize;
            }
            Width += LeftBearing + RightBearing;

            //Reset nominal metric
            NominalMetric = null;
        }