Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add drawing centric path building api. #206

Merged
merged 10 commits into from
Apr 13, 2022
Merged

Conversation

tocsoft
Copy link
Member

@tocsoft tocsoft commented Mar 1, 2022

Add drawing centric path building api and migrate GlyphRenderer to use new helper class directly

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following matches the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 馃懏.
  • I have provided test coverage for my change (where applicable)

Description

As we replatformed glyph rendering onto of this API its should be covered by font tests.

-migrate GlyphRenderer to use new helper class directly
@tocsoft
Copy link
Member Author

tocsoft commented Mar 1, 2022

we probably have some missing api/cases as those are just the ones we can utilise for GlyphRendering but we can expand as required.

That's the class I would hand the SVG path parsing logic off too (at least as an extension method).

@codecov
Copy link

codecov bot commented Mar 1, 2022

Codecov Report

Merging #206 (4148163) into main (1a8dc88) will increase coverage by 0%.
The diff coverage is 91%.

@@         Coverage Diff         @@
##           main   #206   +/-   ##
===================================
  Coverage    70%    71%           
===================================
  Files        87     87           
  Lines      5119   5176   +57     
  Branches   1062   1069    +7     
===================================
+ Hits       3630   3694   +64     
+ Misses     1279   1273    -6     
+ Partials    210    209    -1     
Flag Coverage 螖
unittests 71% <91%> (+<1%) 猬嗭笍

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage 螖
src/ImageSharp.Drawing/Shapes/Text/GlyphBuilder.cs 100% <酶> (酶)
...ssing/Processors/Text/DrawTextProcessor{TPixel}.cs 97% <50%> (酶)
src/ImageSharp.Drawing/Shapes/PathBuilder.cs 89% <81%> (+<1%) 猬嗭笍
...ImageSharp.Drawing/Shapes/Text/BaseGlyphBuilder.cs 94% <90%> (+4%) 猬嗭笍
src/ImageSharp.Drawing/Shapes/ArcLineSegment.cs 94% <94%> (酶)
...mageSharp.Drawing/Shapes/CubicBezierLineSegment.cs 92% <100%> (+4%) 猬嗭笍
src/ImageSharp.Drawing/Shapes/Clipper/clipper.cs 50% <0%> (-1%) 猬囷笍
src/ImageSharp.Drawing/Shapes/LinearLineSegment.cs 100% <0%> (+5%) 猬嗭笍

Continue to review full report at Codecov.

Legend - Click here to learn more
螖 = absolute <relative> (impact), 酶 = not affected, ? = missing data
Powered by Codecov. Last update 1a8dc88...4148163. Read the comment docs.

/// <summary>
/// Allow you to derivatively draw shapes and paths.
/// </summary>
public class PathDrawer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anyway we can simplify things by combining these two types? It seems, to me, that the overlap is confusing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially I had assumed it wouldn't work as a single class but it seems I was wrong, I've merged the ***To() APIs into the PathBuilder itself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great news!!

@tocsoft
Copy link
Member Author

tocsoft commented Mar 2, 2022

