mirror of https://github.com/SixLabors/ImageSharp
8 changed files with 539 additions and 8 deletions
@ -0,0 +1,132 @@ |
|||
// <copyright file="Draw_Rectangle.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using Drawing; |
|||
using Drawing.Brushes; |
|||
using Drawing.Paths; |
|||
using Drawing.Pens; |
|||
using Drawing.Processors; |
|||
using Drawing.Shapes; |
|||
using Processors; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Draws the outline of the polygon with the provided pen.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="pen">The pen.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <param name="options">The options.</param>
|
|||
/// <returns>
|
|||
/// The Image
|
|||
/// </returns>
|
|||
public static Image<TColor, TPacked> DrawPolygon<TColor, TPacked>(this Image<TColor, TPacked> source, IPen<TColor, TPacked> pen, RectangleF shape, GraphicsOptions options) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.Process(new DrawPathProcessor<TColor, TPacked>(pen, (IPath)new RectangularPolygon(shape), options)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Draws the outline of the polygon with the provided pen.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="pen">The pen.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <returns>The Image</returns>
|
|||
public static Image<TColor, TPacked> DrawPolygon<TColor, TPacked>(this Image<TColor, TPacked> source, IPen<TColor, TPacked> pen, RectangleF shape) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.DrawPolygon(pen, shape, GraphicsOptions.Default); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Draws the outline of the polygon with the provided brush at the provided thickness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="brush">The brush.</param>
|
|||
/// <param name="thickness">The thickness.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <param name="options">The options.</param>
|
|||
/// <returns>
|
|||
/// The Image
|
|||
/// </returns>
|
|||
public static Image<TColor, TPacked> DrawPolygon<TColor, TPacked>(this Image<TColor, TPacked> source, IBrush<TColor, TPacked> brush, float thickness, RectangleF shape, GraphicsOptions options) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.DrawPolygon(new Pen<TColor, TPacked>(brush, thickness), shape, options); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Draws the outline of the polygon with the provided brush at the provided thickness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="brush">The brush.</param>
|
|||
/// <param name="thickness">The thickness.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <returns>The Image</returns>
|
|||
public static Image<TColor, TPacked> DrawPolygon<TColor, TPacked>(this Image<TColor, TPacked> source, IBrush<TColor, TPacked> brush, float thickness, RectangleF shape) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.DrawPolygon(new Pen<TColor, TPacked>(brush, thickness), shape); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Draws the outline of the polygon with the provided brush at the provided thickness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="color">The color.</param>
|
|||
/// <param name="thickness">The thickness.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <param name="options">The options.</param>
|
|||
/// <returns>
|
|||
/// The Image
|
|||
/// </returns>
|
|||
public static Image<TColor, TPacked> DrawPolygon<TColor, TPacked>(this Image<TColor, TPacked> source, TColor color, float thickness, RectangleF shape, GraphicsOptions options) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.DrawPolygon(new SolidBrush<TColor, TPacked>(color), thickness, shape, options); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Draws the outline of the polygon with the provided brush at the provided thickness.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="color">The color.</param>
|
|||
/// <param name="thickness">The thickness.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <returns>The Image</returns>
|
|||
public static Image<TColor, TPacked> DrawPolygon<TColor, TPacked>(this Image<TColor, TPacked> source, TColor color, float thickness, RectangleF shape) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.DrawPolygon(new SolidBrush<TColor, TPacked>(color), thickness, shape); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
// <copyright file="Fill_Rectangle.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using Drawing; |
|||
using Drawing.Brushes; |
|||
using Drawing.Paths; |
|||
using Drawing.Processors; |
|||
using Drawing.Shapes; |
|||
using Processors; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Image{TColor, TPacked}"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Flood fills the image in the shape o fhte provided polygon with the specified brush..
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="brush">The brush.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <param name="options">The options.</param>
|
|||
/// <returns>
|
|||
/// The Image
|
|||
/// </returns>
|
|||
public static Image<TColor, TPacked> Fill<TColor, TPacked>(this Image<TColor, TPacked> source, IBrush<TColor, TPacked> brush, RectangleF shape, GraphicsOptions options) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.Process(new FillShapeProcessor<TColor, TPacked>(brush, new RectangularPolygon(shape), options)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Flood fills the image in the shape o fhte provided polygon with the specified brush..
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="brush">The brush.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <returns>The Image</returns>
|
|||
public static Image<TColor, TPacked> Fill<TColor, TPacked>(this Image<TColor, TPacked> source, IBrush<TColor, TPacked> brush, RectangleF shape) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.Process(new FillShapeProcessor<TColor, TPacked>(brush, new RectangularPolygon(shape), GraphicsOptions.Default)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Flood fills the image in the shape o fhte provided polygon with the specified brush..
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="color">The color.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <param name="options">The options.</param>
|
|||
/// <returns>
|
|||
/// The Image
|
|||
/// </returns>
|
|||
public static Image<TColor, TPacked> Fill<TColor, TPacked>(this Image<TColor, TPacked> source, TColor color, RectangleF shape, GraphicsOptions options) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.Fill(new SolidBrush<TColor, TPacked>(color), shape, options); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Flood fills the image in the shape o fhte provided polygon with the specified brush..
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The type of the color.</typeparam>
|
|||
/// <typeparam name="TPacked">The type of the packed.</typeparam>
|
|||
/// <param name="source">The source.</param>
|
|||
/// <param name="color">The color.</param>
|
|||
/// <param name="shape">The shape.</param>
|
|||
/// <returns>The Image</returns>
|
|||
public static Image<TColor, TPacked> Fill<TColor, TPacked>(this Image<TColor, TPacked> source, TColor color, RectangleF shape) |
|||
where TColor : struct, IPackedPixel<TPacked> |
|||
where TPacked : struct, IEquatable<TPacked> |
|||
{ |
|||
return source.Fill(new SolidBrush<TColor, TPacked>(color), shape); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,237 @@ |
|||
// <copyright file="RectangularPolygon.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Drawing.Shapes |
|||
{ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Numerics; |
|||
using System.Threading.Tasks; |
|||
using Paths; |
|||
|
|||
/// <summary>
|
|||
/// A way of optermising drawing rectangles.
|
|||
/// </summary>
|
|||
/// <seealso cref="ImageSharp.Drawing.Shapes.IShape" />
|
|||
public class RectangularPolygon : IShape, IPath |
|||
{ |
|||
private readonly RectangleF rectangle; |
|||
private readonly Vector2 topLeft; |
|||
private readonly Vector2 bottomRight; |
|||
private readonly Vector2[] points; |
|||
private readonly IEnumerable<IPath> pathCollection; |
|||
private readonly float halfLength; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RectangularPolygon"/> class.
|
|||
/// </summary>
|
|||
/// <param name="rect">The rect.</param>
|
|||
public RectangularPolygon(ImageSharp.Rectangle rect) |
|||
: this((RectangleF)rect) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RectangularPolygon"/> class.
|
|||
/// </summary>
|
|||
/// <param name="rect">The rect.</param>
|
|||
public RectangularPolygon(ImageSharp.RectangleF rect) |
|||
{ |
|||
this.rectangle = rect; |
|||
this.points = new Vector2[4] |
|||
{ |
|||
this.topLeft = new Vector2(rect.Left, rect.Top), |
|||
new Vector2(rect.Right, rect.Top), |
|||
this.bottomRight = new Vector2(rect.Right, rect.Bottom), |
|||
new Vector2(rect.Left, rect.Bottom) |
|||
}; |
|||
|
|||
this.halfLength = this.rectangle.Width + this.rectangle.Height; |
|||
this.Length = this.halfLength * 2; |
|||
this.pathCollection = new[] { this }; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the bounding box of this shape.
|
|||
/// </summary>
|
|||
/// <value>
|
|||
/// The bounds.
|
|||
/// </value>
|
|||
public RectangleF Bounds => this.rectangle; |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this instance is closed.
|
|||
/// </summary>
|
|||
/// <value>
|
|||
/// <c>true</c> if this instance is closed; otherwise, <c>false</c>.
|
|||
/// </value>
|
|||
public bool IsClosed => true; |
|||
|
|||
/// <summary>
|
|||
/// Gets the length of the path
|
|||
/// </summary>
|
|||
/// <value>
|
|||
/// The length.
|
|||
/// </value>
|
|||
public float Length { get; } |
|||
|
|||
/// <summary>
|
|||
/// Calculates the distance along and away from the path for a specified point.
|
|||
/// </summary>
|
|||
/// <param name="point">The point along the path.</param>
|
|||
/// <returns>
|
|||
/// Returns details about the point and its distance away from the path.
|
|||
/// </returns>
|
|||
PointInfo IPath.Distance(Vector2 point) |
|||
{ |
|||
bool inside; // dont care about inside/outside for paths just distance
|
|||
return this.Distance(point, false, out inside); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds
|
|||
/// </summary>
|
|||
/// <param name="point">The point.</param>
|
|||
/// <returns>
|
|||
/// Returns the distance from the shape to the point
|
|||
/// </returns>
|
|||
public float Distance(Vector2 point) |
|||
{ |
|||
bool insidePoly; |
|||
var result = this.Distance(point, true, out insidePoly); |
|||
|
|||
// invert the distance from path when inside
|
|||
return insidePoly ? -result.DistanceFromPath : result.DistanceFromPath; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an enumerator that iterates through the collection.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// An enumerator that can be used to iterate through the collection.
|
|||
/// </returns>
|
|||
public IEnumerator<IPath> GetEnumerator() |
|||
{ |
|||
return this.pathCollection.GetEnumerator(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an enumerator that iterates through a collection.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
|
|||
/// </returns>
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return this.pathCollection.GetEnumerator(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts the <see cref="ILineSegment" /> into a simple linear path..
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// Returns the current <see cref="ILineSegment" /> as simple linear path.
|
|||
/// </returns>
|
|||
public Vector2[] AsSimpleLinearPath() |
|||
{ |
|||
return this.points; |
|||
} |
|||
|
|||
private PointInfo Distance(Vector2 point, bool getDistanceAwayOnly, out bool isInside) |
|||
{ |
|||
// point in rectangle
|
|||
// if after its clamped by the extreams its still the same then it must be inside :)
|
|||
Vector2 clamped = Vector2.Clamp(point, this.topLeft, this.bottomRight); |
|||
isInside = clamped == point; |
|||
|
|||
float distanceFromEdge = float.MaxValue; |
|||
float distanceAlongEdge = 0f; |
|||
|
|||
if (isInside) |
|||
{ |
|||
// get the absolute distances from the extreams
|
|||
Vector2 topLeftDist = Vector2.Abs(point - this.topLeft); |
|||
Vector2 bottomRightDist = Vector2.Abs(point - this.bottomRight); |
|||
|
|||
// get the min components
|
|||
Vector2 minDists = Vector2.Min(topLeftDist, bottomRightDist); |
|||
|
|||
// and then the single smallest (dont have to worry about direction)
|
|||
distanceFromEdge = Math.Min(minDists.X, minDists.Y); |
|||
|
|||
if (!getDistanceAwayOnly) |
|||
{ |
|||
// we need to make clamped the closest point
|
|||
if (this.topLeft.X + distanceFromEdge == point.X) |
|||
{ |
|||
// closer to lhf
|
|||
clamped.X = this.topLeft.X; // y is already the same
|
|||
|
|||
// distance along edge is length minus the amout down we are from the top of the rect
|
|||
distanceAlongEdge = this.Length - (clamped.Y - this.topLeft.Y); |
|||
} |
|||
else if (this.topLeft.Y + distanceFromEdge == point.Y) |
|||
{ |
|||
// closer to top
|
|||
clamped.Y = this.topLeft.Y; // x is already the same
|
|||
|
|||
distanceAlongEdge = clamped.X - this.topLeft.X; |
|||
} |
|||
else if (this.bottomRight.Y - distanceFromEdge == point.Y) |
|||
{ |
|||
// closer to bottom
|
|||
clamped.Y = this.bottomRight.Y; // x is already the same
|
|||
|
|||
distanceAlongEdge = (this.bottomRight.X - clamped.X) + this.halfLength; |
|||
} |
|||
else if (this.bottomRight.X - distanceFromEdge == point.X) |
|||
{ |
|||
// closer to rhs
|
|||
clamped.X = this.bottomRight.X; // x is already the same
|
|||
|
|||
distanceAlongEdge = (this.bottomRight.Y - clamped.Y) + this.rectangle.Width; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// clamped is the point on the path thats closest no matter what
|
|||
distanceFromEdge = (clamped - point).Length(); |
|||
|
|||
if (!getDistanceAwayOnly) |
|||
{ |
|||
// we need to figure out whats the cloests edge now and thus what distance/poitn is closest
|
|||
if (this.topLeft.X == clamped.X) |
|||
{ |
|||
// distance along edge is length minus the amout down we are from the top of the rect
|
|||
distanceAlongEdge = this.Length - (clamped.Y - this.topLeft.Y); |
|||
} |
|||
else if (this.topLeft.Y == clamped.Y) |
|||
{ |
|||
distanceAlongEdge = clamped.X - this.topLeft.X; |
|||
} |
|||
else if (this.bottomRight.Y == clamped.Y) |
|||
{ |
|||
distanceAlongEdge = (this.bottomRight.X - clamped.X) + this.halfLength; |
|||
} |
|||
else if (this.bottomRight.X == clamped.X) |
|||
{ |
|||
distanceAlongEdge = (this.bottomRight.Y - clamped.Y) + this.rectangle.Width; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return new PointInfo |
|||
{ |
|||
SearchPoint = point, |
|||
DistanceFromPath = distanceFromEdge, |
|||
ClosestPointOnPath = clamped, |
|||
DistanceAlongPath = distanceAlongEdge |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,71 @@ |
|||
// <copyright file="Crop.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Benchmarks |
|||
{ |
|||
using System.Drawing; |
|||
using System.Drawing.Drawing2D; |
|||
|
|||
using BenchmarkDotNet.Attributes; |
|||
using CoreImage = ImageSharp.Image; |
|||
using CoreRectangle = ImageSharp.Rectangle; |
|||
using CoreColor = ImageSharp.Color; |
|||
using System.IO; |
|||
using System.Numerics; |
|||
|
|||
public class FillRectangle |
|||
{ |
|||
[Benchmark(Baseline = true, Description = "System.Drawing Fill Rectangle")] |
|||
public void FillRectangleSystemDrawing() |
|||
{ |
|||
using (Bitmap destination = new Bitmap(800, 800)) |
|||
{ |
|||
|
|||
using (Graphics graphics = Graphics.FromImage(destination)) |
|||
{ |
|||
graphics.InterpolationMode = InterpolationMode.Default; |
|||
graphics.SmoothingMode = SmoothingMode.AntiAlias; |
|||
var pen = new Pen(Color.HotPink, 10); |
|||
graphics.FillRectangle(Brushes.HotPink, new Rectangle(10, 10, 190, 140)); |
|||
} |
|||
|
|||
using (MemoryStream ms = new MemoryStream()) |
|||
{ |
|||
destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); |
|||
} |
|||
} |
|||
} |
|||
|
|||
[Benchmark(Description = "ImageSharp Fill Rectangle")] |
|||
public void FillRactangleCore() |
|||
{ |
|||
CoreImage image = new CoreImage(800, 800); |
|||
|
|||
image.Fill(CoreColor.HotPink, new ImageSharp.Drawing.Shapes.RectangularPolygon(new CoreRectangle(10, 10, 190, 140))); |
|||
|
|||
using (MemoryStream ms = new MemoryStream()) |
|||
{ |
|||
image.SaveAsBmp(ms); |
|||
} |
|||
} |
|||
|
|||
[Benchmark(Description = "ImageSharp Fill Rectangle - As Polygon")] |
|||
public void FillPolygonCore() |
|||
{ |
|||
CoreImage image = new CoreImage(800, 800); |
|||
|
|||
image.FillPolygon(CoreColor.HotPink, new[] { |
|||
new Vector2(10, 10), |
|||
new Vector2(200, 10), |
|||
new Vector2(200, 150), |
|||
new Vector2(10, 150) }); |
|||
|
|||
using (MemoryStream ms = new MemoryStream()) |
|||
{ |
|||
image.SaveAsBmp(ms); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue