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
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;

namespace SixLabors.ImageSharp
{
/// <summary>
/// Extensions methods fpor the <see cref="GraphicsOptions"/> class.
/// </summary>
internal static class GraphicsOptionsExtensions
{
/// <summary>
/// Evaluates if a given SOURCE color can completely replace a BACKDROP color given the current blending and composition settings.
/// </summary>
/// <param name="options">The graphics options.</param>
/// <param name="color">The source color.</param>
/// <returns>true if the color can be considered opaque</returns>
/// <remarks>
/// Blending and composition is an expensive operation, in some cases, like
/// 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.
/// </remarks>
public static bool IsOpaqueColorWithoutBlending(this GraphicsOptions options, Color color)
{
if (options.ColorBlendingMode != PixelColorBlendingMode.Normal)
{
return false;
}

if (options.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver
&& options.AlphaCompositionMode != PixelAlphaCompositionMode.Src)
{
return false;
}

const float Opaque = 1F;

if (options.BlendPercentage != Opaque)
{
return false;
}

if (((Vector4)color).W != Opaque)
{
return false;
}

return true;
}
}
}
6 changes: 3 additions & 3 deletions src/ImageSharp.Drawing/Primitives/ShapeRegion.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
Expand Down Expand Up @@ -49,7 +49,7 @@ public override int Scan(float y, Span<float> buffer, Configuration configuratio

using (IMemoryOwner<PointF> tempBuffer = configuration.MemoryAllocator.Allocate<PointF>(buffer.Length))
{
Span<PointF> innerBuffer = tempBuffer.GetSpan();
Span<PointF> innerBuffer = tempBuffer.Memory.Span;
int count = this.Shape.FindIntersections(start, end, innerBuffer);

for (int i = 0; i < count; i++)
Expand All @@ -61,4 +61,4 @@ public override int Scan(float y, Span<float> buffer, Configuration configuratio
}
}
}
}
}
61 changes: 39 additions & 22 deletions src/ImageSharp.Drawing/Processing/BrushApplicator.cs
Original file line number Diff line number Diff line change
@@ -1,68 +1,85 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Buffers;

using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;

namespace SixLabors.ImageSharp.Processing
{
/// <summary>
/// primitive that converts a point in to a color for discovering the fill color based on an implementation
/// A primitive that converts a point into a color for discovering the fill color based on an implementation.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <seealso cref="System.IDisposable" />
public abstract class BrushApplicator<TPixel> : IDisposable // disposable will be required if/when there is an ImageBrush
/// <seealso cref="IDisposable" />
public abstract class BrushApplicator<TPixel> : IDisposable
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="BrushApplicator{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="target">The target.</param>
/// <param name="options">The options.</param>
internal BrushApplicator(ImageFrame<TPixel> target, GraphicsOptions options)
internal BrushApplicator(Configuration configuration, GraphicsOptions options, ImageFrame<TPixel> target)
{
this.Configuration = configuration;
this.Target = target;
this.Options = options;
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options);
}

/// <summary>
/// Gets the blender
/// Gets the configuration instance to use when performing operations.
/// </summary>
protected Configuration Configuration { get; }

/// <summary>
/// Gets the pixel blender.
/// </summary>
internal PixelBlender<TPixel> Blender { get; }

/// <summary>
/// Gets the destination
/// Gets the target image.
/// </summary>
protected ImageFrame<TPixel> Target { get; }

/// <summary>
/// Gets the blend percentage
/// Gets thegraphics options
/// </summary>
protected GraphicsOptions Options { get; }

/// <summary>
/// Gets the color for a single pixel.
/// Gets the overlay pixel at the specified position.
/// </summary>
/// <param name="x">The x coordinate.</param>
/// <param name="y">The y coordinate.</param>
/// <returns>The a <typeparamref name="TPixel"/> that should be applied to the pixel.</returns>
/// <param name="x">The x-coordinate.</param>
/// <param name="y">The y-coordinate.</param>
/// <returns>The <see typeparam="TPixel"/> at the specified position.</returns>
internal abstract TPixel this[int x, int y] { get; }

/// <inheritdoc/>
public abstract void Dispose();
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

/// <summary>
/// Disposes the object and frees resources for the Garbage Collector.
/// </summary>
/// <param name="disposing">Whether to dispose managed and unmanaged objects.</param>
protected virtual void Dispose(bool disposing)
{
}

/// <summary>
/// Applies the opacity weighting for each pixel in a scanline to the target based on the pattern contained in the brush.
/// </summary>
/// <param name="scanline">The a collection of opacity values between 0 and 1 to be merged with the brushed color value before being applied to the target.</param>
/// <param name="x">The x position in the target pixel space that the start of the scanline data corresponds to.</param>
/// <param name="y">The y position in the target pixel space that whole scanline corresponds to.</param>
/// <param name="scanline">A collection of opacity values between 0 and 1 to be merged with the brushed color value before being applied to the target.</param>
/// <param name="x">The x-position in the target pixel space that the start of the scanline data corresponds to.</param>
/// <param name="y">The y-position in the target pixel space that whole scanline corresponds to.</param>
/// <remarks>scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.</remarks>
internal virtual void Apply(Span<float> scanline, int x, int y)
{
Expand All @@ -71,8 +88,8 @@ internal virtual void Apply(Span<float> scanline, int x, int y)
using (IMemoryOwner<float> amountBuffer = memoryAllocator.Allocate<float>(scanline.Length))
using (IMemoryOwner<TPixel> overlay = memoryAllocator.Allocate<TPixel>(scanline.Length))
{
Span<float> amountSpan = amountBuffer.GetSpan();
Span<TPixel> overlaySpan = overlay.GetSpan();
Span<float> amountSpan = amountBuffer.Memory.Span;
Span<TPixel> overlaySpan = overlay.Memory.Span;

for (int i = 0; i < scanline.Length; i++)
{
Expand All @@ -89,7 +106,7 @@ internal virtual void Apply(Span<float> scanline, int x, int y)
}

Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(this.Target.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(this.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}
Expand Down
41 changes: 19 additions & 22 deletions src/ImageSharp.Drawing/Processing/EllipticGradientBrush.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
Expand Down Expand Up @@ -47,12 +47,14 @@ public EllipticGradientBrush(

/// <inheritdoc />
public override BrushApplicator<TPixel> CreateApplicator<TPixel>(
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> source,
RectangleF region,
GraphicsOptions options) =>
RectangleF region) =>
new RadialGradientBrushApplicator<TPixel>(
source,
configuration,
options,
source,
this.center,
this.referenceAxisEnd,
this.axisRatio,
Expand Down Expand Up @@ -86,24 +88,26 @@ private sealed class RadialGradientBrushApplicator<TPixel> : GradientBrushApplic
/// <summary>
/// Initializes a new instance of the <see cref="RadialGradientBrushApplicator{TPixel}" /> class.
/// </summary>
/// <param name="target">The target image</param>
/// <param name="options">The options</param>
/// <param name="center">Center of the ellipse</param>
/// <param name="configuration">The configuration instance to use when performing operations.</param>
/// <param name="options">The graphics options.</param>
/// <param name="target">The target image.</param>
/// <param name="center">Center of the ellipse.</param>
/// <param name="referenceAxisEnd">Point on one angular points of the ellipse.</param>
/// <param name="axisRatio">
/// Ratio of the axis length's. Used to determine the length of the second axis,
/// the first is defined by <see cref="center"/> and <see cref="referenceAxisEnd"/>.</param>
/// <param name="colorStops">Definition of colors</param>
/// <param name="colorStops">Definition of colors.</param>
/// <param name="repetitionMode">Defines how the gradient colors are repeated.</param>
public RadialGradientBrushApplicator(
ImageFrame<TPixel> target,
Configuration configuration,
GraphicsOptions options,
ImageFrame<TPixel> target,
PointF center,
PointF referenceAxisEnd,
float axisRatio,
ColorStop[] colorStops,
GradientRepetitionMode repetitionMode)
: base(target, options, colorStops, repetitionMode)
: base(configuration, options, target, colorStops, repetitionMode)
{
this.center = center;
this.referenceAxisEnd = referenceAxisEnd;
Expand All @@ -122,11 +126,6 @@ public RadialGradientBrushApplicator(
this.cosRotation = (float)Math.Cos(this.rotation);
}

/// <inheritdoc />
public override void Dispose()
{
}

/// <inheritdoc />
protected override float PositionOnGradient(float xt, float yt)
{
Expand All @@ -139,23 +138,21 @@ protected override float PositionOnGradient(float xt, float yt)
float xSquared = x * x;
float ySquared = y * y;

var inBoundaryChecker = (xSquared / this.referenceRadiusSquared)
+ (ySquared / this.secondRadiusSquared);

return inBoundaryChecker;
return (xSquared / this.referenceRadiusSquared) + (ySquared / this.secondRadiusSquared);
}

private float AngleBetween(PointF junction, PointF a, PointF b)
{
var vA = a - junction;
var vB = b - junction;
PointF vA = a - junction;
PointF vB = b - junction;
return MathF.Atan2(vB.Y, vB.X) - MathF.Atan2(vA.Y, vA.X);
}

private float DistanceBetween(
PointF p1,
PointF p2)
{
// TODO: Can we not just use Vector2 distance here?
float dX = p1.X - p2.X;
float dXsquared = dX * dX;

Expand All @@ -165,4 +162,4 @@ private float DistanceBetween(
}
}
}
}
}
40 changes: 23 additions & 17 deletions src/ImageSharp.Drawing/Processing/Extensions/DrawImageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ public static class DrawImageExtensions
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image image,
float opacity) =>
source.ApplyProcessor(
float opacity)
{
var options = new GraphicsOptions();
return source.ApplyProcessor(
new DrawImageProcessor(
image,
Point.Empty,
GraphicsOptions.Default.ColorBlendingMode,
GraphicsOptions.Default.AlphaCompositionMode,
opacity));
image,
Point.Empty,
options.ColorBlendingMode,
options.AlphaCompositionMode,
opacity));
}

