public void Render(SKCanvas canvas, IGeometryVisual geometry, double scale) { var moist = geometry as IMoist; if (moist == null || !moist.IsValid) { return; } using (var paint = new SKPaint()) { // Setup common paint parameters paint.Color = moist.ToolSettings.SelectedColor.ToSkiaColor(); paint.IsAntialias = true; paint.IsStroke = false; var text = moist.ToolSettings.SelectedText; if (string.IsNullOrEmpty(text)) { paint.StrokeWidth = (float)(moist.Size * scale); paint.StrokeCap = SKStrokeCap.Round; canvas.DrawPoint((float)(moist.Point.X * scale), (float)(moist.Point.Y * scale), paint); } else { paint.TextSize = (float)(moist.Size * scale); // Get the path of the text to calibrate the touch point to the middle of the text area var originalTextPath = paint.GetTextPath(text, (float)(moist.Point.X * scale), (float)(moist.Point.Y * scale)); // Set the mid of the text area to the touch point var calibratedX = originalTextPath.Bounds.Left - originalTextPath.Bounds.Width / 2; var calibratedY = originalTextPath.Bounds.Bottom + originalTextPath.Bounds.Height / 2; // Set the right text color var textColor = Converter.ContrastColor(moist.ToolSettings.SelectedColor); // Get the path of the calibrated text area and add some padding to the rect var calibratedTextPath = paint.GetTextPath(text, calibratedX, calibratedY); // Rect parameters float left; float top; float right; float bottom; float cornerRadius; var textSizeDependentPadding = paint.TextSize / 4; left = calibratedTextPath.Bounds.Left - textSizeDependentPadding; top = calibratedTextPath.Bounds.Top - textSizeDependentPadding; right = calibratedTextPath.Bounds.Right + textSizeDependentPadding; bottom = calibratedTextPath.Bounds.Bottom + textSizeDependentPadding; cornerRadius = paint.TextSize / 2; var rect = new SKRect(left, top, right, bottom); // Draw background rect canvas.DrawRoundRect(rect, cornerRadius, cornerRadius, paint); // Draw text paint.Color = textColor.ToSkiaColor(); canvas.DrawText(text, calibratedX, calibratedY, paint); // Draw the background border in same color as text paint.IsStroke = true; canvas.DrawRoundRect(rect, cornerRadius, cornerRadius, paint); } } }
public void Render(SKCanvas canvas, IGeometryVisual gemoetry, double scale) { var text = gemoetry as IText; if (text == null || !text.IsValid) { return; } using (var paint = new SKPaint()) { // Setup common paint parameters paint.IsAntialias = true; paint.IsStroke = false; paint.TextSize = (float)(text.Size * scale); paint.Color = text.Color.ToSkiaColor(); // Get the path of the text to calibrate the touch point to the middle of the text area var originalTextPath = paint.GetTextPath(text.Value, (float)(text.Point.X * scale), (float)(text.Point.Y * scale)); // Set the mid of the text area to the touch point var calibratedX = originalTextPath.Bounds.Left - originalTextPath.Bounds.Width / 2; var calibratedY = originalTextPath.Bounds.Bottom + originalTextPath.Bounds.Height / 2; if (text.IsFilled) { // Set the right text color var textColor = Converter.ContrastColor(text.Color); var calibratedTextPath = paint.GetTextPath(text.Value, calibratedX, calibratedY); // Get the path of the calibrated text area and add some padding to the rect var left = calibratedTextPath.Bounds.Left - Padding; var top = calibratedTextPath.Bounds.Top - Padding; var right = calibratedTextPath.Bounds.Right + Padding; var bottom = calibratedTextPath.Bounds.Bottom + Padding; var rect = new SKRect(left, top, right, bottom); // Draw background rect canvas.DrawRect(rect, paint); // Draw text paint.Color = textColor.ToSkiaColor(); canvas.DrawText(text.Value, calibratedX, calibratedY, paint); // Draw the background border in same color as text paint.IsStroke = true; canvas.DrawRect(rect, paint); } else { // Draw Text canvas.DrawText(text.Value, calibratedX, calibratedY, paint); } } }
private void DrawTooltip(SKCanvas canvas, ChartEntry entry) { using (var textPaint = new SKPaint { Style = SKPaintStyle.StrokeAndFill, Color = TooltipTextColor, TextAlign = SKTextAlign.Center, TextSize = TooltipTextSize }) { var topBottomMargin = TooltipTextSize; var tooltipTextYPosition = _tooltipPoint.Y - TooltipYOffset - topBottomMargin; var textPath = textPaint.GetTextPath(entry.Label, _tooltipPoint.X, tooltipTextYPosition); using (var tooltipBackgroundPaint = new SKPaint { Style = SKPaintStyle.StrokeAndFill, Color = TooltipBackgroundColor }) { var leftRightMargin = TooltipTextSize / 2; canvas.DrawRoundRect(new SKRect(textPath.Bounds.Left - leftRightMargin, textPath.Bounds.Top - topBottomMargin, textPath.Bounds.Right + leftRightMargin, textPath.Bounds.Bottom + topBottomMargin), TooltipRadius, TooltipRadius, tooltipBackgroundPaint); } canvas.DrawText(entry.Label, _tooltipPoint.X, tooltipTextYPosition, textPaint); } }
private static MemoryStream CreateCallbackImage(City city) { using var paint = new SKPaint { Color = new SKColor((byte)Random.Next(0, 256), (byte)Random.Next(0, 256), (byte)Random.Next(0, 256)), Typeface = SKTypeface.FromFamilyName(null, SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright), TextSize = 20 }; SKRect bounds; using (var textPath = paint.GetTextPath(city.Name, 0, 0)) { // Set transform to center and enlarge clip path to window height textPath.GetTightBounds(out bounds); } using (var bitmap = new SKBitmap((int)(bounds.Width + 1), (int)(bounds.Height + 1))) using (var canvas = new SKCanvas(bitmap)) { canvas.Clear(); canvas.DrawText(city.Name, -bounds.Left, -bounds.Top, paint); var memStream = new MemoryStream(); using (var wStream = new SKManagedWStream(memStream)) { bitmap.Encode(wStream, SKEncodedImageFormat.Png, 100); } return(memStream); } }
public GlobularTextPage() { Title = "Globular Text"; canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; using (SKPaint textPaint = new SKPaint()) { textPaint.Typeface = SKTypeface.FromFamilyName("Times New Roman"); textPaint.TextSize = 100; using (SKPath textPath = textPaint.GetTextPath("HELLO", 0, 0)) { SKRect textPathBounds; textPath.GetBounds(out textPathBounds); globePath = textPath.CloneWithTransform((SKPoint pt) => { double longitude = (Math.PI / textPathBounds.Width) * (pt.X - textPathBounds.Left) - Math.PI / 2; double latitude = (Math.PI / textPathBounds.Height) * (pt.Y - textPathBounds.Top) - Math.PI / 2; longitude *= 0.75; latitude *= 0.75; float x = (float)(Math.Cos(latitude) * Math.Sin(longitude)); float y = (float)Math.Sin(latitude); return(new SKPoint(x, y)); }); } } }
public void GetTextPathSucceedsForEmtptyString() { var paint = new SKPaint(); paint.TextEncoding = SKTextEncoding.Utf8; Assert.NotNull(paint.GetTextPath("", 0, 0)); }
public static void Save(Dictionary <int, ushort> characterToGlyphMap, SKTypeface typeface, float textSize, string fill, string outputDirectory, ZipArchive?zipArchive) { var skColor = new SKColor(0x00, 0x00, 0x00); using var skTextPaint = new SKPaint { IsAntialias = true, Color = skColor, Typeface = typeface, TextEncoding = SKTextEncoding.Utf32, TextSize = textSize, TextAlign = SKTextAlign.Center, LcdRenderText = true, SubpixelText = true }; var metrics = skTextPaint.FontMetrics; var mAscent = metrics.Ascent; var mDescent = metrics.Descent; foreach (var kvp in characterToGlyphMap) { var charCode = kvp.Key; var utf32 = Char.ConvertFromUtf32((int)charCode); float x = 0; float y = (mAscent / 2.0f) - mDescent / 2.0f; using var outlinePath = skTextPaint.GetTextPath(utf32, x, y); using var fillPath = skTextPaint.GetFillPath(outlinePath); fillPath.Transform(SKMatrix.CreateTranslation(-fillPath.Bounds.Left, -fillPath.Bounds.Top)); var bounds = fillPath.Bounds; var svgPathData = fillPath.ToSvgPathData(); var sb = new StringBuilder(); sb.AppendLine($"<svg viewBox=\"{bounds.Left} {bounds.Top} {bounds.Width} {bounds.Height}\" xmlns=\"http://www.w3.org/2000/svg\">"); // width=\"{bounds.Width}\" height=\"{bounds.Height}\" sb.AppendLine($" <path fill=\"{fill}\" d=\"{svgPathData}\"/>"); sb.AppendLine($"</svg>"); var svg = sb.ToString(); var outputPath = Path.Combine(outputDirectory, $"{charCode.ToString("X2").PadLeft(5, '0')}_{typeface.FamilyName}.svg"); if (zipArchive != null) { var zipArchiveEntry = zipArchive.CreateEntry(outputPath); using var streamWriter = new StreamWriter(zipArchiveEntry.Open()); streamWriter.Write(svg); } else { using var streamWriter = File.CreateText(outputPath); streamWriter.Write(svg); } } }
/// <summary> /// Returns a font scale value based on the size of the letter X in a given typeface. /// </summary> /// <param name="typeface">The typeface to measure the scale from.</param> /// <returns>A float value typically between 0 and 1. Many common typefaces have values around 0.5.</returns> internal static float GetFontScale(SKTypeface typeface) { var text = "X"; using var paint = new SKPaint { Typeface = typeface, TextSize = 1 }; var rect = paint.GetTextPath(text, 0, 0).ComputeTightBounds(); return((rect.Width + rect.Height) / 2); }
private void DrawShadow(SKCanvas canvas, SKTypeface font, string text = "Xamarin", int x = 0, int y = 0, int fontsize = 200, int strokewidth = 2, string shadowcolor = "#AAffff00", string shadowg1 = "#ff0000", string shadowg2 = "#cccccc") { using (SKPaint measurepaint = new SKPaint()) { measurepaint.Style = SKPaintStyle.Fill; measurepaint.IsAntialias = true; measurepaint.Typeface = font; measurepaint.TextSize = (float)fontsize; using (SKPath textPath = measurepaint.GetTextPath(text, (float)x, (float)y + (float)fontsize)) { using (SKPaint paint2 = new SKPaint()) { paint2.IsAntialias = true; paint2.StrokeMiter = 1000; paint2.StrokeCap = SKStrokeCap.Round; paint2.StrokeJoin = SKStrokeJoin.Round; paint2.Style = SKPaintStyle.StrokeAndFill; paint2.StrokeWidth = (float)strokewidth; if (Gradient) { paint2.Color = FromString(shadowcolor); } else { paint2.Color = FromString(shadowg1); } paint2.Typeface = font; paint2.TextSize = (float)fontsize; SKRect textBounds = textPath.Bounds; if (Gradient) { paint2.Shader = SKShader.CreateLinearGradient( new SKPoint(textBounds.Left + textBounds.Width * 0.5f, textBounds.Top), new SKPoint(textBounds.Left + textBounds.Width * 0.5f, textBounds.Bottom), new SKColor[] { FromString(shadowg1), FromString(shadowg2) }, null, SKShaderTileMode.Clamp); } paint2.ImageFilter = SKImageFilter.CreateDropShadow(8, 8, 4, 4, FromString(shadowcolor), SKDropShadowImageFilterShadowMode.DrawShadowOnly); canvas.DrawPath(textPath, paint2); } } } }
public static void Test(string outputDirectory) { int width = 500; int height = 500; SKRect svgBounds = SKRect.Create(0, 0, 100, 100); outputDirectory = System.IO.Path.Combine(outputDirectory, "SkiaTestFile.svg"); using (SKFileWStream stream = new SKFileWStream(outputDirectory)) // there are a few types of streams { using (SKCanvas canvas = SKSvgCanvas.Create(svgBounds, stream)) // SKBitmap bitmap = new SKBitmap(width, height); // using (SKCanvas canvas = new SKCanvas(bitmap)) { using (SKPaint paint = new SKPaint()) { paint.Typeface = SKTypeface.FromFamilyName(null, SKTypefaceStyle.Bold); paint.TextSize = 10; // paint.Style = SKPaintStyle.Stroke; // paint.StrokeWidth = 1; // paint.Color = SKColors.Red; using (SKPath textPath = paint.GetTextPath("CODE", 0, 0)) { // Set transform to center and enlarge clip path to window height SKRect bounds; textPath.GetTightBounds(out bounds); // canvas.Translate(width / 2, height/ 2); // canvas.Scale(width / bounds.Width, height / bounds.Height); // canvas.Translate(-bounds.MidX, -bounds.MidY); canvas.Translate(-bounds.Left, -bounds.Top); // Set the clip path // canvas.ClipPath(textPath); canvas.DrawPath(textPath, paint); } // End Using textPath } // End Using paint } // End Using canvas } // End Using stream // string foo = bitmap.ToString(); //System.Console.WriteLine(foo); System.Console.WriteLine("text"); }
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) { SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPaint textPaint = new SKPaint()) { // Set Style for the character outlines textPaint.Style = SKPaintStyle.Stroke; // Set TextSize based on screen size textPaint.TextSize = Math.Min(info.Width, info.Height); // Measure the text SKRect textBounds; textPaint.MeasureText("@", ref textBounds); // Coordinates to center text on screen float xText = info.Width / 2 - textBounds.MidX; float yText = info.Height / 2 - textBounds.MidY; // Get the path for the character outlines using (SKPath textPath = textPaint.GetTextPath("@", xText, yText)) { // Create a new path for the outlines of the path using (SKPath outlinePath = new SKPath()) { // Convert the path to the outlines of the stroked path textPaint.StrokeWidth = 25; textPaint.GetFillPath(textPath, outlinePath); // Stroke that new path using (SKPaint outlinePaint = new SKPaint()) { outlinePaint.Style = SKPaintStyle.Stroke; outlinePaint.StrokeWidth = 5; outlinePaint.Color = SKColors.Red; canvas.DrawPath(outlinePath, outlinePaint); } } } } }
public static void Save(Dictionary <int, ushort> characterToGlyphMap, SKTypeface typeface, float textSize, string brush, StreamWriter streamWriter) { var skColor = new SKColor(0x00, 0x00, 0x00); using var skTextPaint = new SKPaint { IsAntialias = true, Color = skColor, Typeface = typeface, TextEncoding = SKTextEncoding.Utf32, TextSize = textSize, TextAlign = SKTextAlign.Center, LcdRenderText = true, SubpixelText = true }; var metrics = skTextPaint.FontMetrics; var mAscent = metrics.Ascent; var mDescent = metrics.Descent; streamWriter.WriteLine("<Styles xmlns=\"https://github.com/avaloniaui\""); streamWriter.WriteLine(" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">"); streamWriter.WriteLine(" <Style>"); streamWriter.WriteLine(" <Style.Resources>"); foreach (var kvp in characterToGlyphMap) { var charCode = kvp.Key; var utf32 = Char.ConvertFromUtf32(charCode); float x = 0; float y = (mAscent / 2.0f) - mDescent / 2.0f; using var outlinePath = skTextPaint.GetTextPath(utf32, x, y); using var fillPath = skTextPaint.GetFillPath(outlinePath); fillPath.Transform(SKMatrix.CreateTranslation(-fillPath.Bounds.Left, -fillPath.Bounds.Top)); var svgPathData = fillPath.ToSvgPathData(); streamWriter.WriteLine($" <GeometryDrawing x:Key=\"{charCode.ToString("X2").PadLeft(5, '0')}\" Brush=\"{brush}\" Geometry=\"{svgPathData}\"/>"); // x:Key=\"{key}\" } streamWriter.WriteLine(" </Style.Resources>"); streamWriter.WriteLine(" </Style>"); streamWriter.WriteLine("</Styles>"); }
public unsafe void TextInterceptsAreFoundCorrectly() { var text = "|"; var paint = new SKPaint(); paint.TextSize = 100; var widths = paint.GetTextIntercepts(text, 50, 100, 0, 100); Assert.Equal(2, widths.Length); var diff = widths[1] - widths[0]; var textPath = paint.GetTextPath(text, 0, 0); var pathWidth = textPath.TightBounds.Width; Assert.Equal(pathWidth, diff, 2); }
public static SKCanvas ClippingText(this SKCanvas canvas, SKImageInfo info, string text, SKPaint paint) { using (SKPath textPath = paint.GetTextPath(text, 0, 0)) { // Set transform to center and enlarge clip path to window height SKRect bounds; textPath.GetTightBounds(out bounds); textPath.FillType = SKPathFillType.InverseWinding; canvas.Translate(info.Width / 2, info.Height / 2); canvas.Scale((info.Width / bounds.Width) * 0.9f, (info.Height / bounds.Height) * 0.9f); canvas.Translate(-bounds.MidX, -bounds.MidY); // Set the clip path canvas.ClipPath(textPath); } // Reset transforms canvas.ResetMatrix(); return(canvas); }
public TextPathEffectPage() { Title = "Text Path Effect"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; // Get the bounds of textPathPaint SKRect textPathPaintBounds; textPathPaint.MeasureText(character, ref textPathPaintBounds); // Create textPath centered around (0, 0) SKPath textPath = textPathPaint.GetTextPath(character, -textPathPaintBounds.MidX, -textPathPaintBounds.MidY); // Create the path effect pathEffect = SKPathEffect.Create1DPath(textPath, littleSize, 0, SKPath1DPathEffectStyle.Translate); }
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) { SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(SKColors.Blue); using (SKPaint paint = new SKPaint()) { paint.Typeface = SKTypeface.FromFamilyName(null, SKTypefaceStyle.Bold); paint.TextSize = 10; using (SKPath textPath = paint.GetTextPath("CODE", 0, 0)) { // Set transform to center and enlarge clip path to window height SKRect bounds; textPath.GetTightBounds(out bounds); canvas.Translate(info.Width / 2, info.Height / 2); canvas.Scale(info.Width / bounds.Width, info.Height / bounds.Height); canvas.Translate(-bounds.MidX, -bounds.MidY); // Set the clip path canvas.ClipPath(textPath); } } // Reset transforms canvas.ResetMatrix(); // Display bitmap to fill window but maintain aspect ratio SKRect rect = new SKRect(0, 0, info.Width, info.Height); canvas.DrawBitmap(bitmap, rect.AspectFill(new SKSize(bitmap.Width, bitmap.Height))); }
private SkiaHelper CreateSkiaHelper() { return(new SkiaHelper() { Size = new Components.RawSize { Width = this.Width, Height = this.Height }, PostChain = new SkiaHelper.CanvasDelegate((SKCanvas canvas) => { using (var rectPaint = new SKPaint { StrokeWidth = 0, StrokeMiter = 0, StrokeJoin = SKStrokeJoin.Round, StrokeCap = SKStrokeCap.Round, Style = SKPaintStyle.Stroke, Color = SKColor.Parse("666"), TextSize = 32, IsAntialias = true }) using (var bgPaint = new SKPaint { StrokeWidth = 0, StrokeMiter = 0, StrokeJoin = SKStrokeJoin.Round, StrokeCap = SKStrokeCap.Round, Style = SKPaintStyle.Fill, Color = SKColor.Parse("33fff9a3"), TextSize = 32, IsAntialias = true }) using (var textPaint = new SKPaint { Typeface = SKFontManager.Default.MatchCharacter('가'), StrokeWidth = 0, StrokeMiter = 0, StrokeJoin = SKStrokeJoin.Round, StrokeCap = SKStrokeCap.Round, Style = SKPaintStyle.StrokeAndFill, Color = SKColor.Parse("FFFFFFFF"), TextSize = 32, IsAntialias = true }) using (var outlinePaint = new SKPaint { Style = textPaint.Style, Typeface = textPaint.Typeface, TextSize = textPaint.TextSize, StrokeCap = textPaint.StrokeCap, StrokeJoin = textPaint.StrokeJoin, StrokeMiter = textPaint.StrokeMiter, IsAntialias = textPaint.IsAntialias, StrokeWidth = 3, Color = SKColor.Parse("FF4374D9"), }) using (var outline2Paint = new SKPaint { Style = textPaint.Style, Typeface = textPaint.Typeface, TextSize = textPaint.TextSize, StrokeCap = textPaint.StrokeCap, StrokeJoin = textPaint.StrokeJoin, StrokeMiter = textPaint.StrokeMiter, IsAntialias = textPaint.IsAntialias, StrokeWidth = 6, Color = SKColor.Parse("FF5CD1E5") }) using (SKPaint preventPaint = new SKPaint { IsAntialias = true, StrokeWidth = 10, Style = SKPaintStyle.StrokeAndFill, Color = SKColors.Black }) using (SKPath frameTextPath = new SKPath()) { SKHelper.Skia_Canvas.Clear(SKColors.Transparent); float x = 10.0f; float y = 5.0f; float measuredWidth = 0; string str = SKHelper.ContentText; while (str != null && str.Length != 0) { SKRect bounds = new SKRect(); int textLength = (int)textPaint.BreakText(str, Size.Width - 24, out measuredWidth); outline2Paint.MeasureText(str, ref bounds); var b = Encoding.UTF8.GetBytes(str); var s = Encoding.UTF8.GetString(b, 0, textLength); if (bounds.Width > this.Width) { textLength -= Encoding.UTF8.GetByteCount($"{s[s.Length - 1]}"); } s = Encoding.UTF8.GetString(b, textLength, b.Length - textLength); // 띄어쓰기가 짤리면 줄 위로 올린다 for (int i = 0; i < s.Length; i++) { if (s[i] == ' ') { textLength++; } else { break; } } y += (int)bounds.Height + 2; using (SKPath textPath = textPaint.GetTextPath(Encoding.UTF8.GetString(b, 0, textLength), x, y)) using (SKPath outlinePath = new SKPath()) { using (SKPaint tempPaint = new SKPaint { IsAntialias = true, Color = SKColors.Black }) { tempPaint.GetFillPath(textPath, outlinePath); frameTextPath.AddPath(textPath, SKPathAddMode.Append); } } str = Encoding.UTF8.GetString(b, (int)textLength, b.Length - (int)textLength); } SKHelper.Skia_Canvas.DrawRect(new SKRect(0, 0, Size.Width, Size.Height), bgPaint); SKHelper.Skia_Canvas.DrawRect(new SKRect(0, 0, Size.Width, Size.Height), rectPaint); SKHelper.Skia_Canvas.DrawPath(frameTextPath, outline2Paint); SKHelper.Skia_Canvas.DrawPath(frameTextPath, outlinePaint); SKHelper.Skia_Canvas.DrawPath(frameTextPath, textPaint); } }) }); }