Browse Source

Pen, Brush & Processors refactored

af/merge-core
Anton Firszov 7 years ago
parent
commit
0e2c53e5ed
  1. 120
      src/ImageSharp.Drawing/Processing/Brushes.cs
  2. 44
      src/ImageSharp.Drawing/Processing/DrawBezierExtensions.cs
  3. 28
      src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs
  4. 11
      src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs
  5. 50
      src/ImageSharp.Drawing/Processing/Pens.cs
  6. 18
      src/ImageSharp.Drawing/Processing/Pen{TPixel}.cs
  7. 57
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs
  8. 63
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
  9. 55
      src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
  10. 29
      src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs
  11. 231
      src/ImageSharp/GraphicsOptions.cs

120
src/ImageSharp.Drawing/Processing/Brushes.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing
/// <summary> /// <summary>
/// A collection of methods for creating generic brushes. /// A collection of methods for creating generic brushes.
/// </summary> /// </summary>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> /// <returns>A New <see cref="PatternBrush"/></returns>
public static class Brushes public static class Brushes
{ {
/// <summary> /// <summary>
@ -94,163 +94,131 @@ namespace SixLabors.ImageSharp.Processing
/// Create as brush that will paint a solid color /// Create as brush that will paint a solid color
/// </summary> /// </summary>
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static SolidBrush Solid(Color color) => new SolidBrush(color);
public static SolidBrush<TPixel> Solid<TPixel>(TPixel color)
where TPixel : struct, IPixel<TPixel>
=> new SolidBrush<TPixel>(color);
/// <summary> /// <summary>
/// Create as brush that will paint a Percent10 Hatch Pattern with the specified colors /// Create as brush that will paint a Percent10 Hatch Pattern with the specified colors
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Percent10(Color foreColor) =>
public static PatternBrush<TPixel> Percent10<TPixel>(TPixel foreColor) new PatternBrush(foreColor, Color.Transparent, Percent10Pattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, Percent10Pattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Percent10 Hatch Pattern with the specified colors /// Create as brush that will paint a Percent10 Hatch Pattern with the specified colors
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param> /// <param name="backColor">Color of the background.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Percent10(Color foreColor, Color backColor) =>
public static PatternBrush<TPixel> Percent10<TPixel>(TPixel foreColor, TPixel backColor) new PatternBrush(foreColor, backColor, Percent10Pattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, Percent10Pattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Percent20 Hatch Pattern with the specified foreground color and a /// Create as brush that will paint a Percent20 Hatch Pattern with the specified foreground color and a
/// transparent background. /// transparent background.
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Percent20(Color foreColor) =>
public static PatternBrush<TPixel> Percent20<TPixel>(TPixel foreColor) new PatternBrush(foreColor, Color.Transparent, Percent20Pattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, Percent20Pattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Percent20 Hatch Pattern with the specified colors /// Create as brush that will paint a Percent20 Hatch Pattern with the specified colors
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param> /// <param name="backColor">Color of the background.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Percent20(Color foreColor, Color backColor) =>
public static PatternBrush<TPixel> Percent20<TPixel>(TPixel foreColor, TPixel backColor) new PatternBrush(foreColor, backColor, Percent20Pattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, Percent20Pattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Horizontal Hatch Pattern with the specified foreground color and a /// Create as brush that will paint a Horizontal Hatch Pattern with the specified foreground color and a
/// transparent background. /// transparent background.
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Horizontal(Color foreColor) =>
public static PatternBrush<TPixel> Horizontal<TPixel>(TPixel foreColor) new PatternBrush(foreColor, Color.Transparent, HorizontalPattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, HorizontalPattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Horizontal Hatch Pattern with the specified colors /// Create as brush that will paint a Horizontal Hatch Pattern with the specified colors
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param> /// <param name="backColor">Color of the background.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Horizontal(Color foreColor, Color backColor) =>
public static PatternBrush<TPixel> Horizontal<TPixel>(TPixel foreColor, TPixel backColor) new PatternBrush(foreColor, backColor, HorizontalPattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, HorizontalPattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Min Hatch Pattern with the specified foreground color and a /// Create as brush that will paint a Min Hatch Pattern with the specified foreground color and a
/// transparent background. /// transparent background.
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Min(Color foreColor) => new PatternBrush(foreColor, Color.Transparent, MinPattern);
public static PatternBrush<TPixel> Min<TPixel>(TPixel foreColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, MinPattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Min Hatch Pattern with the specified colors /// Create as brush that will paint a Min Hatch Pattern with the specified colors
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param> /// <param name="backColor">Color of the background.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Min(Color foreColor, Color backColor) =>
public static PatternBrush<TPixel> Min<TPixel>(TPixel foreColor, TPixel backColor) new PatternBrush(foreColor, backColor, MinPattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, MinPattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Vertical Hatch Pattern with the specified foreground color and a /// Create as brush that will paint a Vertical Hatch Pattern with the specified foreground color and a
/// transparent background. /// transparent background.
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Vertical(Color foreColor) =>
public static PatternBrush<TPixel> Vertical<TPixel>(TPixel foreColor) new PatternBrush(foreColor, Color.Transparent, VerticalPattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, VerticalPattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Vertical Hatch Pattern with the specified colors /// Create as brush that will paint a Vertical Hatch Pattern with the specified colors
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param> /// <param name="backColor">Color of the background.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush Vertical(Color foreColor, Color backColor) =>
public static PatternBrush<TPixel> Vertical<TPixel>(TPixel foreColor, TPixel backColor) new PatternBrush(foreColor, backColor, VerticalPattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, VerticalPattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Forward Diagonal Hatch Pattern with the specified foreground color and a /// Create as brush that will paint a Forward Diagonal Hatch Pattern with the specified foreground color and a
/// transparent background. /// transparent background.
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush ForwardDiagonal(Color foreColor) =>
public static PatternBrush<TPixel> ForwardDiagonal<TPixel>(TPixel foreColor) new PatternBrush(foreColor, Color.Transparent, ForwardDiagonalPattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, ForwardDiagonalPattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Forward Diagonal Hatch Pattern with the specified colors /// Create as brush that will paint a Forward Diagonal Hatch Pattern with the specified colors
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param> /// <param name="backColor">Color of the background.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush ForwardDiagonal(Color foreColor, Color backColor) =>
public static PatternBrush<TPixel> ForwardDiagonal<TPixel>(TPixel foreColor, TPixel backColor) new PatternBrush(foreColor, backColor, ForwardDiagonalPattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, ForwardDiagonalPattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Backward Diagonal Hatch Pattern with the specified foreground color and a /// Create as brush that will paint a Backward Diagonal Hatch Pattern with the specified foreground color and a
/// transparent background. /// transparent background.
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush BackwardDiagonal(Color foreColor) =>
public static PatternBrush<TPixel> BackwardDiagonal<TPixel>(TPixel foreColor) new PatternBrush(foreColor, Color.Transparent, BackwardDiagonalPattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, BackwardDiagonalPattern);
/// <summary> /// <summary>
/// Create as brush that will paint a Backward Diagonal Hatch Pattern with the specified colors /// Create as brush that will paint a Backward Diagonal Hatch Pattern with the specified colors
/// </summary> /// </summary>
/// <param name="foreColor">Color of the foreground.</param> /// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param> /// <param name="backColor">Color of the background.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <returns>A New <see cref="PatternBrush"/></returns>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns> public static PatternBrush BackwardDiagonal(Color foreColor, Color backColor) =>
public static PatternBrush<TPixel> BackwardDiagonal<TPixel>(TPixel foreColor, TPixel backColor) new PatternBrush(foreColor, backColor, BackwardDiagonalPattern);
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, BackwardDiagonalPattern);
} }
} }

44
src/ImageSharp.Drawing/Processing/DrawBezierExtensions.cs

@ -15,80 +15,80 @@ namespace SixLabors.ImageSharp.Processing
/// <summary> /// <summary>
/// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush /// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
/// <param name="brush">The brush.</param> /// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param> /// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param> /// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, float thickness, params PointF[] points) public static IImageProcessingContext DrawBeziers(this IImageProcessingContext source, GraphicsOptions options, IBrush brush, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(options, new Pen<TPixel>(brush, thickness), new Path(new CubicBezierLineSegment(points))); => source.Draw(options, new Pen(brush, thickness), new Path(new CubicBezierLineSegment(points)));
/// <summary> /// <summary>
/// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush /// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param> /// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param> /// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param> /// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, params PointF[] points) public static IImageProcessingContext DrawBeziers(this IImageProcessingContext source, IBrush brush, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(new Pen<TPixel>(brush, thickness), new Path(new CubicBezierLineSegment(points))); => source.Draw(new Pen(brush, thickness), new Path(new CubicBezierLineSegment(points)));
/// <summary> /// <summary>
/// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush /// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param> /// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param> /// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, params PointF[] points) public static IImageProcessingContext DrawBeziers(this IImageProcessingContext source, TPixel color, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.DrawBeziers(new SolidBrush<TPixel>(color), thickness, points); => source.DrawBeziers(new SolidBrush(color), thickness, points);
/// <summary> /// <summary>
/// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush /// Draws the provided points as an open Bezier path at the provided thickness with the supplied brush
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param> /// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param> /// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, TPixel color, float thickness, params PointF[] points) public static IImageProcessingContext DrawBeziers(this IImageProcessingContext source, GraphicsOptions options, TPixel color, float thickness, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.DrawBeziers(options, new SolidBrush<TPixel>(color), thickness, points); => source.DrawBeziers(options, new SolidBrush(color), thickness, points);
/// <summary> /// <summary>
/// Draws the provided points as an open Bezier path with the supplied pen /// Draws the provided points as an open Bezier path with the supplied pen
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
/// <param name="pen">The pen.</param> /// <param name="pen">The pen.</param>
/// <param name="points">The points.</param> /// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IPen<TPixel> pen, params PointF[] points) public static IImageProcessingContext DrawBeziers(this IImageProcessingContext source, GraphicsOptions options, IPen pen, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(options, pen, new Path(new CubicBezierLineSegment(points))); => source.Draw(options, pen, new Path(new CubicBezierLineSegment(points)));
/// <summary> /// <summary>
/// Draws the provided points as an open Bezier path with the supplied pen /// Draws the provided points as an open Bezier path with the supplied pen
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param> /// <param name="pen">The pen.</param>
/// <param name="points">The points.</param> /// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, params PointF[] points) public static IImageProcessingContext DrawBeziers(this IImageProcessingContext source, IPen pen, params PointF[] points)
where TPixel : struct, IPixel<TPixel>
=> source.Draw(pen, new Path(new CubicBezierLineSegment(points))); => source.Draw(pen, new Path(new CubicBezierLineSegment(points)));
} }
} }

28
src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs

@ -15,40 +15,38 @@ namespace SixLabors.ImageSharp.Processing
/// Provides an implementation of an image brush for painting images within areas. /// Provides an implementation of an image brush for painting images within areas.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
public class ImageBrush<TPixel> : IBrush<TPixel> public class ImageBrush<TPixel> : IBrush
where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// The image to paint. /// The image to paint.
/// </summary> /// </summary>
private readonly ImageFrame<TPixel> image; private readonly Image image;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ImageBrush{TPixel}"/> class. /// Initializes a new instance of the <see cref="ImageBrush{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="image">The image.</param> /// <param name="image">The image.</param>
public ImageBrush(ImageFrame<TPixel> image) public ImageBrush(Image image)
{ {
this.image = image; this.image = image;
} }
/// <summary> /// <inheritdoc />
/// Initializes a new instance of the <see cref="ImageBrush{TPixel}"/> class. public BrushApplicator<TPixel> CreateApplicator<TPixel>(
/// </summary> ImageFrame<TPixel> source,
/// <param name="image">The image.</param> RectangleF region,
public ImageBrush(Image<TPixel> image) GraphicsOptions options)
: this(image.Frames.RootFrame) where TPixel : struct, IPixel<TPixel>
{ {
Image<TPixel> specificImage = (Image<TPixel>)this.image;
return new ImageBrushApplicator<TPixel>(source, specificImage.Frames.RootFrame, region, options);
} }
/// <inheritdoc />
public BrushApplicator<TPixel> CreateApplicator(ImageFrame<TPixel> source, RectangleF region, GraphicsOptions options)
=> new ImageBrushApplicator(source, this.image, region, options);
/// <summary> /// <summary>
/// The image brush applicator. /// The image brush applicator.
/// </summary> /// </summary>
private class ImageBrushApplicator : BrushApplicator<TPixel> private class ImageBrushApplicator<TPixel> : BrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// The source image. /// The source image.

11
src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs

@ -97,7 +97,11 @@ namespace SixLabors.ImageSharp.Processing
RectangleF region, RectangleF region,
GraphicsOptions options) GraphicsOptions options)
where TPixel : struct, IPixel<TPixel> => where TPixel : struct, IPixel<TPixel> =>
new PatternBrushApplicator<TPixel>(source, this.pattern, this.patternVector, options); new PatternBrushApplicator<TPixel>(
source,
this.pattern.ToPixelMatrix<TPixel>(source.Configuration),
this.patternVector,
options);
/// <summary> /// <summary>
/// The pattern brush applicator. /// The pattern brush applicator.
@ -118,11 +122,10 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="patternVector">The patternVector.</param> /// <param name="patternVector">The patternVector.</param>
/// <param name="options">The options</param> /// <param name="options">The options</param>
public PatternBrushApplicator(ImageFrame<TPixel> source, in DenseMatrix<Color> pattern, DenseMatrix<Vector4> patternVector, GraphicsOptions options) public PatternBrushApplicator(ImageFrame<TPixel> source, in DenseMatrix<TPixel> pattern, DenseMatrix<Vector4> patternVector, GraphicsOptions options)
: base(source, options) : base(source, options)
{ {
this.pattern = new DenseMatrix<TPixel>(pattern.Columns, pattern.Rows); this.pattern = pattern;
Color.ToPixel<TPixel>(source.Configuration, pattern.Data, this.pattern.Data);
this.patternVector = patternVector; this.patternVector = patternVector;
} }

50
src/ImageSharp.Drawing/Processing/Pens.cs

@ -21,109 +21,79 @@ namespace SixLabors.ImageSharp.Processing
/// </summary> /// </summary>
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> Solid<TPixel>(TPixel color, float width) public static Pen Solid(Color color, float width) => new Pen(color, width);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width);
/// <summary> /// <summary>
/// Create a solid pen with out any drawing patterns /// Create a solid pen with out any drawing patterns
/// </summary> /// </summary>
/// <param name="brush">The brush.</param> /// <param name="brush">The brush.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> Solid<TPixel>(IBrush<TPixel> brush, float width) public static Pen Solid(IBrush brush, float width) => new Pen(brush, width);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width);
/// <summary> /// <summary>
/// Create a pen with a 'Dash' drawing patterns /// Create a pen with a 'Dash' drawing patterns
/// </summary> /// </summary>
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> Dash<TPixel>(TPixel color, float width) public static Pen Dash(Color color, float width) => new Pen(color, width, DashedPattern);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width, DashedPattern);
/// <summary> /// <summary>
/// Create a pen with a 'Dash' drawing patterns /// Create a pen with a 'Dash' drawing patterns
/// </summary> /// </summary>
/// <param name="brush">The brush.</param> /// <param name="brush">The brush.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> Dash<TPixel>(IBrush<TPixel> brush, float width) public static Pen Dash(IBrush brush, float width) => new Pen(brush, width, DashedPattern);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width, DashedPattern);
/// <summary> /// <summary>
/// Create a pen with a 'Dot' drawing patterns /// Create a pen with a 'Dot' drawing patterns
/// </summary> /// </summary>
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> Dot<TPixel>(TPixel color, float width) public static Pen Dot(Color color, float width) => new Pen(color, width, DottedPattern);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width, DottedPattern);
/// <summary> /// <summary>
/// Create a pen with a 'Dot' drawing patterns /// Create a pen with a 'Dot' drawing patterns
/// </summary> /// </summary>
/// <param name="brush">The brush.</param> /// <param name="brush">The brush.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> Dot<TPixel>(IBrush<TPixel> brush, float width) public static Pen Dot(IBrush brush, float width) => new Pen(brush, width, DottedPattern);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width, DottedPattern);
/// <summary> /// <summary>
/// Create a pen with a 'Dash Dot' drawing patterns /// Create a pen with a 'Dash Dot' drawing patterns
/// </summary> /// </summary>
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> DashDot<TPixel>(TPixel color, float width) public static Pen DashDot(Color color, float width) => new Pen(color, width, DashDotPattern);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width, DashDotPattern);
/// <summary> /// <summary>
/// Create a pen with a 'Dash Dot' drawing patterns /// Create a pen with a 'Dash Dot' drawing patterns
/// </summary> /// </summary>
/// <param name="brush">The brush.</param> /// <param name="brush">The brush.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> DashDot<TPixel>(IBrush<TPixel> brush, float width) public static Pen DashDot(IBrush brush, float width) => new Pen(brush, width, DashDotPattern);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width, DashDotPattern);
/// <summary> /// <summary>
/// Create a pen with a 'Dash Dot Dot' drawing patterns /// Create a pen with a 'Dash Dot Dot' drawing patterns
/// </summary> /// </summary>
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> DashDotDot<TPixel>(TPixel color, float width) public static Pen DashDotDot(Color color, float width) => new Pen(color, width, DashDotDotPattern);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width, DashDotDotPattern);
/// <summary> /// <summary>
/// Create a pen with a 'Dash Dot Dot' drawing patterns /// Create a pen with a 'Dash Dot Dot' drawing patterns
/// </summary> /// </summary>
/// <param name="brush">The brush.</param> /// <param name="brush">The brush.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns> /// <returns>The Pen</returns>
public static Pen<TPixel> DashDotDot<TPixel>(IBrush<TPixel> brush, float width) public static Pen DashDotDot(IBrush brush, float width) => new Pen(brush, width, DashDotDotPattern);
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width, DashDotDotPattern);
} }
} }