Currently missing the ArcTo function (but i'll add it soon) it should then have all the required features for svg path parsing which i have a 2nd branch where i'm adding that.

/// <param name="point">The point.</param>
/// <returns>The <see cref="PathBuilder"/></returns>
public PathBuilder QuadraticBezierTo(Vector2 secondControlPoint, Vector2 point)
=> this.AddBezier(this.currentPoint, secondControlPoint, point);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether the two AddBezier methods should be renamed? AddQuadraticBezier AddCubicBezier

/// <param name="point">The point.</param>
/// <returns>The <see cref="PathBuilder"/></returns>
public PathBuilder QuadraticBezierTo(Vector2 secondControlPoint, Vector2 point)
=> this.AddBezier(this.currentPoint, secondControlPoint, point);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether the two AddBezier methods should be renamed? AddQuadraticBezier AddCubicBezier

@JimBobSquarePants
Copy link
Member

@tocsoft How should ArcTo work? I might have a crack at implementing it as I want to get this and the SVG parsing PR done so I can incorporate it into the testing for #178 (I'm actually happy with the output for that PR, I just want extra comparisons against known SVG examples)

I wanna get the improvements to path text drawing in before #211 so we can have the same rich text functionality in both scenarios.

@JimBobSquarePants
Copy link
Member

Ah.... I see you already worked out ArcTo

d3ae3c0#diff-ef4d23a8c344c2392f8ac64a5b6bca8d1a8d3fb3eca4d8fb7ed17a28b346bfbdR229

Shall I clean that up and copy it across?

@tocsoft
Copy link
Member Author

tocsoft commented Apr 6, 2022

please do... I had forgotten I had gotten that far with it... I think the code still need validating as right. Also it was in need of optimising it looks to me like there should be some quick Vector2 wins possible in there.

@JimBobSquarePants
Copy link
Member

Cool. Will have a look tonight

@JimBobSquarePants
Copy link
Member

I've made some progress using this as an additional reference.

https://github.com/google/skia/blob/1f193df9b393d50da39570dab77a0bb5d28ec8ef/src/core/SkPathBuilder.cpp#L437-L505

SkMatrix is whack! What a horrible API!

@JimBobSquarePants
Copy link
Member

I've almost got this working.

I had to almost completely refactor your implementation as It was giving me NANs for any input. I based mine on the reference above https://github.com/google/skia/blob/1f193df9b393d50da39570dab77a0bb5d28ec8ef/src/core/SkPathBuilder.cpp#L437-L505

I'm confident about the radius and sweep and calculations as the basic example I've added to the unit tests works well however when I mix radii things start to go wrong. I'm fairly certain it's to do with the startAngle parameter I'm passing.

I've been using the following SkiaSharp code as a reference.

var info = new SKImageInfo(300, 300);
using (var surface = SKSurface.Create(info))
{
	SKCanvas canvas = surface.Canvas;

	canvas.Clear(SKColors.White);
	using (SKPath path = new SKPath())
	using (SKPaint fillPaint = new SKPaint())
	{
		fillPaint.Color = SKColors.Black;
		path.MoveTo(new(50, 50));
		//path.ArcTo(20, 20, -72, SKPathArcSize.Large, SKPathDirection.CounterClockwise, 200, 200);
		path.ArcTo(20, 50, -72, SKPathArcSize.Small, SKPathDirection.Clockwise, 200, 200);
		canvas.DrawPath(path, fillPaint);
		canvas.Save();
	}

	using FileStream fs = File.Create(@"C:\development\arc2.png");
	surface.Snapshot().Encode(SKEncodedImageFormat.Png, 100).SaveTo(fs);
}

I also have an SVG

<svg height="300" width="300" xmlns="http://www.w3.org/2000/svg">
    <path d="M 50 50 A 20 50 -72 0 1 200 2000" stroke="black" stroke-width="1" fill="black" />
</svg>

I don't have the geometry chops to figure out this last part I'm afraid. 馃様

@JimBobSquarePants
Copy link
Member

@tocsoft I've made progress!

There's something wrong with the point generation code in EllipticalArcLineSegment. I've hacked together a solution to the segment adding code from SVG.Sharpie which works perfectly. Need to compare and fix our original implementation but will definitely need some help.

Black on the left represents our working solution, red the solution derived from EllipticalArcLineSegment. Skia is on the right which matches the SVG output.

image

@JimBobSquarePants
Copy link
Member

JimBobSquarePants commented Apr 12, 2022

Hey @tocsoft

Got this all working now and also fixed a heap of issues with the old ArcLineSegment (it was using non-standard origin and rotation). It uses CubicBezierLineSegment underneath to generate the actual points now so generates about 10% of what it did previously.

I renamed a few things in PathBuilder for consistency that I highlighted earlier also.

I think it's ready to review. I'm sure there's some stuff that could be using System.Numerics but I didn't want to attempt that.

Here's some examples of the output. (These are also in the tests)

FillPathArcToAlternates
FillPathCanvasArcs
FillPathSVGArcs

@JimBobSquarePants JimBobSquarePants marked this pull request as ready for review April 12, 2022 15:33
@JimBobSquarePants JimBobSquarePants added this to the 1.0.0-rc.1 milestone Apr 12, 2022
@tocsoft
Copy link
Member Author

tocsoft commented Apr 12, 2022

Looking good, only thing I can see is the left over class.

I can't actually approve the PR cause I initially, created but apart from the class I am happy with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants