/// <summary> /// Calculates / Renders the Main Geometry object /// </summary> /// <returns></returns> private void BuildGeometry() { Uri ttfPathUri = new Uri(TtfPath); GlyphTypeface glyphTypeface = new GlyphTypeface(ttfPathUri); ushort[] glyphIndexes = new ushort[Text.Length]; double[] advanceWidths = new double[Text.Length]; for (int n = 0; n < Text.Length; n++) { ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[Text[n]]; glyphIndexes[n] = glyphIndex; double width = glyphTypeface.AdvanceWidths[glyphIndex] * HintingEmSize; advanceWidths[n] = width; } GlyphRun wholeString = new GlyphRun( glyphTypeface, //glyphTypeface 0, //bidiLevel Specifies the bidirectional layout level. Even-numbered and zero values imply left-to-right layout; odd-numbered values imply right-to-left layout. false, //isSideways HintingEmSize, //renderingEmSize glyphIndexes, //glyphIndices (IList<ushort>) Offset, //Point baselineOrigin advanceWidths, //IList<double> advancedWiths null, //IList<Point> glyphOffsets null, //IList<char> characters null, //string deviceFontName null, //IList<ushort> clustermap null, //IList<bool>caretStops null //System.Windows.MarkupLanguage ); TextAsGeometry = wholeString.BuildGeometry(); }
public override PathGeometry Build(SvgTextContentElement element, string text, double x, double y) { ComputeMeasurement(text, x, y); _textWidth = 0; if (_glyphRun == null) { return(new PathGeometry()); } // Approximate the width of the text... Rect designRect = _glyphRun.ComputeAlignmentBox(); designRect.Offset(_glyphRunOrigin.X, _glyphRunOrigin.Y); _textWidth = Math.Max(0, designRect.Right); PathGeometry pathGeometry = null; var geometry = _glyphRun.BuildGeometry(); if (geometry is PathGeometry) { pathGeometry = (PathGeometry)geometry; } else { pathGeometry = new PathGeometry(); pathGeometry.AddGeometry(geometry); } return(pathGeometry); }
public override void Render(DrawingContext context) { var c = (char)_rand.Next(65, 90); if (_fontSize + _direction > 200) { _direction = -10; } if (_fontSize + _direction < 20) { _direction = 10; } _fontSize += _direction; _glyphIndices[0] = _glyphTypeface.GetGlyph(c); _characters[0] = c; var glyphRun = new GlyphRun(_glyphTypeface, _fontSize, _characters, _glyphIndices); var geometry = glyphRun.BuildGeometry(); context.DrawGeometry(Brushes.Green, null, geometry); }
private bool CheckGlyphRun() { if (glyphRun == null) { if (string.IsNullOrEmpty(Text)) { return(false); } var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch); GlyphTypeface glyphTypeface; if (!typeface.TryGetGlyphTypeface(out glyphTypeface)) { return(false); } var glyphIndices = new ushort[Text.Length]; var advanceWidths = new double[Text.Length]; for (int i = 0; i < Text.Length; i++) { var glyphIndex = glyphTypeface.CharacterToGlyphMap[Text[i]]; glyphIndices[i] = glyphIndex; advanceWidths[i] = glyphTypeface.AdvanceWidths[glyphIndex] * FontSize; } glyphRun = new GlyphRun(glyphTypeface, 0, false, FontSize, glyphIndices, new Point(), advanceWidths, null, null, null, null, null, null); outline = glyphRun.BuildGeometry().GetWidenedPathGeometry(new Pen(null, OutlineThickness * 2d)); } return(true); }
private PathGeometry BuildStyledFontGeometry() { var typeface = new Typeface(Font, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); GlyphTypeface glyphTypeface; if (!typeface.TryGetGlyphTypeface(out glyphTypeface)) { return(null); } var glyphIndexes = new ushort[Font.Source.Length]; var advanceWidths = new double[Font.Source.Length]; for (int n = 0; n < Font.Source.Length; n++) { if (glyphTypeface.CharacterToGlyphMap.ContainsKey(Font.Source[n])) { ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[Font.Source[n]]; glyphIndexes[n] = glyphIndex; double width = glyphTypeface.AdvanceWidths[glyphIndex] * 12; advanceWidths[n] = width; } } var run = new GlyphRun(glyphTypeface, 0, false, 12, glyphIndexes, new Point(0, 12), advanceWidths, null, null, null, null, null, null); PathGeometry ret = PathGeometry.CreateFromGeometry(run.BuildGeometry()); ret.Freeze(); return(ret); }
public override void RenderGeometry(GeometryGroup geometry, double scale, double x, double y) { GlyphRun glyphRun = GetGlyphRun(scale, x, y); GeometryGroup geoGroup = glyphRun.BuildGeometry() as GeometryGroup; geometry.Children.Add(geoGroup); }
public override void RenderGeometry(GeometryGroup geometry, double scale, double x, double y) { GlyphRun glyphRun = GetGlyphRun(scale, x, y); GeometryGroup geoGroup = glyphRun.BuildGeometry() as GeometryGroup; PathGeometry pg = geoGroup.GetFlattenedPathGeometry(); geometry.Children.Add(pg); }
/// <summary> /// Returns a rough outline of a glyph run. useful for calculating a convex hull /// </summary> /// <param name="glyphRun">Glyph run to outline</param> /// <returns>List<Point> of geometry tracing the GlyphRun</Point></returns> public static List <Point> GetOutline(this GlyphRun glyphRun) { if (glyphRun != null) { var geo = glyphRun.BuildGeometry(); return(GetGeoPoints(geo)); } return(null); }
public void DrawGlyphRun(PenF pen, Color?fillColor, GlyphRun glyphRun, float?tolerance = null) { pen.Color = _transform.Transform(pen.Color); if (fillColor.HasValue) { fillColor = _transform.Transform(fillColor.Value); } _DrawGeometry(pen, fillColor, glyphRun.BuildGeometry(), tolerance); }
public GlyphRunGeometryControl() { var glyphTypeface = new Typeface(TestFontFamily).GlyphTypeface; var glyphIndices = new[] { glyphTypeface.GetGlyph('A'), glyphTypeface.GetGlyph('B'), glyphTypeface.GetGlyph('C') }; var characters = new[] { 'A', 'B', 'C' }; var glyphRun = new GlyphRun(glyphTypeface, 100, characters, glyphIndices); Geometry = glyphRun.BuildGeometry(); }
// External API public bool DrawGlyphs(GlyphRun glyphrun, Rect bounds, Matrix trans, string desp) { if (glyphrun == null) { return(true); } int start = 0; PrimitiveInfo topPI; Geometry topBounds; Geometry inter; // If glyph has intersection with something on the top, change to geometry fill // Use bounding rectangle to test for overlapping first, avoinding expensive BuildGeometry call if ((_overlapping != null) && FindIntersection(new RectangleGeometry(bounds), ref start, out topPI, out topBounds, out inter)) { start = 0; Geometry cur = glyphrun.BuildGeometry(); cur = Utility.TransformGeometry(cur, trans); if (FindIntersection(cur, ref start, out topPI, out topBounds, out inter)) { // FillGeometry expects brush in world space. Apply trans to brush. if (_brush != null) { _brush = _brush.ApplyTransformCopy(trans); } FillGeometry(topPI, cur, desp, null, null, start, inter, topBounds); return(true); } } _dc.Comment(desp); return(_dc.DrawGlyphs(glyphrun, _clip, trans, _brush)); }
/// <summary> /// Enumerates through the drawing group of a visual to extract the geometries. /// </summary> /// <param name="dg"></param> /// <param name="currentParent"></param> private static void EnumerateDrawingGroup(DrawingGroup dg, GeometryGroup currentParent) { for (int i = 0; i < dg.Children.Count; i++) { if (dg.Children[i] is GeometryDrawing) { GeometryDrawing geometryDrawing = dg.Children[i] as GeometryDrawing; if (geometryDrawing != null) { Geometry geometry = geometryDrawing.Geometry; currentParent.Children.Add(geometry); } } else if (dg.Children[i] is DrawingGroup) { EnumerateDrawingGroup((DrawingGroup)dg.Children[i], currentParent); } else if (dg.Children[i] is GlyphRunDrawing) { GlyphRunDrawing glyphrunDrawing = dg.Children[i] as GlyphRunDrawing; GlyphRun glyphrun = glyphrunDrawing.GlyphRun; if (glyphrun != null) { Geometry geometry = glyphrun.BuildGeometry(); currentParent.Children.Add(geometry); } } else if (dg.Children[i] is ImageDrawing) { ImageDrawing imagedrawing = dg.Children[i] as ImageDrawing; RectangleGeometry rg = new RectangleGeometry(imagedrawing.Rect); currentParent.Children.Add(rg); } else if (dg.Children[i] is VideoDrawing) { VideoDrawing videodrawing = dg.Children[i] as VideoDrawing; RectangleGeometry rg = new RectangleGeometry(videodrawing.Rect); currentParent.Children.Add(rg); } } }
private void Test2() { //Glyph系クラス GlyphRun glyphRun; GlyphRunDrawing glyphRunDrawing; Glyphs glyphs; GlyphTypeface glyphTypeface; FontFamily fontFamily = new FontFamily("Meiryo UI"); var typefaces = fontFamily.GetTypefaces(); Uri myFontUri = null; foreach (var face in typefaces) { face.TryGetGlyphTypeface(out GlyphTypeface gType); myFontUri = gType.FontUri; break; } glyphs = new(); glyphs.FontUri = myFontUri; glyphs.FontRenderingEmSize = 100; //glyphs.StyleSimulations = StyleSimulations.BoldItalicSimulation; glyphs.UnicodeString = "(ゆっくり)"; glyphs.Fill = Brushes.MediumOrchid; //glyphs.BidiLevel = 1; //glyphs.IsSideways = true; GlyphRun gRun = glyphs.ToGlyphRun(); var chars = gRun.Characters; var clustre = gRun.ClusterMap; var box = gRun.ComputeAlignmentBox(); var inkBox = gRun.ComputeInkBoundingBox(); var dfName = gRun.DeviceFontName; var inside = gRun.GetCaretCharacterHitFromDistance(100, out bool isindside); var hit = gRun.GetNextCaretCharacterHit(new System.Windows.Media.TextFormatting.CharacterHit()); var gInd = gRun.GlyphIndices; var gOffset = gRun.GlyphOffsets; var gTypeface = gRun.GlyphTypeface; MyGrid.Children.Add(glyphs); DrawingVisual dv = new(); //dv.Offset = new Vector(0, -100); using (var dc = dv.RenderOpen()) { //dc.DrawRectangle(Brushes.MediumBlue, null, new Rect(0, 0, 500, 500)); //dc.DrawRectangle(Brushes.MediumBlue, null, new Rect(0, 0, box.Width, box.Height)); dc.DrawGlyphRun(Brushes.MediumAquamarine, gRun); } Rect r3 = dv.Drawing.Bounds; Rect r = dv.ContentBounds; Rect r2 = dv.DescendantBounds; var geo = gRun.BuildGeometry(); Rect rectGeo1 = geo.Bounds; Rect rectGeo2 = geo.GetRenderBounds(null); RenderTargetBitmap bitmap = new((int)box.Width, (int)box.Height, 96, 96, PixelFormats.Pbgra32); bitmap.Render(dv); glyphRunDrawing = new(Brushes.MediumAquamarine, gRun); MyGrid.Background = new DrawingBrush(glyphRunDrawing); //Glyphs //FontUri フォント //FontRenderingEmSize フォントサイズみたいなもの //StyleSimulations 太字と斜体の指定 //BidiLevel 文字を並べる向きの指定、0or偶数で左から、奇数で右からになる //ToGlyphRun() GlyphRun作成 //GlyphRun クラス (System.Windows.Media) | Microsoft Docs //https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.media.glyphrun?view=net-6.0 // 同じ描画スタイルが設定され、サイズ、フォント、およびフォントの書体が同じである一連のグリフを表します。 //GlyphRunDrawingと組み合わせて使う //プロパティ //AdvanceWidths //グリフ インデックスに対応するアドバンス幅を表す Double 値の一覧を取得または設定します。 //BaselineOrigin Point //GlyphRun のベースライン原点を取得または設定します。 //BidiLevel Int32 //GlyphRun の双方向の入れ子レベルを取得または設定します。 //CaretStops bool //GlyphRun を表す Unicode で UTF16 コード ポイント毎にキャレット ストップがあるかどうかを決定する Boolean 値の一覧を取得または設定します。 //Characters List<Char> //GlyphRun の Unicode を表す UTF16 コード ポイントの一覧を取得または設定します。 //ClusterMap List<Uint16> //GlyphRun の文字をグリフ インデックスにマップする UInt16 値の一覧を取得または設定します。 //DeviceFontName string //GlyphRun が最適化される対象の、デバイス固有のフォントを取得または設定します。 //FontRenderingEmSize double //GlyphRun のレンダリングに使用する全角サイズを取得または設定します。 //GlyphIndices list<Uint16> //描画物理フォントのグリフ インデックスを表す UInt16 値の配列を取得または設定します。 //GlyphOffsets List<point> //GlyphRun のグリフのオフセットを表す Point 値の配列を取得または設定します。 //GlyphTypeface GlyphTypeface //GlyphTypeface の GlyphRun を取得または設定します。 //IsHitTestable bool //GlyphRun 内に有効なキャレット文字ヒットがあるかどうかを示す値を取得します。 //IsSideways bool //グリフを回転するかどうかを示す値を取得または設定します。 //Language XmlLanguage //XmlLanguage の GlyphRun を取得または設定します。 //PixelsPerDip Single //テキストを表示する PixelsPerDip を取得または設定します。 //メソッド //BuildGeometry // GlyphRunのジオメトリを取得します。 //ComputeAlignmentBox Rect // GlyphRunの配置ボックスを取得します。 //ComputeInkBoundingBox Rect // GlyphRunのインク境界ボックスを取得します。 //GetCaretCharacterHitFromDistance(Double, Boolean) CharacterHitグリフラン内でヒットした文字に関する情報を表します。 // GlyphRunのキャレットの文字ヒットを表すCharacterHit値を取得します。 //GetDistanceFromCaretCharacterHit(CharacterHit) double // GlyphRunの前縁から、指定された文字ヒットを含むキャレットストップの前縁または後縁までのオフセットを取得します。 //GetNextCaretCharacterHit(CharacterHit) CharacterHit // GlyphRunで論理方向にヒットした次の有効なキャレット文字を取得します。 //GetPreviousCaretCharacterHit(CharacterHit) CharacterHit // GlyphRunで論理方向にヒットした前の有効なキャレット文字を取得します。 }
/// <summary> /// 构建文本形状 /// </summary> /// <param name="text">文本内容</param> /// <param name="x">横坐标</param> /// <param name="y">纵坐标</param> /// <param name="totalwidth">总宽度</param> /// <returns>形状</returns> private Geometry BuildGlyphRun(string text, double x, double y, ref double totalwidth) { double baseline = y; SVGBaseLineShift baseline_shift = this.GetAttributeValue <SVGBaseLineShift>("baseline-shift", true, null); double font_size = this.GetAttributeValue <SVGDouble>("font-size", true, new SVGDouble(12)).GetValue(12); SVGFontFamily font_family = this.GetAttributeValue <SVGFontFamily>("font-family", true, SVGFontFamily.Default); SVGFontWeight font_weight = this.GetAttributeValue <SVGFontWeight>("font-weight", true, SVGFontWeight.Default); SVGFontStyle font_style = this.GetAttributeValue <SVGFontStyle>("font-style", true, SVGFontStyle.Default); SVGTextAnchor text_anchor = this.GetAttributeValue <SVGTextAnchor>("text-anchor", true, SVGTextAnchor.Default); SVGTextDecoration text_decoration = this.GetAttributeValue <SVGTextDecoration>("text-decoration", true, null); double letter_spacing = this.GetAttributeValue <SVGDouble>("letter-spacing", true, SVGDouble.Zero).GetValue(12); double word_spacing = this.GetAttributeValue <SVGDouble>("word-spacing", true, SVGDouble.Zero).GetValue(12); GlyphRun glyphs = null; Typeface type_face = new Typeface(font_family.Value, font_style.Value, font_weight.Value, FontStretch.FromOpenTypeStretch(9), SVGFontFamily.Default.Value); GlyphTypeface glyph_type_face; if (!type_face.TryGetGlyphTypeface(out glyph_type_face)) { return(null); } glyphs = new GlyphRun(); ((System.ComponentModel.ISupportInitialize)glyphs).BeginInit(); glyphs.GlyphTypeface = glyph_type_face; glyphs.FontRenderingEmSize = font_size; List <char> text_chars = new List <char>(); List <ushort> glyph_indices = new List <ushort>(); List <double> advance_widths = new List <double>(); totalwidth = 0; for (int i = 0; i < text.Length; ++i) { char c = text[i]; int code_point = c; ushort glyph_index; if (!glyph_type_face.CharacterToGlyphMap.TryGetValue(code_point, out glyph_index)) { continue; } text_chars.Add(c); double glyph_width = glyph_type_face.AdvanceWidths[glyph_index]; glyph_indices.Add(glyph_index); advance_widths.Add(glyph_width * font_size + letter_spacing); if (char.IsWhiteSpace(c)) { advance_widths[advance_widths.Count - 1] += word_spacing; } totalwidth += advance_widths[advance_widths.Count - 1]; } glyphs.Characters = text_chars.ToArray(); glyphs.GlyphIndices = glyph_indices.ToArray(); glyphs.AdvanceWidths = advance_widths.ToArray(); double alignmentoffset = 0; if (text_anchor.Value == TextAlignment.Center) { alignmentoffset = totalwidth / 2; } else if (text_anchor.Value == TextAlignment.Right) { alignmentoffset = totalwidth; } glyphs.BaselineOrigin = new Point(x - alignmentoffset, baseline); ((System.ComponentModel.ISupportInitialize)glyphs).EndInit(); GeometryGroup result = new GeometryGroup(); result.Children.Add(glyphs.BuildGeometry()); if (text_decoration != null) { double decoration_pos = 0; double decoration_thinkess = 0; if (text_decoration.Value == TextDecorationLocation.Strikethrough) { decoration_pos = baseline - (type_face.StrikethroughPosition * font_size); decoration_thinkess = type_face.StrikethroughThickness * font_size; } else if (text_decoration.Value == TextDecorationLocation.Underline) { decoration_pos = baseline - (type_face.UnderlinePosition * font_size); decoration_thinkess = type_face.UnderlineThickness * font_size; } else if (text_decoration.Value == TextDecorationLocation.OverLine) { decoration_pos = baseline - font_size; decoration_thinkess = type_face.StrikethroughThickness * font_size; } System.Windows.Rect bounds = new System.Windows.Rect(result.Bounds.Left, decoration_pos, result.Bounds.Width, decoration_thinkess); result.Children.Add(new RectangleGeometry(bounds)); } return(result); }
public override Geometry Build(SvgTextContentElement element, string text, double x, double y) { var alignment = this.TextAlignment; if (alignment != TextAlignment.Left) { var textSize = this.MeasureText(element, text, true); var textWidth = Math.Max(textSize.Width, this.Width); if (alignment == TextAlignment.Center) { x -= textWidth / 2; } else { x -= textWidth; } } ComputeMeasurement(text, x, y + this.Baseline); _textWidth = 0; if (_glyphRun == null) { return(new GeometryGroup()); } // Approximate the width of the text... Rect designRect = _glyphRun.ComputeAlignmentBox(); //designRect.Offset(_glyphRunOrigin.X, _glyphRunOrigin.Y); _textWidth = Math.Max(0, designRect.Right); var geometry = _glyphRun.BuildGeometry(); if (geometry == null) { return(geometry); } if (_textDecorations == null || _textDecorations.Count == 0) { if (_buildPathGeometry) { PathGeometry pathGeometry = geometry as PathGeometry; if (pathGeometry == null) { pathGeometry = new PathGeometry(); pathGeometry.AddGeometry(geometry); } return(pathGeometry); } return(geometry); } var baseline = y + this.Baseline; GeometryGroup geomGroup = geometry as GeometryGroup; if (geomGroup == null) { geomGroup = new GeometryGroup(); geomGroup.Children.Add(geometry); } foreach (var textDeDecoration in _textDecorations) { double decorationPos = 0; double decorationThickness = 0; if (textDeDecoration.Location == TextDecorationLocation.Strikethrough) { decorationPos = baseline - (this.StrikethroughPosition * _fontSize); decorationThickness = this.StrikethroughThickness * _fontSize; } else if (textDeDecoration.Location == TextDecorationLocation.Underline) { decorationPos = baseline - (this.UnderlinePosition * _fontSize); decorationThickness = this.UnderlineThickness * _fontSize; } else if (textDeDecoration.Location == TextDecorationLocation.OverLine) { decorationPos = baseline - _fontSize; decorationThickness = this.OverlineThickness * _fontSize; } Rect bounds = new Rect(geomGroup.Bounds.Left, decorationPos, geomGroup.Bounds.Width, decorationThickness + 0.5); var rectGeom = new RectangleGeometry(bounds); if (_buildPathGeometry) { PathGeometry pathGeometry = new PathGeometry(); pathGeometry.AddGeometry(rectGeom); geomGroup.Children.Add(pathGeometry); } else { geomGroup.Children.Add(rectGeom); } } if (_buildPathGeometry) { PathGeometry pathGeometry = new PathGeometry(); pathGeometry.AddGeometry(geomGroup); return(pathGeometry); } return(geomGroup); }
public void DrawGlyphRun(Color?foreground, DrawingPen pen, GlyphRun glyphRun) { _needFilpCoordinate = false; _DrawPathGeometry(foreground, pen, glyphRun.BuildGeometry()); _needFilpCoordinate = true; }
public override Geometry Build(SvgTextContentElement element, string text, double x, double y) { if (_fontSize <= 0) { return(new GeometryGroup()); } // bool isRightToLeft = false; var xmlLang = element.XmlLang; if (!string.IsNullOrWhiteSpace(xmlLang)) { if (string.Equals(xmlLang, "ar", StringComparison.OrdinalIgnoreCase) || // Arabic language string.Equals(xmlLang, "he", StringComparison.OrdinalIgnoreCase)) // Hebrew language { // isRightToLeft = true; // this.BidiLevel = 1; if (text.Length > 0) { char[] charArray = text.ToCharArray(); Array.Reverse(charArray); text = new string(charArray); } } } var alignment = this.TextAlignment; if (alignment != TextAlignment.Left) { var textSize = this.MeasureText(element, text, true); var textWidth = Math.Max(textSize.Width, this.Width); if (alignment == TextAlignment.Center) { x -= textWidth / 2; } else { x -= textWidth; } } //else if (isRightToLeft) //{ // var textSize = this.MeasureText(element, text, true); // var textWidth = Math.Max(textSize.Width, this.Width); // x -= textWidth; //} ComputeMeasurement(text, x, y + this.Baseline); _textWidth = 0; if (_glyphRun == null) { return(new GeometryGroup()); } // Approximate the width of the text... Rect designRect = _glyphRun.ComputeAlignmentBox(); //designRect.Offset(_glyphRunOrigin.X, _glyphRunOrigin.Y); _textWidth = Math.Max(0, designRect.Right); var geometry = _glyphRun.BuildGeometry(); if (geometry == null) { return(geometry); } if (_textDecorations == null || _textDecorations.Count == 0) { if (_buildPathGeometry) { PathGeometry pathGeometry = geometry as PathGeometry; if (pathGeometry == null) { pathGeometry = new PathGeometry(); pathGeometry.AddGeometry(geometry); } return(pathGeometry); } return(geometry); } var baseline = y + this.Baseline; GeometryGroup geomGroup = geometry as GeometryGroup; if (geomGroup == null) { geomGroup = new GeometryGroup(); geomGroup.Children.Add(geometry); } foreach (var textDeDecoration in _textDecorations) { double decorationPos = 0; double decorationThickness = 0; if (textDeDecoration.Location == TextDecorationLocation.Strikethrough) { decorationPos = baseline - (this.StrikethroughPosition * _fontSize); decorationThickness = this.StrikethroughThickness * _fontSize; } else if (textDeDecoration.Location == TextDecorationLocation.Underline) { decorationPos = baseline - (this.UnderlinePosition * _fontSize); decorationThickness = this.UnderlineThickness * _fontSize; } else if (textDeDecoration.Location == TextDecorationLocation.OverLine) { decorationPos = baseline - _fontSize; decorationThickness = this.OverlineThickness * _fontSize; } Rect bounds = new Rect(geomGroup.Bounds.Left, decorationPos, geomGroup.Bounds.Width, decorationThickness + 0.5); var rectGeom = new RectangleGeometry(bounds); if (_buildPathGeometry) { PathGeometry pathGeometry = new PathGeometry(); pathGeometry.AddGeometry(rectGeom); geomGroup.Children.Add(pathGeometry); } else { geomGroup.Children.Add(rectGeom); } } if (_buildPathGeometry) { PathGeometry pathGeometry = new PathGeometry(); pathGeometry.AddGeometry(geomGroup); return(pathGeometry); } return(geomGroup); }
private void MakeBitmap() { while (true) { _newText.WaitOne(); GlyphTypeface glyphTypeface = null; if (_glyphTypeface != null) { lock (_glyphTypeface) { glyphTypeface = _glyphTypeface; } } if (glyphTypeface != null) { if (_lines == null || _lines.Length == 0) { _img = null; } else { if (_lines[0].VobSubMergedPack != null) { var bitmaps = _lines.Select(l => l.GetImage()).ToArray(); int bw = bitmaps.Max(b => b.Width); int bh = bitmaps.Sum(b => b.Height); BitmapSource bimage = CreateBitmap((int)bw, (int)bh, 96, dc => { double ypos = 0; for (int lb = 0; lb < bitmaps.Count(); lb++) { var bs = bitmaps[lb].ToBitmapSource(); Point bLoc = new Point((bw - bs.Width) / 2, ypos); Size bSize = new Size(bs.Width, bs.Height); ypos += bs.Height; dc.DrawImage(bs, new Rect(bLoc, bSize)); } }); bimage.Freeze(); _img = bimage; } else { var lines = new List <string>(_lines.Select(l => l.Text).SelectMany(t => t.Split(new string[] { Environment.NewLine }, 10000, StringSplitOptions.None))).ToArray(); { ushort[][] glyphIndexes = new ushort[lines.Length][]; double[][] advanceWidths = new double[lines.Length][]; double[] totalWidth = new double[lines.Length]; int l = 0; foreach (var text in lines) { glyphIndexes[l] = new ushort[text.Length]; advanceWidths[l] = new double[text.Length]; for (int n = 0; n < text.Length; n++) { if (glyphTypeface.CharacterToGlyphMap.ContainsKey(text[n])) { ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[text[n]]; glyphIndexes[l][n] = glyphIndex; double width = glyphTypeface.AdvanceWidths[glyphIndex] * _fontSize; advanceWidths[l][n] = width; totalWidth[l] += width; } } l++; } double w = totalWidth.Max(lw => lw) + _marginLeft + _marginRight; double h = (lines.Length * _fontSize) + _fontSize / 4 + _marginBottom; BitmapSource image = CreateBitmap((int)w, (int)h, 96, dc => { int line = 1; if (_back != Brushes.Transparent) { dc.DrawRectangle(_back, null, new Rect(0d, 0d, w, h)); } foreach (var text in lines) { if (string.IsNullOrEmpty(text)) { line++; continue; } var origin = new Point((w - totalWidth[line - 1]) / 2, line * _fontSize); var orig = ((SolidColorBrush)_stroke.Clone()).Color; var strokeBrush = new SolidColorBrush { Color = new Color() { B = orig.B, R = orig.R, G = orig.G, A = _strokeGlow ? (byte)35 : orig.A } }; var glyphRun = new GlyphRun(glyphTypeface, 0, false, _fontSize, glyphIndexes[line - 1], origin, advanceWidths[line - 1], null, null, null, null, null, null); if (_underline) { double y = origin.Y; y -= (glyphTypeface.Baseline + _typeface.UnderlinePosition * _fontSize); for (double i = _strokeThickness; i > 0; i--) { dc.DrawLine( new Pen(strokeBrush, (_typeface.UnderlineThickness * _fontSize) + i), new Point(origin.X - _strokeThickness / 2, y), new Point(origin.X + totalWidth[line - 1] + _strokeThickness / 2, y)); if (!_strokeGlow) { break; } } } var geo = glyphRun.BuildGeometry(); for (double i = _strokeThickness; i > 0; i--) { dc.DrawGeometry(null, new Pen(strokeBrush, i), geo); if (!_strokeGlow) { break; } } dc.DrawGlyphRun(_fill, glyphRun); if (_underline) { double y = origin.Y; y -= (glyphTypeface.Baseline + _typeface.UnderlinePosition * _fontSize); dc.DrawLine(new Pen(_fill, _typeface.UnderlineThickness * _fontSize), new Point(origin.X, y), new Point(origin.X + totalWidth[line - 1], y)); } line++; } }); image.Freeze(); _img = image; } } } } try { _newText.Release(); } catch { } Dispatcher.Invoke(((Action)(() => { _newText.WaitOne(); InvalidateVisual(); })), DispatcherPriority.Render, new object[] { }); } }