18
src/ImageSharp.Drawing/Processing/Pen{TPixel}.cs

@ -9,7 +9,6 @@ namespace SixLabors.ImageSharp.Processing
/// <summary> /// <summary>
/// Provides a pen that can apply a pattern to a line with a set brush and thickness /// Provides a pen that can apply a pattern to a line with a set brush and thickness
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <remarks> /// <remarks>
/// The pattern will be in to the form of new float[]{ 1f, 2f, 0.5f} this will be /// The pattern will be in to the form of new float[]{ 1f, 2f, 0.5f} this will be
/// converted into a pattern that is 3.5 times longer that the width with 3 sections /// converted into a pattern that is 3.5 times longer that the width with 3 sections
@ -18,8 +17,7 @@ namespace SixLabors.ImageSharp.Processing
/// section 3 will be width/2 long and will be filled /// section 3 will be width/2 long and will be filled
/// the the pattern will immediately repeat without gap. /// the the pattern will immediately repeat without gap.
/// </remarks> /// </remarks>
public class Pen<TPixel> : IPen<TPixel> public class Pen : IPen
where TPixel : struct, IPixel<TPixel>
{ {
private readonly float[] pattern; private readonly float[] pattern;
@ -29,8 +27,8 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
public Pen(TPixel color, float width, float[] pattern) public Pen(Color color, float width, float[] pattern)
: this(new SolidBrush<TPixel>(color), width, pattern) : this(new SolidBrush(color), width, pattern)
{ {
} }
@ -40,7 +38,7 @@ namespace SixLabors.ImageSharp.Processing
/// <param name="brush">The brush.</param> /// <param name="brush">The brush.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
public Pen(IBrush<TPixel> brush, float width, float[] pattern) public Pen(IBrush brush, float width, float[] pattern)
{ {
this.StrokeFill = brush; this.StrokeFill = brush;
this.StrokeWidth = width; this.StrokeWidth = width;
@ -52,8 +50,8 @@ namespace SixLabors.ImageSharp.Processing
/// </summary> /// </summary>
/// <param name="color">The color.</param> /// <param name="color">The color.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
public Pen(TPixel color, float width) public Pen(Color color, float width)
: this(new SolidBrush<TPixel>(color), width) : this(new SolidBrush(color), width)
{ {
} }
@ -62,13 +60,13 @@ namespace SixLabors.ImageSharp.Processing
/// </summary> /// </summary>
/// <param name="brush">The brush.</param> /// <param name="brush">The brush.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
public Pen(IBrush<TPixel> brush, float width) public Pen(IBrush brush, float width)
: this(brush, width, Pens.EmptyPattern) : this(brush, width, Pens.EmptyPattern)
{ {
} }
/// <inheritdoc/> /// <inheritdoc/>
public IBrush<TPixel> StrokeFill { get; } public IBrush StrokeFill { get; }
/// <inheritdoc/> /// <inheritdoc/>
public float StrokeWidth { get; } public float StrokeWidth { get; }

57
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs

@ -13,6 +13,26 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{ {
public class FillProcessor : IImageProcessor
{
public FillProcessor(IBrush brush, GraphicsOptions options)
{
this.Brush = brush;
this.Options = options;
}
public IBrush Brush { get; }
public GraphicsOptions Options { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
return new FillProcessor<TPixel>(this);
}
}
/// <summary> /// <summary>
/// Using the brush as a source of pixels colors blends the brush color with source. /// Using the brush as a source of pixels colors blends the brush color with source.
/// </summary> /// </summary>
@ -20,21 +40,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
internal class FillProcessor<TPixel> : ImageProcessor<TPixel> internal class FillProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> private readonly FillProcessor definition;
/// The brush.
/// </summary> public FillProcessor(FillProcessor definition)
private readonly IBrush<TPixel> brush;
private readonly GraphicsOptions options;
/// <summary>
/// Initializes a new instance of the <see cref="FillProcessor{TPixel}"/> class.
/// </summary>
/// <param name="brush">The brush to source pixel colors from.</param>
/// <param name="options">The options</param>
public FillProcessor(IBrush<TPixel> brush, GraphicsOptions options)
{ {
this.brush = brush; this.definition = definition;
this.options = options;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -55,11 +65,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
IBrush brush = this.definition.Brush;
GraphicsOptions options = this.definition.Options;
// If there's no reason for blending, then avoid it. // If there's no reason for blending, then avoid it.
if (this.IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush)) if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush))
{ {
ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings().MultiplyMinimumPixelsPerTask(4); ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings().MultiplyMinimumPixelsPerTask(4);
TPixel colorPixel = solidBrush.Color.ToPixel<TPixel>();
ParallelHelper.IterateRows( ParallelHelper.IterateRows(
workingRect, workingRect,
parallelSettings, parallelSettings,
@ -67,7 +82,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{ {
for (int y = rows.Min; y < rows.Max; y++) for (int y = rows.Min; y < rows.Max; y++)
{ {
source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); source.GetPixelRowSpan(y).Slice(minX, width).Fill(colorPixel);
} }
}); });
} }
@ -85,10 +100,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
} }
using (IMemoryOwner<float> amount = source.MemoryAllocator.Allocate<float>(width)) using (IMemoryOwner<float> amount = source.MemoryAllocator.Allocate<float>(width))
using (BrushApplicator<TPixel> applicator = this.brush.CreateApplicator( using (BrushApplicator<TPixel> applicator = brush.CreateApplicator(
source, source,
sourceRectangle, sourceRectangle,
this.options)) options))
{ {
amount.GetSpan().Fill(1f); amount.GetSpan().Fill(1f);
@ -109,16 +124,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
} }
} }
private bool IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush) private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush)
{ {
solidBrush = this.brush as SolidBrush<TPixel>; solidBrush = this.definition.Brush as SolidBrush;
if (solidBrush == null) if (solidBrush == null)
{ {
return false; return false;
} }
return this.options.IsOpaqueColorWithoutBlending(solidBrush.Color); return this.definition.Options.IsOpaqueColorWithoutBlending(solidBrush.Color);
} }
} }
} }

