/// <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)); }
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)); }
public double MeasureChars(string chars, int startOffset, double emsize, double available, bool wordboundary, out int fitted) { int totalUnits = (int)Math.Floor((available * this.FUnitsPerEm) / emsize); int measured = 0; int count = 0; int lastWordLen = 0; int lastWordCount = 0; for (int i = startOffset; i < chars.Length; i++) { char c = chars[i]; if (char.IsWhiteSpace(c)) { lastWordLen = measured; lastWordCount = count; } HMetric metric; if (_lookup.TryGetValue(c, out metric) == false) { int moffset = _offsets.GetCharacterGlyphOffset(c); if (moffset >= _metrics.Count) { moffset = _metrics.Count - 1; } metric = _metrics[moffset]; _lookup.Add(c, metric); } if (i == 0) { measured -= metric.LeftSideBearing; } measured += metric.AdvanceWidth; if (measured > totalUnits) { measured -= metric.AdvanceWidth; break; } else { count++; } } if (count + startOffset < chars.Length) { if (wordboundary && lastWordLen > 0) { //Not everything fitted so go bask to the last full word //(if there was one). measured = lastWordLen; count = lastWordCount; } } double w = (measured * emsize) / (double)_unitsPerEm; fitted = count; return(w); }