public GlyphMetrics[] GetGlyphMetrics(MyScript.IInk.Text.Text text, TextSpan[] spans) { var glyphMetrics = new List <GlyphMetrics>(); GetGlyphMetrics(text, spans, glyphMetrics); return(glyphMetrics.ToArray()); }
public Rectangle[] GetCharacterBoundingBoxes(MyScript.IInk.Text.Text text, TextSpan[] spans) { var glyphMetrics = GetGlyphMetrics(text, spans); Rectangle[] rectangles = new Rectangle[glyphMetrics.Length]; for (int i = 0; i < glyphMetrics.Length; ++i) { rectangles[i] = glyphMetrics[i].BoundingBox; } return(rectangles); }
public Rectangle[] GetCharacterBoundingBoxes(MyScript.IInk.Text.Text text, TextSpan[] spans) { List <Rectangle> rectangles = new List <Rectangle>(); if (Thread.CurrentThread == Application.Current.Dispatcher.Thread) { GetCharacterBoundingBoxes_(text, spans, rectangles, dpiX, dpiY); } else { Application.Current.Dispatcher.BeginInvoke(new Action(() => { GetCharacterBoundingBoxes_(text, spans, rectangles, dpiX, dpiY); })).Wait(); } return(rectangles.ToArray()); }
public Rectangle[] GetCharacterBoundingBoxes(MyScript.IInk.Text.Text text, TextSpan[] spans) { var glyphMetrics = new List <GlyphMetrics>(); var rectangles = new List <Rectangle>(); GetGlyphMetrics(text, spans, glyphMetrics); foreach (var metrics in glyphMetrics) { rectangles.Add(metrics.BoundingBox); } return(rectangles.ToArray()); }
private static void GetCharacterBoundingBoxes_(MyScript.IInk.Text.Text text, TextSpan[] spans, List <Rectangle> rectangles, float dpiX, float dpiY) { var firstStyle = spans.First().Style; var textBlock = new TextBlock(); textBlock.FontFamily = new FontFamily(firstStyle.FontFamily); textBlock.Padding = new Thickness(0.0); textBlock.Margin = new Thickness(0.0); textBlock.TextWrapping = TextWrapping.NoWrap; textBlock.HorizontalAlignment = HorizontalAlignment.Left; textBlock.VerticalAlignment = VerticalAlignment.Top; foreach (var textSpan in spans) { var fontFamily = new FontFamily(textSpan.Style.FontFamily); var fontSize = mm2px(textSpan.Style.FontSize, dpiY); var fontWeight = FontWeight.FromOpenTypeWeight(textSpan.Style.FontWeight); var fontStretch = FontStretches.Normal; var fontStyle = FontStyles.Normal; if (textSpan.Style.FontStyle.Equals("italic")) { fontStyle = FontStyles.Italic; } else if (textSpan.Style.FontStyle.Equals("oblique")) { fontStyle = FontStyles.Oblique; } if (textSpan.Style.FontWeight >= 700) { fontWeight = FontWeights.Bold; } else if (textSpan.Style.FontWeight >= 400) { fontWeight = FontWeights.Normal; } else { fontWeight = FontWeights.Light; } // Process glyph one by one to generate one box per glyph for (int j = textSpan.BeginPosition; j < textSpan.EndPosition; ++j) { var textRun = new Run(text.GetGlyphLabelAt(j)); textRun.FontFamily = fontFamily; textRun.FontSize = fontSize; textRun.FontWeight = fontWeight; textRun.FontStyle = fontStyle; textRun.FontStretch = fontStretch; textBlock.Inlines.Add(textRun); } } textBlock.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); textBlock.Arrange(new Rect(textBlock.DesiredSize)); var baseline = (float)textBlock.BaselineOffset; var d = VisualTreeHelper.GetDrawing(textBlock); WalkDrawingForText(d, rectangles, baseline, dpiX, dpiY); }
private void GetGlyphMetrics(MyScript.IInk.Text.Text text, TextSpan[] spans, List <GlyphMetrics> glyphMetrics) { // Process glyph one by one to generate one box per glyph for (int s = 0; s < spans.Length; ++s) { var textSpan = spans[s]; var fontKey = FontKeyFromStyle(textSpan.Style); for (int j = textSpan.BeginPosition; j < textSpan.EndPosition; ++j) { var glyphLabel = text.GetGlyphLabelAt(j); var glyphMetrics_ = GetGlyphMetrics(fontKey, glyphLabel); glyphMetrics.Add(glyphMetrics_); } } if (glyphMetrics.Count == 0) { return; } // Draw text to get data for glyphs FormattedText formattedText; { var firstStyle = spans[0].Style; var firstFontKey = FontKeyFromStyle(firstStyle); var firstFontTypeFace = new Typeface(firstFontKey.FontFamily, firstFontKey.FontStyle, firstFontKey.FontWeight, firstFontKey.FontStretch); formattedText = new FormattedText ( text.Label, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, firstFontTypeFace, firstFontKey.FontSize, Brushes.Black ); formattedText.TextAlignment = TextAlignment.Left; for (int s = 0; s < spans.Length; ++s) { var textSpan = spans[s]; var charIndex = textSpan.BeginPosition; var charCount = textSpan.EndPosition - textSpan.BeginPosition; var fontKey = FontKeyFromStyle(textSpan.Style); var fontTypeFace = new Typeface(fontKey.FontFamily, fontKey.FontStyle, fontKey.FontWeight, fontKey.FontStretch); formattedText.SetFontFamily(fontKey.FontFamily, charIndex, charCount); formattedText.SetFontSize(fontKey.FontSize, charIndex, charCount); formattedText.SetFontWeight(fontKey.FontWeight, charIndex, charCount); formattedText.SetFontStretch(fontKey.FontStretch, charIndex, charCount); formattedText.SetFontStyle(fontKey.FontStyle, charIndex, charCount); formattedText.SetFontTypeface(fontTypeFace, charIndex, charCount); } } var drawing = new DrawingGroup(); { var ctx = drawing.Open(); ctx.DrawText(formattedText, new System.Windows.Point(0.0, 0.0)); ctx.Close(); } // Apply baseline and offsets of glyphs to bounding boxes float baseline = (float)formattedText.Baseline; WalkDrawingForText(drawing, glyphMetrics, baseline); }
public GlyphMetrics[] GetGlyphMetrics(MyScript.IInk.Text.Text text, TextSpan[] spans) { CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice(); GlyphMetrics[] glyphMetrics = new GlyphMetrics[text.GlyphCount]; var firstStyle = spans[0].Style; var firstFontKey = FontKeyFromStyle(firstStyle); if (text.GlyphCount == 1) { glyphMetrics[0] = GetGlyphMetrics(firstFontKey, text.Label, canvasDevice); } else { var textFormat = new CanvasTextFormat() { FontSize = mm2px(firstStyle.FontSize, dpiY), FontFamily = firstStyle.FontFamily, FontStyle = firstFontKey.FontStyle, FontWeight = firstFontKey.FontWeight }; using (var canvasTextLayout = new CanvasTextLayout(canvasDevice, text.Label, textFormat, 10000, 10000)) { for (int i = 0; i < spans.Length; ++i) { var charIndex = spans[i].BeginPosition; var charCount = spans[i].EndPosition - spans[i].BeginPosition; var style = spans[i].Style; var fontKey = FontKeyFromStyle(style); canvasTextLayout.SetFontFamily(charIndex, charCount, fontKey.FontFamily); canvasTextLayout.SetFontSize(charIndex, charCount, fontKey.FontSize); canvasTextLayout.SetFontWeight(charIndex, charCount, fontKey.FontWeight); canvasTextLayout.SetFontStyle(charIndex, charCount, fontKey.FontStyle); } // Use of TextElementEnumerator to get character indices as in the CanvasTextLayout var tee = StringInfo.GetTextElementEnumerator(text.Label); // Use of ClusterMetrics to identify ligatures in the CanvasTextLayout int cluster = 0; int clusterStartChar = 0; var clusterCharCount = canvasTextLayout.ClusterMetrics[cluster].CharacterCount; for (int i = 0, g = 0; i < text.GlyphCount; ++i) { var fontKey = new FontKey(canvasTextLayout.GetFontFamily(i) , canvasTextLayout.GetFontSize(i) , canvasTextLayout.GetFontWeight(i) , canvasTextLayout.GetFontStyle(i)); var glyphLabel = text.GetGlyphLabelAt(i); var glyphMetrics_ = GetGlyphMetrics(fontKey, glyphLabel, canvasDevice); // Find cluster associated to element if (tee.MoveNext()) { g = tee.ElementIndex; } while ((g < clusterStartChar) || (g >= (clusterStartChar + clusterCharCount))) { ++cluster; clusterStartChar += clusterCharCount; clusterCharCount = canvasTextLayout.ClusterMetrics[cluster].CharacterCount; } if (g > clusterStartChar) { // Ligature with the previous glyph // The position is not accurate because of glyphs substitution at rendering // but it makes the illusion. var prevGlyphMetrics = glyphMetrics[i - 1]; glyphMetrics_.BoundingBox.X = prevGlyphMetrics.BoundingBox.X + prevGlyphMetrics.BoundingBox.Width + prevGlyphMetrics.RightSideBearing + glyphMetrics_.LeftSideBearing; } else { var charPos = canvasTextLayout.GetCaretPosition(g, false); glyphMetrics_.BoundingBox.X += px2mm(charPos.X, dpiX); } glyphMetrics[i] = glyphMetrics_; } } } return(glyphMetrics); }
private static void GetGlyphMetrics_(MyScript.IInk.Text.Text text, TextSpan[] spans, List <GlyphMetrics> glyphMetrics, float dpiX, float dpiY) { var drawing = new DrawingGroup(); var ctx = drawing.Open(); float baseline = 0.0f; int spanCount = 0; foreach (var textSpan in spans) { var fontFamily = new FontFamily(textSpan.Style.FontFamily); var fontSize = mm2px(textSpan.Style.FontSize, dpiY); var fontWeight = FontWeight.FromOpenTypeWeight(textSpan.Style.FontWeight); var fontStretch = FontStretches.Normal; var fontStyle = FontStyles.Normal; if (textSpan.Style.FontStyle.Equals("italic")) { fontStyle = FontStyles.Italic; } else if (textSpan.Style.FontStyle.Equals("oblique")) { fontStyle = FontStyles.Oblique; } if (textSpan.Style.FontWeight >= 700) { fontWeight = FontWeights.Bold; } else if (textSpan.Style.FontWeight >= 400) { fontWeight = FontWeights.Normal; } else { fontWeight = FontWeights.Light; } var typeFace = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch); // Process glyph one by one to generate one box per glyph var label = ""; for (int j = textSpan.BeginPosition; j < textSpan.EndPosition; ++j) { var glyphLabel = text.GetGlyphLabelAt(j); var formattedText = new FormattedText ( glyphLabel, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeFace, fontSize, Brushes.Black ); formattedText.TextAlignment = TextAlignment.Left; var geometry = formattedText.BuildGeometry(new System.Windows.Point(0.0f, 0.0f)); var rect = geometry.Bounds; // For glyph without geometry (space) if (rect.IsEmpty) { rect = new Rect(0.0, 0.0, formattedText.Width, formattedText.Height); } var rectX = (float)rect.X; var rectY = (float)rect.Y; var rectW = (float)rect.Width; var rectH = (float)rect.Height; var leftBearing = -(float)(rect.X); var rightBearing = 0.0f; var glyphX = px2mm(rectX, dpiX); var glyphY = px2mm(rectY, dpiY); var glyphW = px2mm(rectW, dpiX); var glyphH = px2mm(rectH, dpiY); var glyphRect = new Rectangle(glyphX, glyphY, glyphW, glyphH); var glyphLeftBearing = px2mm(leftBearing, dpiX); var glyphRightBearing = px2mm(rightBearing, dpiX); glyphMetrics.Add(new GlyphMetrics(glyphRect, glyphLeftBearing, glyphRightBearing)); label += glyphLabel; } // Draw current span { var formattedText = new FormattedText ( label, System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeFace, fontSize, Brushes.Black ); formattedText.TextAlignment = TextAlignment.Left; if (spanCount == 0) { baseline = (float)formattedText.Baseline; } ctx.DrawText(formattedText, new System.Windows.Point(0.0, 0.0)); } ++spanCount; } ctx.Close(); // Apply baseline and offsets of glyphs to bounding boxes if (glyphMetrics.Count > 0) { WalkDrawingForText(drawing, glyphMetrics, baseline, dpiX, dpiY); } }
public GlyphMetrics[] GetGlyphMetrics(MyScript.IInk.Text.Text text, TextSpan[] spans) { CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice(); GlyphMetrics[] glyphMetrics = new GlyphMetrics[text.GlyphCount]; var firstStyle = spans[0].Style; var firstFontKey = FontKeyFromStyle(firstStyle); if (text.GlyphCount == 1) { glyphMetrics[0] = GetGlyphMetrics(firstFontKey, text.Label, canvasDevice); } else { var textFormat = new CanvasTextFormat() { FontSize = firstFontKey.FontSize, FontFamily = firstFontKey.FontFamily, FontStyle = firstFontKey.FontStyle, FontWeight = firstFontKey.FontWeight, WordWrapping = CanvasWordWrapping.NoWrap, Options = UseColorFont ? CanvasDrawTextOptions.EnableColorFont : CanvasDrawTextOptions.Default }; using (var canvasTextLayout = new CanvasTextLayout(canvasDevice, text.Label, textFormat, 0.0f, 0.0f)) { for (int i = 0; i < spans.Length; ++i) { var charIndex = text.GetGlyphBeginAt(spans[i].BeginPosition); var charCount = text.GetGlyphEndAt(spans[i].EndPosition - 1) - charIndex; var style = spans[i].Style; var fontKey = FontKeyFromStyle(style); canvasTextLayout.SetFontFamily(charIndex, charCount, fontKey.FontFamily); canvasTextLayout.SetFontSize(charIndex, charCount, fontKey.FontSize); canvasTextLayout.SetFontWeight(charIndex, charCount, fontKey.FontWeight); canvasTextLayout.SetFontStyle(charIndex, charCount, fontKey.FontStyle); } for (int i = 0; i < text.GlyphCount; ++i) { var glyphLabel = text.GetGlyphLabelAt(i); var glyphCharStart = text.GetGlyphBeginAt(i); var glyphCharEnd = text.GetGlyphEndAt(i); var glyphFontKey = new FontKey(canvasTextLayout.GetFontFamily(glyphCharStart) , canvasTextLayout.GetFontSize(glyphCharStart) , canvasTextLayout.GetFontWeight(glyphCharStart) , canvasTextLayout.GetFontStyle(glyphCharStart)); var glyphMetrics_ = GetGlyphMetrics(glyphFontKey, glyphLabel, canvasDevice); // Find cluster associated to element // (Use of ClusterMetrics to identify ligatures in the CanvasTextLayout) int cluster = -1; int clusterCharStart = 0; if (canvasTextLayout.ClusterMetrics != null) { for (int c = 0; c < canvasTextLayout.ClusterMetrics.Length; ++c) { var clusterCharCount = canvasTextLayout.ClusterMetrics[c].CharacterCount; if ((glyphCharStart >= clusterCharStart) && (glyphCharStart < (clusterCharStart + clusterCharCount))) { cluster = c; break; } clusterCharStart += clusterCharCount; } } if ((i > 0) && (cluster >= 0) && (glyphCharStart > clusterCharStart)) { // Ligature with the previous glyph // The position is not accurate because of glyphs substitution at rendering // but it makes the illusion. var prevGlyphMetrics = glyphMetrics[i - 1]; glyphMetrics_.BoundingBox.X = prevGlyphMetrics.BoundingBox.X + prevGlyphMetrics.BoundingBox.Width + prevGlyphMetrics.RightSideBearing + glyphMetrics_.LeftSideBearing; } else { float glyphX = 0.0f; var charRegions = canvasTextLayout.GetCharacterRegions(glyphCharStart, glyphCharEnd - glyphCharStart); if ((charRegions != null) && (charRegions.Length > 0)) { glyphX = (float)charRegions[0].LayoutBounds.X; } else { var glyphPos = canvasTextLayout.GetCaretPosition(glyphCharStart, false); glyphX = (float)glyphPos.X; } glyphMetrics_.BoundingBox.X += px2mm(glyphX, dpiX); } glyphMetrics[i] = glyphMetrics_; } } } return(glyphMetrics); }