Skip to content

Commit 8935070

Browse files
ProcessWithCanvas -> Paint
1 parent 390d2a4 commit 8935070

File tree

54 files changed

+284
-264
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+284
-264
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ SixLabors.ImageSharp.Drawing
1515
</div>
1616

1717
**ImageSharp.Drawing** is a cross-platform 2D drawing library built on top of [ImageSharp](https://github.com/SixLabors/ImageSharp). It provides path construction, polygon manipulation, fills, strokes, gradient brushes, pattern brushes, and text rendering. Built against [.NET 8](https://docs.microsoft.com/en-us/dotnet/standard/net-standard).
18+
19+
## Quick Start
20+
21+
```csharp
22+
image.Mutate(ctx => ctx.Paint(canvas =>
23+
{
24+
canvas.Fill(Brushes.Solid(Color.White));
25+
canvas.Fill(Brushes.Solid(Color.Red), new EllipsePolygon(200, 200, 100));
26+
canvas.Draw(Pens.Solid(Color.Blue, 3F), new RectangularPolygon(50, 50, 200, 100));
27+
}));
28+
```
1829

1930
## License
2031

samples/DrawShapesWithImageSharp/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ A sample application that demonstrates the core vector drawing capabilities of I
1010
- **Curves** — Ellipses via `EllipsePolygon` and cubic Bezier arcs via `CubicBezierLineSegment`.
1111
- **Text as paths** — Converting text to vector outlines using `TextBuilder.GeneratePaths()` with system fonts, including text laid out along a curved path.
1212
- **Serialized glyph data** — Rendering OpenSans letter shapes ('a' and 'o') from serialized coordinate data as `ComplexPolygon` instances.
13-
- **Canvas API**`Fill` for solid backgrounds and shape rendering via `ProcessWithCanvas`.
13+
- **Canvas API**`Fill` for solid backgrounds and shape rendering via `Paint`.
1414

1515
## Running
1616

src/ImageSharp.Drawing/Processing/DRAWING_CANVAS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ Before looking at the flow, it helps to define the major terms in the sense used
5959

6060
It is not the rasterizer. It is the object that makes the public drawing model coherent.
6161

62+
Most callers reach that model through `IImageProcessingContext.Paint(...)`, while lower-level code can
63+
also create a canvas directly with the `CreateCanvas(...)` extension methods.
64+
6265
### Batcher
6366

6467
`DrawingCanvasBatcher<TPixel>` is the deferred command queue. It stores pending `CompositionCommand` values, prepares them during flush, builds a `CompositionScene`, and calls `IDrawingBackend.FlushCompositions(...)`.
@@ -99,7 +102,8 @@ There are two backend-selection paths in the architecture:
99102
- the ordinary public `DrawingCanvas<TPixel>` constructors resolve the backend from `Configuration`
100103
- specialized infrastructure can construct a canvas with an explicit backend
101104

102-
The ordinary CPU entry points also include the `CreateCanvas(...)` extension methods on `Image<TPixel>` and `ImageFrame<TPixel>`, which route into those same constructors.
105+
The ordinary CPU entry points include `Paint(...)` on `IImageProcessingContext` and the `CreateCanvas(...)`
106+
extension methods on `Image<TPixel>` and `ImageFrame<TPixel>`, which route into those same constructors.
103107

104108
That explicit-backend path matters for the WebGPU helpers. `WebGPUWindow<TPixel>`, `WebGPURenderTarget<TPixel>`, and `WebGPUDeviceContext<TPixel>` create canvases that point directly at their owned `WebGPUDrawingBackend` instance instead of storing that backend on the caller's `Configuration`.
105109

src/ImageSharp.Drawing/Processing/IDrawingCanvas.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public interface IDrawingCanvas : IDisposable
4949
/// Saves the current drawing state and begins an isolated compositing layer.
5050
/// Subsequent draw commands are recorded into an isolated logical layer. When
5151
/// <see cref="Restore"/> closes the layer, that layer becomes eligible for
52-
/// composition during the next <see cref="Flush"/> or <see cref="System.IDisposable.Dispose"/>.
52+
/// composition during the next <see cref="Flush"/> or <see cref="IDisposable.Dispose"/>.
5353
/// </summary>
5454
/// <returns>The save count after the layer state has been pushed.</returns>
5555
public int SaveLayer();
@@ -58,7 +58,7 @@ public interface IDrawingCanvas : IDisposable
5858
/// Saves the current drawing state and begins an isolated compositing layer.
5959
/// Subsequent draw commands are recorded into an isolated logical layer. When
6060
/// <see cref="Restore"/> closes the layer, that layer is composed during the next
61-
/// <see cref="Flush"/> or <see cref="System.IDisposable.Dispose"/> using the specified
61+
/// <see cref="Flush"/> or <see cref="IDisposable.Dispose"/> using the specified
6262
/// <paramref name="layerOptions"/> (blend mode, alpha composition, opacity).
6363
/// </summary>
6464
/// <param name="layerOptions">
@@ -71,7 +71,7 @@ public interface IDrawingCanvas : IDisposable
7171
/// Saves the current drawing state and begins an isolated compositing layer
7272
/// bounded to a subregion. Subsequent draw commands are recorded into that isolated
7373
/// logical layer. When <see cref="Restore"/> closes the layer, it is composed during
74-
/// the next <see cref="Flush"/> or <see cref="System.IDisposable.Dispose"/> using the specified
74+
/// the next <see cref="Flush"/> or <see cref="IDisposable.Dispose"/> using the specified
7575
/// <paramref name="layerOptions"/>.
7676
/// </summary>
7777
/// <param name="layerOptions">
@@ -89,7 +89,7 @@ public interface IDrawingCanvas : IDisposable
8989
/// <remarks>
9090
/// If the most recently saved state was created by a <c>SaveLayer</c> overload,
9191
/// the layer is closed in the deferred scene. Actual composition happens during the
92-
/// next <see cref="Flush"/> or <see cref="System.IDisposable.Dispose"/>.
92+
/// next <see cref="Flush"/> or <see cref="IDisposable.Dispose"/>.
9393
/// </remarks>
9494
public void Restore();
9595

@@ -101,7 +101,7 @@ public interface IDrawingCanvas : IDisposable
101101
/// and the last discarded frame becomes the current state.
102102
/// If any discarded state was created by a <c>SaveLayer</c> overload,
103103
/// those layers are closed in the deferred scene and are composed during the next
104-
/// <see cref="Flush"/> or <see cref="System.IDisposable.Dispose"/>.
104+
/// <see cref="Flush"/> or <see cref="IDisposable.Dispose"/>.
105105
/// </remarks>
106106
/// <param name="saveCount">The save count to restore to.</param>
107107
public void RestoreTo(int saveCount);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
namespace SixLabors.ImageSharp.Drawing.Processing;
5+
6+
/// <summary>
7+
/// Represents the per-frame painting callback executed by <see cref="PaintExtensions.Paint(IImageProcessingContext, CanvasAction)"/>.
8+
/// </summary>
9+
/// <param name="canvas">The drawing canvas for the current image frame.</param>
10+
public delegate void CanvasAction(IDrawingCanvas canvas);
11+
12+
/// <summary>
13+
/// Adds image-processing extensions that paint each frame through <see cref="IDrawingCanvas"/>.
14+
/// </summary>
15+
public static class PaintExtensions
16+
{
17+
/// <summary>
18+
/// Paints each image frame using drawing options from the current context.
19+
/// </summary>
20+
/// <param name="source">The image processing context to paint.</param>
21+
/// <param name="action">The per-frame painting callback.</param>
22+
/// <returns>The <see cref="IImageProcessingContext"/> so additional processing operations can be chained.</returns>
23+
public static IImageProcessingContext Paint(
24+
this IImageProcessingContext source,
25+
CanvasAction action)
26+
=> source.Paint(source.GetDrawingOptions(), action);
27+
28+
/// <summary>
29+
/// Paints each image frame using the supplied drawing options.
30+
/// </summary>
31+
/// <param name="source">The image processing context to paint.</param>
32+
/// <param name="options">The drawing options applied when creating each frame canvas.</param>
33+
/// <param name="action">The per-frame painting callback.</param>
34+
/// <returns>The <see cref="IImageProcessingContext"/> so additional processing operations can be chained.</returns>
35+
public static IImageProcessingContext Paint(
36+
this IImageProcessingContext source,
37+
DrawingOptions options,
38+
CanvasAction action)
39+
{
40+
Guard.NotNull(options, nameof(options));
41+
Guard.NotNull(action, nameof(action));
42+
43+
return source.ApplyProcessor(new PaintProcessor(options, action));
44+
}
45+
}

src/ImageSharp.Drawing/Processing/ProcessWithCanvasProcessor.cs renamed to src/ImageSharp.Drawing/Processing/PaintProcessor.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66
namespace SixLabors.ImageSharp.Drawing.Processing;
77

88
/// <summary>
9-
/// Defines a processor that executes a canvas callback for each image frame.
9+
/// Defines the image processor used by <see cref="PaintExtensions.Paint(IImageProcessingContext, DrawingOptions, CanvasAction)"/>
10+
/// to execute a canvas callback for each image frame.
1011
/// </summary>
11-
public sealed class ProcessWithCanvasProcessor : IImageProcessor
12+
public sealed class PaintProcessor : IImageProcessor
1213
{
1314
/// <summary>
14-
/// Initializes a new instance of the <see cref="ProcessWithCanvasProcessor"/> class.
15+
/// Initializes a new instance of the <see cref="PaintProcessor"/> class.
1516
/// </summary>
16-
/// <param name="options">The drawing options.</param>
17-
/// <param name="action">The per-frame canvas callback.</param>
18-
public ProcessWithCanvasProcessor(DrawingOptions options, CanvasAction action)
17+
/// <param name="options">The drawing options used when creating each frame canvas.</param>
18+
/// <param name="action">The per-frame painting callback.</param>
19+
public PaintProcessor(DrawingOptions options, CanvasAction action)
1920
{
2021
Guard.NotNull(options, nameof(options));
2122
Guard.NotNull(action, nameof(action));
@@ -25,10 +26,13 @@ public ProcessWithCanvasProcessor(DrawingOptions options, CanvasAction action)
2526
}
2627

2728
/// <summary>
28-
/// Gets the drawing options.
29+
/// Gets the drawing options used when creating each frame canvas.
2930
/// </summary>
3031
public DrawingOptions Options { get; }
3132

33+
/// <summary>
34+
/// Gets the per-frame painting callback.
35+
/// </summary>
3236
internal CanvasAction Action { get; }
3337

3438
/// <inheritdoc />
@@ -37,5 +41,5 @@ public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(
3741
Image<TPixel> source,
3842
Rectangle sourceRectangle)
3943
where TPixel : unmanaged, IPixel<TPixel>
40-
=> new ProcessWithCanvasProcessor<TPixel>(configuration, this, source, sourceRectangle);
44+
=> new PaintProcessor<TPixel>(configuration, this, source, sourceRectangle);
4145
}

src/ImageSharp.Drawing/Processing/ProcessWithCanvasProcessor{TPixel}.cs renamed to src/ImageSharp.Drawing/Processing/PaintProcessor{TPixel}.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,26 @@
66
namespace SixLabors.ImageSharp.Drawing.Processing;
77

88
/// <summary>
9-
/// Executes a per-frame canvas callback for a specific pixel type.
9+
/// Executes the <see cref="PaintProcessor"/> callback for a specific pixel type by creating a
10+
/// <see cref="DrawingCanvas{TPixel}"/> over each frame.
1011
/// </summary>
1112
/// <typeparam name="TPixel">The pixel format.</typeparam>
12-
internal sealed class ProcessWithCanvasProcessor<TPixel> : ImageProcessor<TPixel>
13+
internal sealed class PaintProcessor<TPixel> : ImageProcessor<TPixel>
1314
where TPixel : unmanaged, IPixel<TPixel>
1415
{
15-
private readonly ProcessWithCanvasProcessor definition;
16+
private readonly PaintProcessor definition;
1617
private readonly CanvasAction action;
1718

1819
/// <summary>
19-
/// Initializes a new instance of the <see cref="ProcessWithCanvasProcessor{TPixel}"/> class.
20+
/// Initializes a new instance of the <see cref="PaintProcessor{TPixel}"/> class.
2021
/// </summary>
2122
/// <param name="configuration">The processing configuration.</param>
22-
/// <param name="definition">The processor definition.</param>
23+
/// <param name="definition">The non-generic processor definition that owns the drawing options and callback.</param>
2324
/// <param name="source">The source image.</param>
24-
/// <param name="sourceRectangle">The source bounds.</param>
25-
public ProcessWithCanvasProcessor(
25+
/// <param name="sourceRectangle">The source bounds passed through the processing pipeline.</param>
26+
public PaintProcessor(
2627
Configuration configuration,
27-
ProcessWithCanvasProcessor definition,
28+
PaintProcessor definition,
2829
Image<TPixel> source,
2930
Rectangle sourceRectangle)
3031
: base(configuration, source, sourceRectangle)

src/ImageSharp.Drawing/Processing/ProcessWithCanvasExtensions.cs

Lines changed: 0 additions & 45 deletions
This file was deleted.

tests/ImageSharp.Drawing.Benchmarks/Drawing/DrawBeziers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void DrawPathSystemDrawing()
3838
public void DrawLinesCore()
3939
{
4040
using Image<Rgba32> image = new(800, 800);
41-
image.Mutate(x => x.ProcessWithCanvas(canvas => canvas.DrawBezier(
41+
image.Mutate(x => x.Paint(canvas => canvas.DrawBezier(
4242
Processing.Pens.Solid(Color.HotPink, 10),
4343
new PointF(10, 500),
4444
new PointF(30, 10),

tests/ImageSharp.Drawing.Benchmarks/Drawing/DrawPolygon.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ public void SystemDrawing()
161161

162162
[Benchmark]
163163
public void ImageSharp()
164-
=> this.image.Mutate(c => c.ProcessWithCanvas(canvas => canvas.Draw(this.isPen, this.imageSharpPath)));
164+
=> this.image.Mutate(c => c.Paint(canvas => canvas.Draw(this.isPen, this.imageSharpPath)));
165165

166166
[Benchmark]
167167
public void ImageSharpWebGPU()

0 commit comments

Comments
 (0)