void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) { var canvas = e.Surface.Canvas; _drawableBounds = e.Info.Rect; canvas.Clear(); if (_skPath == null) { return; } SKMatrix transformMatrix = CreateMatrix(); SKPath transformedSkPath = new SKPath(); _skPath.Transform(transformMatrix, transformedSkPath); SKRect fillBounds = transformMatrix.MapRect(_pathFillBounds); SKRect strokeBounds; using (SKPath strokePath = new SKPath()) { _skPaint.GetFillPath(transformedSkPath, strokePath); strokeBounds = strokePath.Bounds; } if (_fill != null) { _skPaint.Style = SKPaintStyle.Fill; if (_fill is GradientBrush fillGradientBrush) { _skPaint.Shader = fillGradientBrush.CreateShader(fillBounds); } else if (_fill is SolidColorBrush fillSolidColorBrush) { _skPaint.Color = fillSolidColorBrush.ToSolidColor(); } canvas.DrawPath(transformedSkPath, _skPaint); _skPaint.Shader = null; } if (_stroke != null) { _skPaint.Style = SKPaintStyle.Stroke; if (_stroke is GradientBrush strokeGradientBrush) { UpdatePathStrokeBounds(); _skPaint.Shader = strokeGradientBrush.CreateShader(strokeBounds); } else if (_stroke is SolidColorBrush strokeSolidColorBrush) { _skPaint.Color = strokeSolidColorBrush.ToSolidColor(); } canvas.DrawPath(transformedSkPath, _skPaint); _skPaint.Shader = null; } }
public void GetFillPathIsWorkingWithLine() { var paint = new SKPaint(); var thinRect = SKRect.Create(20, 10, 0, 20); var rect = SKRect.Create(10, 10, 20, 20); var path = new SKPath(); path.MoveTo(20, 10); path.LineTo(20, 30); var fillPath = new SKPath(); var isFilled = paint.GetFillPath(path, fillPath); Assert.True(isFilled); Assert.Equal(thinRect, fillPath.Bounds); Assert.Equal(2, fillPath.PointCount); paint.StrokeWidth = 20; paint.IsStroke = true; isFilled = paint.GetFillPath(path, fillPath); Assert.True(isFilled); Assert.Equal(rect, fillPath.Bounds); Assert.Equal(4 + 1, fillPath.PointCount); // +1 becuase the last point is the same as the first Assert.Equal(4, fillPath.Points.Distinct().Count()); }
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) { SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPath circlePath = new SKPath()) { circlePath.AddCircle(info.Width / 2, info.Height / 2, Math.Min(info.Width / 2, info.Height / 2) - redThickStroke.StrokeWidth); if (!outlineThePath) { canvas.DrawPath(circlePath, blueFill); canvas.DrawPath(circlePath, redThickStroke); } else { using (SKPath outlinePath = new SKPath()) { redThickStroke.GetFillPath(circlePath, outlinePath); canvas.DrawPath(outlinePath, blueFill); canvas.DrawPath(outlinePath, redThinStroke); } } } }
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); } } }
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 void GetFillPathIsWorking() { var paint = new SKPaint(); var rect = new SKRect(10, 10, 30, 30); var path = new SKPath(); path.AddRect(rect); var fillPath = new SKPath(); var isFilled = paint.GetFillPath(path, fillPath); Assert.True(isFilled); Assert.Equal(rect, fillPath.Bounds); Assert.Equal(4, fillPath.PointCount); }
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 bool HitTest(Point p, IShape shape) { var stroke = shape.Stroke; if (stroke is not null && stroke.Width < 4) { stroke = new Stroke(color: stroke.Color, width: 4); } using var path = new SKPath(); path.AddOval(shape.Bounds.ToSk()); using var paint = new SKPaint() .SetStroke(stroke) .SetFill(shape.Fill) .SetPaintStyle(stroke, shape.Fill); using var fillPath = paint.GetFillPath(path); using var region = new SKRegion(fillPath); return(region.Contains((int)p.X, (int)p.Y)); }
/// <inheritdoc/> public IPathShape ToStrokePathShape(IBaseShape shape) { var path = PathGeometryConverter.ToSKPath(shape, 0.0, 0.0, (value) => (float)value); if (path == null) { return(null); } var factory = _serviceProvider.GetService <IFactory>(); var style = shape.Style != null ? (IShapeStyle)shape.Style?.Copy(null) : factory.CreateShapeStyle(ProjectEditorConfiguration.DefaulStyleName); var stroke = (IColor)style.Stroke.Copy(null); var fill = (IColor)style.Fill.Copy(null); style.Stroke = fill; style.Fill = stroke; using var pen = new SKPaint(); SkiaSharpRenderer.ToSKPaintPen(style, (value) => (float)value, 96.0, 96.0, true, pen); var result = pen.GetFillPath(path, 1.0f); if (result != null) { if (result.IsEmpty) { result.Dispose(); return(null); } var geometry = PathGeometryConverter.ToPathGeometry(result, 0.0, 0.0, factory); var pathShape = factory.CreatePathShape( "Path", style, geometry, true, false); result.Dispose(); return(pathShape); } return(null); }
/// <summary> /// Update path cache for given stroke width. /// </summary> /// <param name="strokeWidth">Stroke width.</param> private void UpdatePathCache(float strokeWidth) { var strokePath = new SKPath(); // For stroke widths close to 0 simply use empty path. Render bounds are cached from fill path. if (Math.Abs(strokeWidth) < float.Epsilon) { _pathCache.Cache(strokePath, strokeWidth, Bounds); } else { using (var paint = new SKPaint()) { paint.IsStroke = true; paint.StrokeWidth = strokeWidth; paint.GetFillPath(EffectivePath, strokePath); _pathCache.Cache(strokePath, strokeWidth, strokePath.TightBounds.ToAvaloniaRect()); } } }
public CatsInFramePage() { Title = "Cats in Frame"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; // Move (0, 0) point to center of cat path catPath.Transform(SKMatrix.MakeTranslation(-240, -175)); // Now catPath is 400 by 250 // Scale it down to 160 by 100 catPath.Transform(SKMatrix.MakeScale(0.40f, 0.40f)); // Get the outlines of the contours of the cat path SKPath outlinedCatPath = new SKPath(); catStroke.GetFillPath(catPath, outlinedCatPath); // Create a 2D path effect from those outlines SKPathEffect fillEffect = SKPathEffect.Create2DPath( new SKMatrix { ScaleX = 170, ScaleY = 110, TransX = 75, TransY = 80, Persp2 = 1 }, outlinedCatPath); // Create a 1D path effect from the scallop path SKPathEffect strokeEffect = SKPathEffect.Create1DPath(scallopPath, 75, 0, SKPath1DPathEffectStyle.Rotate); // Set the sum the effects to frame paint framePaint.PathEffect = SKPathEffect.CreateSum(fillEffect, strokeEffect); }
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); } }) }); }