/// <summary>
/// Draws the given image together with the current one by blending their pixels.
Expand All @@ -49,7 +52,7 @@ public static IImageProcessingContext DrawImage(
image,
Point.Empty,
colorBlending,
GraphicsOptions.Default.AlphaCompositionMode,
new GraphicsOptions().AlphaCompositionMode,
opacity));

/// <summary>
Expand Down Expand Up @@ -100,14 +103,17 @@ public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image image,
Point location,
float opacity) =>
source.ApplyProcessor(
float opacity)
{
var options = new GraphicsOptions();
return source.ApplyProcessor(
new DrawImageProcessor(
image,
location,
GraphicsOptions.Default.ColorBlendingMode,
GraphicsOptions.Default.AlphaCompositionMode,
opacity));
image,
location,
options.ColorBlendingMode,
options.AlphaCompositionMode,
opacity));
}

/// <summary>
/// Draws the given image together with the current one by blending their pixels.
Expand All @@ -129,7 +135,7 @@ public static IImageProcessingContext DrawImage(
image,
location,
colorBlending,
GraphicsOptions.Default.AlphaCompositionMode,
new GraphicsOptions().AlphaCompositionMode,
opacity));

/// <summary>
Expand Down Expand Up @@ -172,4 +178,4 @@ public static IImageProcessingContext DrawImage(
options.AlphaCompositionMode,
options.BlendPercentage));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static IImageProcessingContext Draw(
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext
Draw(this IImageProcessingContext source, IPen pen, IPathCollection paths) =>
source.Draw(GraphicsOptions.Default, pen, paths);
source.Draw(new GraphicsOptions(), pen, paths);

/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static IImageProcessingContext Draw(
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext Draw(this IImageProcessingContext source, IPen pen, IPath path) =>
source.Draw(GraphicsOptions.Default, pen, path);
source.Draw(new GraphicsOptions(), pen, path);

/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
Expand Down
Loading