Add RoundedRectanglePolygon and PathBuilder helpers. by JimBobSquarePants · Pull Request #390 · SixLabors/ImageSharp.Drawing · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
24 changes: 12 additions & 12 deletions samples/DrawShapesWithImageSharp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private static void DrawPosterComposition()

// The lake is a plain rectangle filled with a vertical LinearGradientBrush. Building it
// with PathBuilder keeps the construction style identical to the surrounding shapes
// even though a RectangularPolygon would also work for an axis-aligned rectangle.
// even though a RectanglePolygon would also work for an axis-aligned rectangle.
PathBuilder lakeShape = new();
lakeShape.AddLines(
new PointF(0, 432),
Expand Down Expand Up @@ -175,7 +175,7 @@ private static void DrawPosterComposition()
// Save pushes a clipping state; Restore pops it. Anything drawn between the two is
// confined to lakeHighlight even though the brush spans its full bounding rectangle.
canvas.Save(lakeHighlightClipOptions, lakeHighlight);
canvas.Fill(Brushes.ForwardDiagonal(Color.White.WithAlpha(.36F), Color.Transparent), new RectangularPolygon(lakeHighlightBounds));
canvas.Fill(Brushes.ForwardDiagonal(Color.White.WithAlpha(.36F), Color.Transparent), new RectanglePolygon(lakeHighlightBounds));
canvas.Restore();

// Title panel: pushing posterPanelOptions onto the canvas with Save activates a
Expand Down Expand Up @@ -249,7 +249,7 @@ private static void DrawPosterComposition()

canvas.Save(posterPanelOptions);
canvas.SaveLayer(new GraphicsOptions { BlendPercentage = .94F }, posterPanelLayerBounds);
canvas.Fill(Brushes.Solid(Color.White.WithAlpha(.86F)), new RectangularPolygon(posterPanelBounds));
canvas.Fill(Brushes.Solid(Color.White.WithAlpha(.86F)), new RectanglePolygon(posterPanelBounds));
canvas.DrawText(posterTextOptions, posterText, Brushes.Solid(Color.DarkSlateGray), pen: null);
canvas.Restore();
canvas.Restore();
Expand Down Expand Up @@ -296,8 +296,8 @@ private static void DrawTransitMap()
pen: null);