63
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs

@ -13,24 +13,15 @@ using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{ {
/// <summary> public class FillRegionProcessor : IImageProcessor
/// Using a brush and a shape fills shape with contents of brush the
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <seealso cref="ImageProcessor{TPixel}" />
internal class FillRegionProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{ {
private const float AntialiasFactor = 1f;
private const int DrawPadding = 1;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FillRegionProcessor{TPixel}" /> class. /// Initializes a new instance of the <see cref="FillRegionProcessor" /> class.
/// </summary> /// </summary>
/// <param name="brush">The details how to fill the region of interest.</param> /// <param name="brush">The details how to fill the region of interest.</param>
/// <param name="region">The region of interest to be filled.</param> /// <param name="region">The region of interest to be filled.</param>
/// <param name="options">The configuration options.</param> /// <param name="options">The configuration options.</param>
public FillRegionProcessor(IBrush<TPixel> brush, Region region, GraphicsOptions options) public FillRegionProcessor(IBrush brush, Region region, GraphicsOptions options)
{ {
this.Region = region; this.Region = region;
this.Brush = brush; this.Brush = brush;
@ -40,7 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
/// <summary> /// <summary>
/// Gets the brush. /// Gets the brush.
/// </summary> /// </summary>
public IBrush<TPixel> Brush { get; } public IBrush Brush { get; }
/// <summary> /// <summary>
/// Gets the region that this processor applies to. /// Gets the region that this processor applies to.
@ -55,10 +46,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
/// </value> /// </value>
public GraphicsOptions Options { get; } public GraphicsOptions Options { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
return new FillRegionProcessor<TPixel>(this);
}
}
/// <summary>
/// Using a brush and a shape fills shape with contents of brush the
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <seealso cref="ImageProcessor{TPixel}" />
internal class FillRegionProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly FillRegionProcessor definition;
public FillRegionProcessor(FillRegionProcessor definition)
{
this.definition = definition;
}
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{ {
Region region = this.Region; GraphicsOptions options = this.definition.Options;
IBrush brush = this.definition.Brush;
Region region = this.definition.Region;
Rectangle rect = region.Bounds; Rectangle rect = region.Bounds;
// Align start/end positions. // Align start/end positions.
@ -84,17 +100,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
// and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the# // and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the#
// region to align with the pixel grid. // region to align with the pixel grid.
float offset = 0.5f; float offset = 0.5f;
if (this.Options.Antialias) if (options.Antialias)
{ {
offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset. offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset.
subpixelCount = this.Options.AntialiasSubpixelDepth; subpixelCount = options.AntialiasSubpixelDepth;
if (subpixelCount < 4) if (subpixelCount < 4)
{ {
subpixelCount = 4; subpixelCount = 4;
} }
} }
using (BrushApplicator<TPixel> applicator = this.Brush.CreateApplicator(source, rect, this.Options)) using (BrushApplicator<TPixel> applicator = brush.CreateApplicator(source, rect, options))
{ {
int scanlineWidth = maxX - minX; int scanlineWidth = maxX - minX;
using (IMemoryOwner<float> bBuffer = source.MemoryAllocator.Allocate<float>(maxIntersections)) using (IMemoryOwner<float> bBuffer = source.MemoryAllocator.Allocate<float>(maxIntersections))
@ -107,7 +123,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
Span<float> buffer = bBuffer.GetSpan(); Span<float> buffer = bBuffer.GetSpan();
Span<float> scanline = bScanline.GetSpan(); Span<float> scanline = bScanline.GetSpan();
bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush); bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush);
TPixel solidBrushColor = isSolidBrushWithoutBlending ? solidBrush.Color.ToPixel<TPixel>() : default;
for (int y = minY; y < maxY; y++) for (int y = minY; y < maxY; y++)
{ {
@ -168,7 +185,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
if (scanlineDirty) if (scanlineDirty)
{ {
if (!this.Options.Antialias) if (!options.Antialias)
{ {
bool hasOnes = false; bool hasOnes = false;
bool hasZeros = false; bool hasZeros = false;
@ -190,7 +207,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{ {
if (hasOnes) if (hasOnes)
{ {
source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrush.Color); source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrushColor);
} }
continue; continue;
@ -204,16 +221,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
} }
} }
private bool IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush) private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush)
{ {
solidBrush = this.Brush as SolidBrush<TPixel>; solidBrush = this.definition.Brush as SolidBrush;
if (solidBrush == null) if (solidBrush == null)
{ {
return false; return false;
} }
return this.Options.IsOpaqueColorWithoutBlending(solidBrush.Color); return this.definition.Options.IsOpaqueColorWithoutBlending(solidBrush.Color);
} }
} }
} }

55
src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs

@ -15,17 +15,10 @@ using SixLabors.Shapes;
namespace SixLabors.ImageSharp.Processing.Processors.Text namespace SixLabors.ImageSharp.Processing.Processors.Text
{ {
/// <summary> public class DrawTextProcessor : IImageProcessor
/// Using the brush as a source of pixels colors blends the brush color with source.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class DrawTextProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{ {
private CachingGlyphRenderer textRenderer;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DrawTextProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="DrawTextProcessor"/> class.
/// </summary> /// </summary>
/// <param name="options">The options</param> /// <param name="options">The options</param>
/// <param name="text">The text we want to render</param> /// <param name="text">The text we want to render</param>
@ -33,7 +26,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
/// <param name="brush">The brush to source pixel colors from.</param> /// <param name="brush">The brush to source pixel colors from.</param>
/// <param name="pen">The pen to outline text with.</param> /// <param name="pen">The pen to outline text with.</param>
/// <param name="location">The location on the image to start drawing the text from.</param> /// <param name="location">The location on the image to start drawing the text from.</param>
public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location) public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location)
{ {
Guard.NotNull(text, nameof(text)); Guard.NotNull(text, nameof(text));
Guard.NotNull(font, nameof(font)); Guard.NotNull(font, nameof(font));
@ -54,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
/// <summary> /// <summary>
/// Gets the brush. /// Gets the brush.
/// </summary> /// </summary>
public IBrush<TPixel> Brush { get; } public IBrush Brush { get; }
/// <summary> /// <summary>
/// Gets the options /// Gets the options
@ -69,7 +62,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
/// <summary> /// <summary>
/// Gets the pen used for outlining the text, if Null then we will not outline /// Gets the pen used for outlining the text, if Null then we will not outline
/// </summary> /// </summary>
public IPen<TPixel> Pen { get; } public IPen Pen { get; }
/// <summary> /// <summary>
/// Gets the font used to render the text. /// Gets the font used to render the text.
@ -81,6 +74,42 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
/// </summary> /// </summary>
public PointF Location { get; } public PointF Location { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
throw new NotImplementedException();
}
}
/// <summary>
/// Using the brush as a source of pixels colors blends the brush color with source.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class DrawTextProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private CachingGlyphRenderer textRenderer;
private readonly DrawTextProcessor definition;
public DrawTextProcessor(DrawTextProcessor definition)
{
this.definition = definition;
}
private TextGraphicsOptions Options => this.definition.Options;
private Font Font => this.definition.Font;
private PointF Location => this.definition.Location;
private string Text => this.definition.Text;
private IPen Pen => this.definition.Pen;
private IBrush Brush => this.definition.Brush;
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle) protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{ {
base.BeforeImageApply(source, sourceRectangle); base.BeforeImageApply(source, sourceRectangle);
@ -115,7 +144,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
Draw(this.textRenderer.FillOperations, this.Brush); Draw(this.textRenderer.FillOperations, this.Brush);
Draw(this.textRenderer.OutlineOperations, this.Pen?.StrokeFill); Draw(this.textRenderer.OutlineOperations, this.Pen?.StrokeFill);
void Draw(List<DrawingOperation> operations, IBrush<TPixel> brush) void Draw(List<DrawingOperation> operations, IBrush brush)
{ {
if (operations?.Count > 0) if (operations?.Count > 0)
{ {

29
src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs

@ -16,16 +16,15 @@ namespace SixLabors.ImageSharp.Processing
/// Provides an implementation of a brush that can recolor an image /// Provides an implementation of a brush that can recolor an image
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
public class RecolorBrush<TPixel> : IBrush<TPixel> public class RecolorBrush : IBrush
where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RecolorBrush{TPixel}" /> class. /// Initializes a new instance of the <see cref="RecolorBrush" /> class.
/// </summary> /// </summary>
/// <param name="sourceColor">Color of the source.</param> /// <param name="sourceColor">Color of the source.</param>
/// <param name="targetColor">Color of the target.</param> /// <param name="targetColor">Color of the target.</param>
/// <param name="threshold">The threshold as a value between 0 and 1.</param> /// <param name="threshold">The threshold as a value between 0 and 1.</param>
public RecolorBrush(TPixel sourceColor, TPixel targetColor, float threshold) public RecolorBrush(Color sourceColor, Color targetColor, float threshold)
{ {
this.SourceColor = sourceColor; this.SourceColor = sourceColor;
this.Threshold = threshold; this.Threshold = threshold;
@ -43,23 +42,33 @@ namespace SixLabors.ImageSharp.Processing
/// <value> /// <value>
/// The color of the source. /// The color of the source.
/// </value> /// </value>
public TPixel SourceColor { get; } public Color SourceColor { get; }
/// <summary> /// <summary>
/// Gets the target color. /// Gets the target color.
/// </summary> /// </summary>
public TPixel TargetColor { get; } public Color TargetColor { get; }
/// <inheritdoc /> /// <inheritdoc />
public BrushApplicator<TPixel> CreateApplicator(ImageFrame<TPixel> source, RectangleF region, GraphicsOptions options) public BrushApplicator<TPixel> CreateApplicator<TPixel>(
ImageFrame<TPixel> source,
RectangleF region,
GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{ {
return new RecolorBrushApplicator(source, this.SourceColor, this.TargetColor, this.Threshold, options); return new RecolorBrushApplicator<TPixel>(
source,
this.SourceColor.ToPixel<TPixel>(),
this.TargetColor.ToPixel<TPixel>(),
this.Threshold,
options);
} }
/// <summary> /// <summary>
/// The recolor brush applicator. /// The recolor brush applicator.
/// </summary> /// </summary>
private class RecolorBrushApplicator : BrushApplicator<TPixel> private class RecolorBrushApplicator<TPixel> : BrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// The source color. /// The source color.
@ -79,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing
private readonly TPixel targetColorPixel; private readonly TPixel targetColorPixel;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RecolorBrushApplicator" /> class. /// Initializes a new instance of the <see cref="RecolorBrushApplicator{TPixel}" /> class.
/// </summary> /// </summary>
/// <param name="source">The source image.</param> /// <param name="source">The source image.</param>
/// <param name="sourceColor">Color of the source.</param> /// <param name="sourceColor">Color of the source.</param>

231
src/ImageSharp/GraphicsOptions.cs

@ -1,141 +1,141 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
/// <summary> /// <summary>
/// Options for influencing the drawing functions. /// Options for influencing the drawing functions.
/// </summary> /// </summary>
public struct GraphicsOptions public struct GraphicsOptions
{ {
/// <summary> /// <summary>
/// Represents the default <see cref="GraphicsOptions"/>. /// Represents the default <see cref="GraphicsOptions"/>.
/// </summary> /// </summary>
public static readonly GraphicsOptions Default = new GraphicsOptions(true); public static readonly GraphicsOptions Default = new GraphicsOptions(true);
private float? blendPercentage; private float? blendPercentage;
private int? antialiasSubpixelDepth; private int? antialiasSubpixelDepth;
private bool? antialias; private bool? antialias;
private PixelColorBlendingMode colorBlendingMode; private PixelColorBlendingMode colorBlendingMode;
private PixelAlphaCompositionMode alphaCompositionMode; private PixelAlphaCompositionMode alphaCompositionMode;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct. /// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
/// </summary> /// </summary>
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param> /// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
public GraphicsOptions(bool enableAntialiasing) public GraphicsOptions(bool enableAntialiasing)
{ {
this.colorBlendingMode = PixelColorBlendingMode.Normal; this.colorBlendingMode = PixelColorBlendingMode.Normal;
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver;
this.blendPercentage = 1; this.blendPercentage = 1;
this.antialiasSubpixelDepth = 16; this.antialiasSubpixelDepth = 16;
this.antialias = enableAntialiasing; this.antialias = enableAntialiasing;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct. /// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
/// </summary> /// </summary>
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param> /// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
/// <param name="opacity">blending percentage to apply to the drawing operation</param> /// <param name="opacity">blending percentage to apply to the drawing operation</param>
public GraphicsOptions(bool enableAntialiasing, float opacity) public GraphicsOptions(bool enableAntialiasing, float opacity)
{ {
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.colorBlendingMode = PixelColorBlendingMode.Normal; this.colorBlendingMode = PixelColorBlendingMode.Normal;
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver;
this.blendPercentage = opacity; this.blendPercentage = opacity;
this.antialiasSubpixelDepth = 16; this.antialiasSubpixelDepth = 16;
this.antialias = enableAntialiasing; this.antialias = enableAntialiasing;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct. /// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
/// </summary> /// </summary>
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param> /// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
/// <param name="opacity">blending percentage to apply to the drawing operation</param> /// <param name="opacity">blending percentage to apply to the drawing operation</param>
/// <param name="blending">color blending mode to apply to the drawing operation</param> /// <param name="blending">color blending mode to apply to the drawing operation</param>
public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, float opacity) public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, float opacity)
{ {
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.colorBlendingMode = blending; this.colorBlendingMode = blending;
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver;
this.blendPercentage = opacity; this.blendPercentage = opacity;
this.antialiasSubpixelDepth = 16; this.antialiasSubpixelDepth = 16;
this.antialias = enableAntialiasing; this.antialias = enableAntialiasing;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct. /// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
/// </summary> /// </summary>
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param> /// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
/// <param name="opacity">blending percentage to apply to the drawing operation</param> /// <param name="opacity">blending percentage to apply to the drawing operation</param>
/// <param name="blending">color blending mode to apply to the drawing operation</param> /// <param name="blending">color blending mode to apply to the drawing operation</param>
/// <param name="composition">alpha composition mode to apply to the drawing operation</param> /// <param name="composition">alpha composition mode to apply to the drawing operation</param>
public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, float opacity) public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, float opacity)
{ {
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.colorBlendingMode = blending; this.colorBlendingMode = blending;
this.alphaCompositionMode = composition; this.alphaCompositionMode = composition;
this.blendPercentage = opacity; this.blendPercentage = opacity;
this.antialiasSubpixelDepth = 16; this.antialiasSubpixelDepth = 16;
this.antialias = enableAntialiasing; this.antialias = enableAntialiasing;
}
/// <summary>
/// Gets or sets a value indicating whether antialiasing should be applied.
/// </summary>
public bool Antialias
{
get => this.antialias ?? true;
set => this.antialias = value;
}
/// <summary>
/// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled.
/// </summary>
public int AntialiasSubpixelDepth
{
get => this.antialiasSubpixelDepth ?? 16;
set => this.antialiasSubpixelDepth = value;
}
/// <summary>
/// Gets or sets a value indicating the blending percentage to apply to the drawing operation
/// </summary>
public float BlendPercentage
{
get => (this.blendPercentage ?? 1).Clamp(0, 1);
set => this.blendPercentage = value;
}
// In the future we could expose a PixelBlender<TPixel> directly on here
// or some forms of PixelBlender factory for each pixel type. Will need
// some API thought post V1.
/// <summary>
/// Gets or sets a value indicating the color blending mode to apply to the drawing operation
/// </summary>
public PixelColorBlendingMode ColorBlendingMode
{
get => this.colorBlendingMode;
set => this.colorBlendingMode = value;
} }
/// <summary> /// <summary>
/// Gets or sets a value indicating the alpha composition mode to apply to the drawing operation /// Gets or sets a value indicating whether antialiasing should be applied.
/// </summary> /// </summary>
public PixelAlphaCompositionMode AlphaCompositionMode public bool Antialias
{ {
get => this.alphaCompositionMode; get => this.antialias ?? true;
set => this.alphaCompositionMode = value; set => this.antialias = value;
}
/// <summary>
/// Gets or sets a value indicating the number of subpixels to use while rendering with antialiasing enabled.
/// </summary>
public int AntialiasSubpixelDepth
{
get => this.antialiasSubpixelDepth ?? 16;
set => this.antialiasSubpixelDepth = value;
}
/// <summary>
/// Gets or sets a value indicating the blending percentage to apply to the drawing operation
/// </summary>
public float BlendPercentage
{
get => (this.blendPercentage ?? 1).Clamp(0, 1);
set => this.blendPercentage = value;
}
// In the future we could expose a PixelBlender<TPixel> directly on here
// or some forms of PixelBlender factory for each pixel type. Will need
// some API thought post V1.
/// <summary>
/// Gets or sets a value indicating the color blending mode to apply to the drawing operation
/// </summary>
public PixelColorBlendingMode ColorBlendingMode
{
get => this.colorBlendingMode;
set => this.colorBlendingMode = value;
}
/// <summary>
/// Gets or sets a value indicating the alpha composition mode to apply to the drawing operation
/// </summary>
public PixelAlphaCompositionMode AlphaCompositionMode
{
get => this.alphaCompositionMode;
set => this.alphaCompositionMode = value;
} }
/// <summary> /// <summary>
@ -149,8 +149,7 @@ namespace SixLabors.ImageSharp
/// filling with a solid color, the blending can be avoided by a plain color replacement. /// filling with a solid color, the blending can be avoided by a plain color replacement.
/// This method can be useful for such processors to select the fast path. /// This method can be useful for such processors to select the fast path.
/// </remarks> /// </remarks>
internal bool IsOpaqueColorWithoutBlending<TPixel>(TPixel color) internal bool IsOpaqueColorWithoutBlending(Color color)
where TPixel : struct, IPixel<TPixel>
{ {
if (this.ColorBlendingMode != PixelColorBlendingMode.Normal) if (this.ColorBlendingMode != PixelColorBlendingMode.Normal)
{ {
@ -174,6 +173,6 @@ namespace SixLabors.ImageSharp
} }
return true; return true;
} }
} }
} }
Loading…
Cancel
Save