// Legend panel: reuse the route pens so the key is drawn with the same stroke options as the map.
canvas.Fill(Brushes.Solid(Color.White.WithAlpha(.9F)), new RectangularPolygon(680, 46, 220, 126));
canvas.Draw(Pens.Solid(Color.LightSlateGray, 2), new RectangularPolygon(680, 46, 220, 126));
canvas.Fill(Brushes.Solid(Color.White.WithAlpha(.9F)), new RectanglePolygon(680, 46, 220, 126));
canvas.Draw(Pens.Solid(Color.LightSlateGray, 2), new RectanglePolygon(680, 46, 220, 126));
canvas.DrawLine(harborLinePen, new PointF(708, 78), new PointF(768, 78));
canvas.DrawLine(gardenLoopPen, new PointF(708, 112), new PointF(768, 112));
canvas.DrawLine(airportLinePen, new PointF(708, 146), new PointF(768, 146));
Expand Down Expand Up @@ -627,7 +627,7 @@ private static void DrawTypographySheet()
// options the draw call uses, otherwise WrappingLength, LineSpacing, or font fallback
// can change where the lines break and the box drifts off the text.
FontRectangle measuredBox = TextMeasurer.MeasureRenderableBounds(measuredText, measuredOptions);
RectangularPolygon measuredBackground = new(
RectanglePolygon measuredBackground = new(
measuredBox.X - 10,
measuredBox.Y - 8,
measuredBox.Width + 20,
Expand Down Expand Up @@ -852,9 +852,9 @@ static void DrawPanel(
Brush titleBrush,
Pen rulePen)
{
RectangularPolygon panel = new(origin.X, origin.Y, width, height);
RectanglePolygon panel = new(origin.X, origin.Y, width, height);

// RectangularPolygon implements IPath. The same shape can be both filled (with a
// RectanglePolygon implements IPath. The same shape can be both filled (with a
// semi-transparent brush) and stroked (with a pen), which keeps the panel framing
// consistent across the sheet without re-allocating geometry.
canvas.Fill(Brushes.Solid(Color.White.WithAlpha(.54F)), panel);
Expand Down Expand Up @@ -947,7 +947,7 @@ static void DrawBeforeAfterWipePanel(
// involved. A simple right-half rectangle is the entire mask, so OilPaint runs only
// on those pixels and the left half stays as the original photograph.
float midX = imageArea.X + (imageArea.Width / 2F);
RectangularPolygon afterRegion = new(
RectanglePolygon afterRegion = new(
midX,
imageArea.Y,
imageArea.Width / 2F,
Expand Down Expand Up @@ -1019,7 +1019,7 @@ static void DrawImageBrushPanel(
imageArea.Y + (imageArea.Height / 2F));
float outerRadius = (MathF.Min(imageArea.Width, imageArea.Height) / 2F) - 6F;
float innerRadius = outerRadius * 0.5F;
Star star = new(starCenter.X, starCenter.Y, 5, innerRadius, outerRadius);
StarPolygon star = new(starCenter.X, starCenter.Y, 5, innerRadius, outerRadius);

// ImageBrush samples the source image in world coordinates: a destination pixel at
// (x, y) reads source pixel (x - offset.X, y - offset.Y) inside SourceRegion. The
Expand Down Expand Up @@ -1080,7 +1080,7 @@ static void DrawPhotoInTextPanel(
ShapeOptions = new ShapeOptions { BooleanOperation = BooleanOperation.Intersection },
};

canvas.Fill(Brushes.Solid(Color.ParseHex("#E2DCC2")), new RectangularPolygon(imageArea));
canvas.Fill(Brushes.Solid(Color.ParseHex("#E2DCC2")), new RectanglePolygon(imageArea));
canvas.Save(clipToGlyphs, glyphClips);
canvas.DrawImage(source, source.Bounds, imageArea, null);
canvas.Restore();
Expand Down Expand Up @@ -1109,7 +1109,7 @@ static float DrawPanelChrome(
Color titleColor,
Color captionColor)
{
RectangularPolygon panelShape = new(panel);
RectanglePolygon panelShape = new(panel);
canvas.Fill(Brushes.Solid(Color.White), panelShape);
canvas.Draw(Pens.Solid(Color.ParseHex("#D7D2C0"), 1), panelShape);

Expand Down
2 changes: 1 addition & 1 deletion samples/DrawShapesWithImageSharp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Image-compositing scene demonstrating four ways a photograph (`tests/Images/Inpu

- **Before / after wipe** — `canvas.Apply(rightHalfRect, ctx => ctx.OilPaint(15, 5))` scopes an `OilPaint` processor to the right half of the photograph.
- **Privacy redaction** — `canvas.Apply(ellipse, ctx => ctx.Pixelate(10))` pixelates an elliptical face-shaped region and leaves the rest untouched.
- **Image as a brush** — `new ImageBrush<Rgba32>(source, source.Bounds, brushOffset)` wraps the photograph as a `Brush` so a `Star` path can be filled with it as a texture; the brush offset aligns the mountain in the photograph with the star's centre.
- **Image as a brush** — `new ImageBrush<Rgba32>(source, source.Bounds, brushOffset)` wraps the photograph as a `Brush` so a `StarPolygon` path can be filled with it as a texture; the brush offset aligns the mountain in the photograph with the star's centre.
- **Photo in text** — `TextBuilder.GeneratePaths("MASK", ...)` produces one `IPath` per glyph; `canvas.Save(intersectionOptions, glyphPaths)` uses them as a compound clip so `DrawImage` only renders inside the letterforms.

## Running
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public override void Paint(DrawingCanvas canvas, TimeSpan deltaTime)
canvas.Apply(edgeRegion, ctx => ctx.DetectEdges());
canvas.Apply(blurRegion, ctx => ctx.GaussianBlur(Math.Max(3F, Math.Min(viewportSize.Width, viewportSize.Height) / 120F)));

canvas.Draw(Pens.Solid(OutlineColor, 3), new RectangularPolygon(edgeRegion));
canvas.Draw(Pens.Solid(OutlineColor, 3), new RectanglePolygon(edgeRegion));
canvas.Draw(Pens.Solid(OutlineColor, 3), blurRegion);
}

Expand Down
14 changes: 7 additions & 7 deletions samples/WebGPUExternalSurfaceDemo/Scenes/ManualTextFlowScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ public override void Paint(DrawingCanvas canvas, TimeSpan deltaTime)
this.cachedObstacleShape = this.obstacleShape;
}

canvas.Fill(PageBrush, new RectangularPolygon(pageLeft, pageTop, pageRight - pageLeft, pageBottom - pageTop));
canvas.Draw(PageOutlinePen, new RectangularPolygon(pageLeft, pageTop, pageRight - pageLeft, pageBottom - pageTop));
canvas.Fill(PageBrush, new RectanglePolygon(pageLeft, pageTop, pageRight - pageLeft, pageBottom - pageTop));
canvas.Draw(PageOutlinePen, new RectanglePolygon(pageLeft, pageTop, pageRight - pageLeft, pageBottom - pageTop));
canvas.Fill(ObstacleBrush, obstaclePath);
canvas.Draw(ObstacleOutlinePen, obstaclePath);

Expand Down Expand Up @@ -238,7 +238,7 @@ public override void Paint(DrawingCanvas canvas, TimeSpan deltaTime)
// The translucent slot fill is a visual aid for the sample. It
// makes the row splitting visible so readers can compare the
// available rectangles with the selected obstacle shape.
canvas.Fill(SlotBrush, new RectangularPolygon(slot.Left, y, slotWidth, lineHeight));
canvas.Fill(SlotBrush, new RectanglePolygon(slot.Left, y, slotWidth, lineHeight));
canvas.DrawText(line, new PointF(slot.Left, y), TextBrush, pen: null);

rowHeight = MathF.Max(rowHeight, lineHeight);
Expand Down Expand Up @@ -274,14 +274,14 @@ private IPath CreateObstaclePath(PointF center, float size)
// circle or rectangle math.
return this.ObstacleShape switch
{
ManualTextFlowObstacleShape.Rectangle => new RectangularPolygon(
ManualTextFlowObstacleShape.Rectangle => new RectanglePolygon(
center.X - radius,
center.Y - radius,
size,
size),
ManualTextFlowObstacleShape.Triangle => new RegularPolygon(center, 3, radius, 180F),
ManualTextFlowObstacleShape.Diamond => new RegularPolygon(center, 4, radius, 0F),
ManualTextFlowObstacleShape.Star => new Star(center, 5, radius * .45F, radius, -18F),
ManualTextFlowObstacleShape.Star => new StarPolygon(center, 5, radius * .45F, radius, -18F),
_ => new EllipsePolygon(center, new SizeF(size, size))
};
}
Expand Down Expand Up @@ -583,7 +583,7 @@ internal enum ManualTextFlowObstacleShape
Circle,

/// <summary>
/// A rectangular obstacle backed by <see cref="RectangularPolygon"/>.
/// A rectangular obstacle backed by <see cref="RectanglePolygon"/>.
/// </summary>
Rectangle,

Expand All @@ -598,7 +598,7 @@ internal enum ManualTextFlowObstacleShape
Diamond,

/// <summary>
/// A concave star obstacle backed by <see cref="Star"/>.
/// A concave star obstacle backed by <see cref="StarPolygon"/>.
/// </summary>
Star
}
10 changes: 5 additions & 5 deletions samples/WebGPUExternalSurfaceDemo/Scenes/RichTextEditorScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,10 @@ public override void Paint(DrawingCanvas canvas, TimeSpan deltaTime)
}

canvas.Fill(BackgroundBrush, canvas.Bounds);
canvas.Fill(EditorBrush, new RectangularPolygon(editorBounds));
canvas.Draw(BorderPen, new RectangularPolygon(editorBounds));
canvas.Fill(EditorBrush, new RectanglePolygon(editorBounds));
canvas.Draw(BorderPen, new RectanglePolygon(editorBounds));

IPath editorClip = new RectangularPolygon(editorBounds);
IPath editorClip = new RectanglePolygon(editorBounds);

// Selection is painted before glyphs, matching normal editor behavior.
// The clipping scope applies only to text so the editor chrome remains crisp.
Expand Down Expand Up @@ -549,11 +549,11 @@ private void DrawSelection(DrawingCanvas canvas, TextMetrics metrics)
// That keeps mixed-bidi ranges visually split instead of filling across reordered gaps.
canvas.Fill(
SelectionBrush,
new RectangularPolygon(rectangle.X, rectangle.Y, width, height));
new RectanglePolygon(rectangle.X, rectangle.Y, width, height));

canvas.Draw(
SelectionBorderPen,
new RectangularPolygon(rectangle.X, rectangle.Y, width, height));
new RectanglePolygon(rectangle.X, rectangle.Y, width, height));
}
}

Expand Down
77 changes: 73 additions & 4 deletions src/ImageSharp.Drawing/PathBuilder.cs
Loading
Loading