diff --git a/.editorconfig b/.editorconfig
index 8f0e28eec6..b0d0662bf8 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -79,6 +79,7 @@ dotnet_naming_rule.private_and_internal_fields_should_be_camel_case.symbols = pr
dotnet_naming_rule.public_and_protected_declarations_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.public_and_protected_declarations_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.public_and_protected_declarations_should_be_pascal_case.symbols = public_and_protected_declarations
+dotnet_naming_symbols.public_and_protected_declarations.applicable_kinds = method, field, event, property
dotnet_naming_rule.static_readonly_declarations_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.static_readonly_declarations_should_be_pascal_case.style = pascal_case
@@ -322,11 +323,11 @@ csharp_space_between_square_brackets = false
# suggest conditional delegate calls,
# suggest deconstructed variable declarations,
# generate expression-bodied accessors,
-# don't generate expression-bodied constructors,
+# generate expression-bodied constructors,
# generate expression-bodied indexers,
# generate expression-bodied lambdas,
-# don't generate expression-bodied methods,
-# don't generate expression-bodied operators,
+# generate expression-bodied methods,
+# generate expression-bodied operators,
# generate expression-bodied properties,
# suggest inlined variable declarations,
# suggest local over anonymous functions,
@@ -348,11 +349,11 @@ csharp_style_conditional_delegate_call = true:suggestion
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_style_expression_bodied_accessors = true:silent
-csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_constructors = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_lambdas = true:silent
-csharp_style_expression_bodied_methods = false:silent
-csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_methods = true:silent
+csharp_style_expression_bodied_operators = true:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_inlined_variable_declaration = true:suggestion
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 01c09d2231..d45d98b393 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -29,6 +29,10 @@
* Ask any question about how to use ImageSharp in the [ImageSharp Gitter Chat Room](https://gitter.im/ImageSharp/General).
+#### Code of Conduct
+This project has adopted the code of conduct defined by the [Contributor Covenant](https://contributor-covenant.org/) to clarify expected behavior in our community.
+For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
+
And please remember. ImageSharp is the work of a very, very, small number of developers who struggle balancing time to contribute to the project with family time and work commitments. We encourage you to pitch in and help make our vision of simple accessible imageprocessing available to all. Open Source can only exist with your help.
Thanks for reading!
diff --git a/.gitmodules b/.gitmodules
index 37ef701cdf..55389121f2 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -2,6 +2,6 @@
path = tests/Images/External
url = https://github.com/SixLabors/Imagesharp.Tests.Images.git
branch = master
-[submodule "standards"]
- path = standards
- url = https://github.com/SixLabors/Standards
+[submodule "shared-infrastructure"]
+ path = shared-infrastructure
+ url = https://github.com/SixLabors/SharedInfrastructure
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000..b34bbb41a3
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,3 @@
+# Code of Conduct
+This project has adopted the code of conduct defined by the [Contributor Covenant](https://contributor-covenant.org/) to clarify expected behavior in our community.
+For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index bf004921ea..efe4cc9665 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -52,7 +52,7 @@
- $(MSBuildThisFileDirectory)standards/SixLabors.snk
+ $(MSBuildThisFileDirectory)shared-infrastructure/SixLabors.snk
Copyright © Six Labors and Contributors
strict;IOperation
true
diff --git a/Directory.Build.targets b/Directory.Build.targets
index d1183e5d46..1dc081782a 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -25,13 +25,13 @@
-
+
-
-
-
-
+
+
+
+
diff --git a/ImageSharp.sln b/ImageSharp.sln
index 1fd5e2d8b4..d4a0419eed 100644
--- a/ImageSharp.sln
+++ b/ImageSharp.sln
@@ -21,7 +21,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
LICENSE = LICENSE
README.md = README.md
run-tests.ps1 = run-tests.ps1
- stylecop.json = stylecop.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{1799C43E-5C54-4A8F-8D64-B1475241DB0D}"
diff --git a/README.md b/README.md
index 078219183e..28c3770373 100644
--- a/README.md
+++ b/README.md
@@ -63,6 +63,10 @@ The **ImageSharp** library is made up of multiple packages:
- Do you have questions? We are happy to help! Please [join our gitter channel](https://gitter.im/ImageSharp/General), or ask them on [stackoverflow](https://stackoverflow.com) using the `ImageSharp` tag. **Do not** open issues for questions!
- Please read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/master/.github/CONTRIBUTING.md) before opening issues or pull requests!
+### Code of Conduct
+This project has adopted the code of conduct defined by the [Contributor Covenant](https://contributor-covenant.org/) to clarify expected behavior in our community.
+For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
+
### API
Our API is designed to be simple to consume. Here's an example of the code required to resize an image using the default Bicubic resampler then turn the colors into their grayscale equivalent using the BT709 standard matrix.
diff --git a/shared-infrastructure b/shared-infrastructure
new file mode 160000
index 0000000000..faf84e44ec
--- /dev/null
+++ b/shared-infrastructure
@@ -0,0 +1 @@
+Subproject commit faf84e44ec90e8a42a7271bcd04fea76279efb08
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index cd3d5e8cb3..6fbbb7c916 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -18,12 +18,12 @@
- $(MSBuildThisFileDirectory)..\standards\SixLabors.ruleset
+ $(MSBuildThisFileDirectory)..\shared-infrastructure\SixLabors.ruleset
true
-
+
diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
index a092e3604b..5a53d3e78b 100644
--- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
+++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
@@ -1,4 +1,4 @@
-
+
@@ -11,6 +11,15 @@
netcoreapp2.1;netstandard1.3;netstandard2.0
+
+
+ $(DefineConstants);SUPPORTS_MATHF
+
+
+
+ $(DefineConstants);SUPPORTS_HASHCODE
+
+
diff --git a/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs b/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs
new file mode 100644
index 0000000000..7315dc5a3e
--- /dev/null
+++ b/src/ImageSharp.Drawing/Processing/PathGradientBrush.cs
@@ -0,0 +1,287 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Primitives;
+using SixLabors.Shapes;
+
+namespace SixLabors.ImageSharp.Processing
+{
+ ///
+ /// Provides an implementation of a brush for painting gradients between multiple color positions in 2D coordinates.
+ /// It works similarly with the class in System.Drawing.Drawing2D of the same name.
+ ///
+ public sealed class PathGradientBrush : IBrush
+ {
+ private readonly IList edges;
+
+ private readonly Color centerColor;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Points that constitute a polygon that represents the gradient area.
+ /// Array of colors that correspond to each point in the polygon.
+ /// Color at the center of the gradient area to which the other colors converge.
+ public PathGradientBrush(PointF[] points, Color[] colors, Color centerColor)
+ {
+ if (points == null)
+ {
+ throw new ArgumentNullException(nameof(points));
+ }
+
+ if (points.Length < 3)
+ {
+ throw new ArgumentOutOfRangeException(
+ nameof(points),
+ "There must be at least 3 lines to construct a path gradient brush.");
+ }
+
+ if (colors == null)
+ {
+ throw new ArgumentNullException(nameof(colors));
+ }
+
+ if (!colors.Any())
+ {
+ throw new ArgumentOutOfRangeException(
+ nameof(colors),
+ "One or more color is needed to construct a path gradient brush.");
+ }
+
+ int size = points.Length;
+
+ var lines = new ILineSegment[size];
+
+ for (int i = 0; i < size; i++)
+ {
+ lines[i] = new LinearLineSegment(points[i % size], points[(i + 1) % size]);
+ }
+
+ this.centerColor = centerColor;
+
+ Color ColorAt(int index) => colors[index % colors.Length];
+
+ this.edges = lines.Select(s => new Path(s))
+ .Select((path, i) => new Edge(path, ColorAt(i), ColorAt(i + 1))).ToList();
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Points that constitute a polygon that represents the gradient area.
+ /// Array of colors that correspond to each point in the polygon.
+ public PathGradientBrush(PointF[] points, Color[] colors)
+ : this(points, colors, CalculateCenterColor(colors))
+ {
+ }
+
+ ///
+ public BrushApplicator CreateApplicator(
+ ImageFrame source,
+ RectangleF region,
+ GraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return new PathGradientBrushApplicator(source, this.edges, this.centerColor, options);
+ }
+
+ private static Color CalculateCenterColor(Color[] colors)
+ {
+ if (colors == null)
+ {
+ throw new ArgumentNullException(nameof(colors));
+ }
+
+ if (!colors.Any())
+ {
+ throw new ArgumentOutOfRangeException(
+ nameof(colors),
+ "One or more color is needed to construct a path gradient brush.");
+ }
+
+ return new Color(colors.Select(c => c.ToVector4()).Aggregate((p1, p2) => p1 + p2) / colors.Length);
+ }
+
+ private static float DistanceBetween(PointF p1, PointF p2) => ((Vector2)(p2 - p1)).Length();
+
+ private struct Intersection
+ {
+ public Intersection(PointF point, float distance)
+ {
+ this.Point = point;
+ this.Distance = distance;
+ }
+
+ public PointF Point { get; }
+
+ public float Distance { get; }
+ }
+
+ ///
+ /// An edge of the polygon that represents the gradient area.
+ ///
+ private class Edge
+ {
+ private readonly Path path;
+
+ private readonly float length;
+
+ private readonly PointF[] buffer;
+
+ public Edge(Path path, Color startColor, Color endColor)
+ {
+ this.path = path;
+
+ Vector2[] points = path.LineSegments.SelectMany(s => s.Flatten()).Select(p => (Vector2)p).ToArray();
+
+ this.Start = points.First();
+ this.StartColor = startColor.ToVector4();
+
+ this.End = points.Last();
+ this.EndColor = endColor.ToVector4();
+
+ this.length = DistanceBetween(this.End, this.Start);
+ this.buffer = new PointF[this.path.MaxIntersections];
+ }
+
+ public PointF Start { get; }
+
+ public Vector4 StartColor { get; }
+
+ public PointF End { get; }
+
+ public Vector4 EndColor { get; }
+
+ public Intersection? FindIntersection(PointF start, PointF end)
+ {
+ int intersections = this.path.FindIntersections(start, end, this.buffer);
+
+ if (intersections == 0)
+ {
+ return null;
+ }
+
+ return this.buffer.Take(intersections)
+ .Select(p => new Intersection(point: p, distance: ((Vector2)(p - start)).LengthSquared()))
+ .Aggregate((min, current) => min.Distance > current.Distance ? current : min);
+ }
+
+ public Vector4 ColorAt(float distance)
+ {
+ float ratio = this.length > 0 ? distance / this.length : 0;
+
+ return Vector4.Lerp(this.StartColor, this.EndColor, ratio);
+ }
+
+ public Vector4 ColorAt(PointF point) => this.ColorAt(DistanceBetween(point, this.Start));
+ }
+
+ ///
+ /// The path gradient brush applicator.
+ ///
+ private class PathGradientBrushApplicator : BrushApplicator
+ where TPixel : struct, IPixel
+ {
+ private readonly PointF center;
+
+ private readonly Vector4 centerColor;
+
+ private readonly float maxDistance;
+
+ private readonly IList edges;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source image.
+ /// Edges of the polygon.
+ /// Color at the center of the gradient area to which the other colors converge.
+ /// The options.
+ public PathGradientBrushApplicator(
+ ImageFrame source,
+ IList edges,
+ Color centerColor,
+ GraphicsOptions options)
+ : base(source, options)
+ {
+ this.edges = edges;
+
+ PointF[] points = edges.Select(s => s.Start).ToArray();
+
+ this.center = points.Aggregate((p1, p2) => p1 + p2) / edges.Count;
+ this.centerColor = centerColor.ToVector4();
+
+ this.maxDistance = points.Select(p => (Vector2)(p - this.center)).Select(d => d.Length()).Max();
+ }
+
+ ///
+ internal override TPixel this[int x, int y]
+ {
+ get
+ {
+ var point = new PointF(x, y);
+
+ if (point == this.center)
+ {
+ return new Color(this.centerColor).ToPixel();
+ }
+
+ Vector2 direction = Vector2.Normalize(point - this.center);
+
+ PointF end = point + (PointF)(direction * this.maxDistance);
+
+ (Edge edge, Intersection? info) = this.FindIntersection(point, end);
+
+ if (!info.HasValue)
+ {
+ return Color.Transparent.ToPixel();
+ }
+
+ PointF intersection = info.Value.Point;
+
+ Vector4 edgeColor = edge.ColorAt(intersection);
+
+ float length = DistanceBetween(intersection, this.center);
+ float ratio = length > 0 ? DistanceBetween(intersection, point) / length : 0;
+
+ Vector4 color = Vector4.Lerp(edgeColor, this.centerColor, ratio);
+
+ return new Color(color).ToPixel();
+ }
+ }
+
+ private (Edge edge, Intersection? info) FindIntersection(PointF start, PointF end)
+ {
+ (Edge edge, Intersection? info) closest = default;
+
+ foreach (Edge edge in this.edges)
+ {
+ Intersection? intersection = edge.FindIntersection(start, end);
+
+ if (!intersection.HasValue)
+ {
+ continue;
+ }
+
+ if (closest.info == null || closest.info.Value.Distance > intersection.Value.Distance)
+ {
+ closest = (edge, intersection);
+ }
+ }
+
+ return closest;
+ }
+
+ ///
+ public override void Dispose()
+ {
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush.cs b/src/ImageSharp.Drawing/Processing/PatternBrush.cs
index a7a6785b92..1999af8a39 100644
--- a/src/ImageSharp.Drawing/Processing/PatternBrush.cs
+++ b/src/ImageSharp.Drawing/Processing/PatternBrush.cs
@@ -99,7 +99,6 @@ namespace SixLabors.ImageSharp.Processing
new PatternBrushApplicator(
source,
this.pattern.ToPixelMatrix(source.Configuration),
- this.patternVector,
options);
///
@@ -112,20 +111,17 @@ namespace SixLabors.ImageSharp.Processing
/// The pattern.
///
private readonly DenseMatrix pattern;
- private readonly DenseMatrix patternVector;
///
/// Initializes a new instance of the class.
///
/// The source image.
/// The pattern.
- /// The patternVector.
/// The options
- public PatternBrushApplicator(ImageFrame source, in DenseMatrix pattern, DenseMatrix patternVector, GraphicsOptions options)
+ public PatternBrushApplicator(ImageFrame source, in DenseMatrix pattern, GraphicsOptions options)
: base(source, options)
{
this.pattern = pattern;
- this.patternVector = patternVector;
}
///
diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs
index 7ec359220e..e217fd9a6c 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs
@@ -1,6 +1,7 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -59,10 +60,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
public float Opacity { get; }
///
- public IImageProcessor CreatePixelSpecificProcessor()
+ public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle)
where TPixelBg : struct, IPixel
{
- var visitor = new ProcessorFactoryVisitor(this);
+ var visitor = new ProcessorFactoryVisitor(this, source, sourceRectangle);
this.Image.AcceptVisitor(visitor);
return visitor.Result;
}
@@ -71,10 +72,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
where TPixelBg : struct, IPixel
{
private readonly DrawImageProcessor definition;
+ private readonly Image source;
+ private readonly Rectangle sourceRectangle;
- public ProcessorFactoryVisitor(DrawImageProcessor definition)
+ public ProcessorFactoryVisitor(DrawImageProcessor definition, Image source, Rectangle sourceRectangle)
{
this.definition = definition;
+ this.source = source;
+ this.sourceRectangle = sourceRectangle;
}
public IImageProcessor Result { get; private set; }
@@ -84,6 +89,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
this.Result = new DrawImageProcessor(
image,
+ this.source,
+ this.sourceRectangle,
this.definition.Location,
this.definition.ColorBlendingMode,
this.definition.AlphaCompositionMode,
@@ -91,4 +98,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
index 21599bf787..eab6b2f4a1 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
@@ -4,7 +4,7 @@
using System;
using SixLabors.ImageSharp.Advanced;
-using SixLabors.ImageSharp.ParallelUtils;
+using SixLabors.ImageSharp.Advanced.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -20,19 +20,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
where TPixelFg : struct, IPixel
{
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- /// The image to blend with the currently processing image.
+ /// The foreground to blend with the currently processing image.
+ /// The source for the current processor instance.
+ /// The source area to process for the current processor instance.
/// The location to draw the blended image.
/// The blending mode to use when drawing the image.
/// The Alpha blending mode to use when drawing the image.
/// The opacity of the image to blend. Must be between 0 and 1.
public DrawImageProcessor(
Image image,
+ Image source,
+ Rectangle sourceRectangle,
Point location,
PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode,
float opacity)
+ : base(source, sourceRectangle)
{
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
@@ -63,11 +68,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
public Point Location { get; }
///
- protected override void OnFrameApply(
- ImageFrame source,
- Rectangle sourceRectangle,
- Configuration configuration)
+ protected override void OnFrameApply(ImageFrame source)
{
+ Rectangle sourceRectangle = this.SourceRectangle;
+ Configuration configuration = this.Configuration;
+
Image targetImage = this.Image;
PixelBlender blender = this.Blender;
int locationY = this.Location.Y;
@@ -86,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
- // not a valid operation because rectangle does not overlap with this image.
+ // Not a valid operation because rectangle does not overlap with this image.
if (workingRect.Width <= 0 || workingRect.Height <= 0)
{
throw new ImageProcessingException(
@@ -97,15 +102,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
workingRect,
configuration,
rows =>
+ {
+ for (int y = rows.Min; y < rows.Max; y++)
{
- for (int y = rows.Min; y < rows.Max; y++)
- {
- Span background = source.GetPixelRowSpan(y).Slice(minX, width);
- Span foreground =
- targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
- blender.Blend(configuration, background, background, foreground, this.Opacity);
- }
- });
+ Span background = source.GetPixelRowSpan(y).Slice(minX, width);
+ Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
+ blender.Blend(configuration, background, background, foreground, this.Opacity);
+ }
+ });
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs
index 81880308cf..1d3cf35576 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
@@ -33,10 +34,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
public GraphicsOptions Options { get; }
///
- public IImageProcessor CreatePixelSpecificProcessor()
+ public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle)
where TPixel : struct, IPixel
{
- return new FillProcessor(this);
+ return new FillProcessor(this, source, sourceRectangle);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs
index 68aef82e2d..4e052818da 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs
@@ -5,8 +5,8 @@ using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Advanced.ParallelUtils;
using SixLabors.ImageSharp.Memory;
-using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -21,14 +21,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
private readonly FillProcessor definition;
- public FillProcessor(FillProcessor definition)
+ public FillProcessor(FillProcessor definition, Image source, Rectangle sourceRectangle)
+ : base(source, sourceRectangle)
{
this.definition = definition;
}
///
- protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
+ protected override void OnFrameApply(ImageFrame source)
{
+ Rectangle sourceRectangle = this.SourceRectangle;
+ Configuration configuration = this.Configuration;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int startY = sourceRectangle.Y;
@@ -42,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
int width = maxX - minX;
- var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
+ Rectangle workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
IBrush brush = this.definition.Brush;
GraphicsOptions options = this.definition.Options;
@@ -50,9 +53,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
// If there's no reason for blending, then avoid it.
if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush))
{
- ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings().MultiplyMinimumPixelsPerTask(4);
+ ParallelExecutionSettings parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration)
+ .MultiplyMinimumPixelsPerTask(4);
- TPixel colorPixel = solidBrush.Color.ToPixel();
+ var colorPixel = solidBrush.Color.ToPixel();
ParallelHelper.IterateRows(
workingRect,
@@ -115,4 +119,4 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
return this.definition.Options.IsOpaqueColorWithoutBlending(solidBrush.Color);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
index 000fa260ab..2318f3168b 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
@@ -1,8 +1,9 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
+using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
@@ -41,10 +42,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
public GraphicsOptions Options { get; }
///
- public IImageProcessor CreatePixelSpecificProcessor()
+ public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle)
where TPixel : struct, IPixel
{
- return new FillRegionProcessor(this);
+ return new FillRegionProcessor(this, source, sourceRectangle);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs
index 347d243ae7..45d5015ae0 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs
@@ -23,14 +23,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
private readonly FillRegionProcessor definition;
- public FillRegionProcessor(FillRegionProcessor definition)
+ public FillRegionProcessor(FillRegionProcessor definition, Image source, Rectangle sourceRectangle)
+ : base(source, sourceRectangle)
{
this.definition = definition;
}
///
- protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
+ protected override void OnFrameApply(ImageFrame source)
{
+ Configuration configuration = this.Configuration;
GraphicsOptions options = this.definition.Options;
IBrush brush = this.definition.Brush;
Region region = this.definition.Region;
diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
index 40621ce997..775cf55abf 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
@@ -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;
@@ -72,10 +72,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
public PointF Location { get; }
///
- public IImageProcessor CreatePixelSpecificProcessor()
+ public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle)
where TPixel : struct, IPixel
{
- return new DrawTextProcessor(this);
+ return new DrawTextProcessor(this, source, sourceRectangle);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs
index b3c336c885..ea042635dd 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs
@@ -27,7 +27,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
private readonly DrawTextProcessor definition;
- public DrawTextProcessor(DrawTextProcessor definition)
+ public DrawTextProcessor(DrawTextProcessor definition, Image source, Rectangle sourceRectangle)
+ : base(source, sourceRectangle)
{
this.definition = definition;
}
@@ -44,35 +45,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
private IBrush Brush => this.definition.Brush;
- protected override void BeforeImageApply(Image source, Rectangle sourceRectangle)
+ protected override void BeforeImageApply()
{
- base.BeforeImageApply(source, sourceRectangle);
+ base.BeforeImageApply();
// do everything at the image level as we are delegating the processing down to other processors
var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location)
- {
- ApplyKerning = this.Options.ApplyKerning,
- TabWidth = this.Options.TabWidth,
- WrappingWidth = this.Options.WrapTextWidth,
- HorizontalAlignment = this.Options.HorizontalAlignment,
- VerticalAlignment = this.Options.VerticalAlignment
- };
-
- this.textRenderer = new CachingGlyphRenderer(source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null);
+ {
+ ApplyKerning = this.Options.ApplyKerning,
+ TabWidth = this.Options.TabWidth,
+ WrappingWidth = this.Options.WrapTextWidth,
+ HorizontalAlignment = this.Options.HorizontalAlignment,
+ VerticalAlignment = this.Options.VerticalAlignment
+ };
+
+ this.textRenderer = new CachingGlyphRenderer(this.Source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null);
this.textRenderer.Options = (GraphicsOptions)this.Options;
var renderer = new TextRenderer(this.textRenderer);
renderer.RenderText(this.Text, style);
}
- protected override void AfterImageApply(Image source, Rectangle sourceRectangle)
+ protected override void AfterImageApply()
{
- base.AfterImageApply(source, sourceRectangle);
+ base.AfterImageApply();
this.textRenderer?.Dispose();
this.textRenderer = null;
}
///
- protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
+ protected override void OnFrameApply(ImageFrame source)
{
// this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome
Draw(this.textRenderer.FillOperations, this.Brush);
@@ -82,33 +83,38 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
{
if (operations?.Count > 0)
{
- using (BrushApplicator app = brush.CreateApplicator(source, sourceRectangle, this.textRenderer.Options))
+ using (BrushApplicator app = brush.CreateApplicator(source, this.SourceRectangle, this.textRenderer.Options))
{
foreach (DrawingOperation operation in operations)
{
Buffer2D buffer = operation.Map;
int startY = operation.Location.Y;
int startX = operation.Location.X;
- int offSetSpan = 0;
+ int offsetSpan = 0;
if (startX < 0)
{
- offSetSpan = -startX;
+ offsetSpan = -startX;
startX = 0;
}
- int fistRow = 0;
+ if (startX >= source.Width)
+ {
+ continue;
+ }
+
+ int firstRow = 0;
if (startY < 0)
{
- fistRow = -startY;
+ firstRow = -startY;
}
int maxHeight = source.Height - startY;
int end = Math.Min(operation.Map.Height, maxHeight);
- for (int row = fistRow; row < end; row++)
+ for (int row = firstRow; row < end; row++)
{
int y = startY + row;
- Span span = buffer.GetRowSpan(row).Slice(offSetSpan);
+ Span span = buffer.GetRowSpan(row).Slice(offsetSpan);
app.Apply(span, startX, y);
}
}
@@ -279,19 +285,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
if (this.renderFill)
{
this.FillOperations.Add(new DrawingOperation
- {
- Location = this.currentRenderPosition,
- Map = renderData.FillMap
- });
+ {
+ Location = this.currentRenderPosition,
+ Map = renderData.FillMap
+ });
}
if (this.renderOutline)
{
this.OutlineOperations.Add(new DrawingOperation
- {
- Location = this.currentRenderPosition,
- Map = renderData.OutlineMap
- });
+ {
+ Location = this.currentRenderPosition,
+ Map = renderData.OutlineMap
+ });
}
}
diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
index 4b1d4222cb..22e6d47e9a 100644
--- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
+++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
@@ -15,6 +15,15 @@ namespace SixLabors.ImageSharp.Advanced
///
public static class AdvancedImageExtensions
{
+ ///
+ /// Accepts a to implement a double-dispatch pattern in order to
+ /// apply pixel-specific operations on non-generic instances
+ ///
+ /// The source.
+ /// The visitor.
+ public static void AcceptVisitor(this Image source, IImageVisitor visitor)
+ => source.Accept(visitor);
+
///
/// Gets the configuration for the image.
///
diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs
index 439ea6de0c..5d172d93f7 100644
--- a/src/ImageSharp/Advanced/AotCompilerTools.cs
+++ b/src/ImageSharp/Advanced/AotCompilerTools.cs
@@ -2,13 +2,12 @@
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
+using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
-using SixLabors.ImageSharp.Processing.Processors.Transforms;
namespace SixLabors.ImageSharp.Advanced
{
@@ -81,9 +80,8 @@ namespace SixLabors.ImageSharp.Advanced
AotCompileWuQuantizer();
AotCompileDithering();
AotCompilePixelOperations();
- AotCompileResizeOperations();
- System.Runtime.CompilerServices.Unsafe.SizeOf();
+ Unsafe.SizeOf();
AotCodec(new Formats.Png.PngDecoder(), new Formats.Png.PngEncoder());
AotCodec(new Formats.Bmp.BmpDecoder(), new Formats.Bmp.BmpEncoder());
@@ -107,8 +105,10 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileOctreeQuantizer()
where TPixel : struct, IPixel
{
- var test = new OctreeFrameQuantizer(new OctreeQuantizer(false));
- test.AotGetPalette();
+ using (var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)))
+ {
+ test.AotGetPalette();
+ }
}
///
@@ -118,9 +118,11 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileWuQuantizer()
where TPixel : struct, IPixel
{
- var test = new WuFrameQuantizer(Configuration.Default.MemoryAllocator, new WuQuantizer(false));
- test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1));
- test.AotGetPalette();
+ using (var test = new WuFrameQuantizer(Configuration.Default.MemoryAllocator, new WuQuantizer(false)))
+ {
+ test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1));
+ test.AotGetPalette();
+ }
}
///
@@ -132,7 +134,10 @@ namespace SixLabors.ImageSharp.Advanced
{
var test = new FloydSteinbergDiffuser();
TPixel pixel = default;
- test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0);
+ using (var image = new ImageFrame(Configuration.Default, 1, 1))
+ {
+ test.Dither(image, pixel, pixel, 0, 0, 0, 0, 0);
+ }
}
///
@@ -171,17 +176,5 @@ namespace SixLabors.ImageSharp.Advanced
var pixelOp = new PixelOperations();
pixelOp.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.Clear);
}
-
- ///
- /// This method pre-seeds the ResizeProcessor for the AoT compiler on iOS.
- ///
- /// The pixel format.
- private static void AotCompileResizeOperations()
- where TPixel : struct, IPixel
- {
- var resizeProcessor = new ResizeProcessor(new ResizeOptions(), default);
- var genericResizeProcessor = new ResizeProcessor((ResizeProcessor)resizeProcessor.CreatePixelSpecificProcessor());
- genericResizeProcessor.AotCreateDestination(new Image(0, 0), default);
- }
}
}
diff --git a/src/ImageSharp/IImageVisitor.cs b/src/ImageSharp/Advanced/IImageVisitor.cs
similarity index 64%
rename from src/ImageSharp/IImageVisitor.cs
rename to src/ImageSharp/Advanced/IImageVisitor.cs
index 971c4d37cb..ba8b13e2e8 100644
--- a/src/ImageSharp/IImageVisitor.cs
+++ b/src/ImageSharp/Advanced/IImageVisitor.cs
@@ -3,13 +3,13 @@
using SixLabors.ImageSharp.PixelFormats;
-namespace SixLabors.ImageSharp
+namespace SixLabors.ImageSharp.Advanced
{
///
- /// A visitor to implement double-dispatch pattern in order to apply pixel-specific operations
- /// on non-generic instances. The operation is dispatched by .
+ /// A visitor to implement a double-dispatch pattern in order to apply pixel-specific operations
+ /// on non-generic instances.
///
- internal interface IImageVisitor
+ public interface IImageVisitor
{
///
/// Provides a pixel-specific implementation for a given operation.
@@ -19,4 +19,4 @@ namespace SixLabors.ImageSharp
void Visit(Image image)
where TPixel : struct, IPixel;
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs b/src/ImageSharp/Advanced/ParallelUtils/ParallelExecutionSettings.cs
similarity index 55%
rename from src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs
rename to src/ImageSharp/Advanced/ParallelUtils/ParallelExecutionSettings.cs
index 40163bc789..431656ef91 100644
--- a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs
+++ b/src/ImageSharp/Advanced/ParallelUtils/ParallelExecutionSettings.cs
@@ -1,16 +1,17 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
using System.Threading.Tasks;
using SixLabors.Memory;
-namespace SixLabors.ImageSharp.ParallelUtils
+namespace SixLabors.ImageSharp.Advanced.ParallelUtils
{
///
/// Defines execution settings for methods in .
///
- internal readonly struct ParallelExecutionSettings
+ public readonly struct ParallelExecutionSettings
{
///
/// Default value for .
@@ -20,11 +21,24 @@ namespace SixLabors.ImageSharp.ParallelUtils
///
/// Initializes a new instance of the struct.
///
+ /// The value used for initializing when using TPL.
+ /// The value for .
+ /// The .
public ParallelExecutionSettings(
int maxDegreeOfParallelism,
int minimumPixelsProcessedPerTask,
MemoryAllocator memoryAllocator)
{
+ // Shall be compatible with ParallelOptions.MaxDegreeOfParallelism:
+ // https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.paralleloptions.maxdegreeofparallelism
+ if (maxDegreeOfParallelism == 0 || maxDegreeOfParallelism < -1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(maxDegreeOfParallelism));
+ }
+
+ Guard.MustBeGreaterThan(minimumPixelsProcessedPerTask, 0, nameof(minimumPixelsProcessedPerTask));
+ Guard.NotNull(memoryAllocator, nameof(memoryAllocator));
+
this.MaxDegreeOfParallelism = maxDegreeOfParallelism;
this.MinimumPixelsProcessedPerTask = minimumPixelsProcessedPerTask;
this.MemoryAllocator = memoryAllocator;
@@ -33,13 +47,15 @@ namespace SixLabors.ImageSharp.ParallelUtils
///
/// Initializes a new instance of the struct.
///
+ /// The value used for initializing when using TPL.
+ /// The .
public ParallelExecutionSettings(int maxDegreeOfParallelism, MemoryAllocator memoryAllocator)
: this(maxDegreeOfParallelism, DefaultMinimumPixelsProcessedPerTask, memoryAllocator)
{
}
///
- /// Gets the MemoryAllocator
+ /// Gets the .
///
public MemoryAllocator MemoryAllocator { get; }
@@ -60,12 +76,26 @@ namespace SixLabors.ImageSharp.ParallelUtils
/// Creates a new instance of
/// having multiplied by
///
+ /// The value to multiply with.
+ /// The modified .
public ParallelExecutionSettings MultiplyMinimumPixelsPerTask(int multiplier)
{
+ Guard.MustBeGreaterThan(multiplier, 0, nameof(multiplier));
+
return new ParallelExecutionSettings(
this.MaxDegreeOfParallelism,
this.MinimumPixelsProcessedPerTask * multiplier,
this.MemoryAllocator);
}
+
+ ///
+ /// Get the default for a
+ ///
+ /// The .
+ /// The .
+ public static ParallelExecutionSettings FromConfiguration(Configuration configuration)
+ {
+ return new ParallelExecutionSettings(configuration.MaxDegreeOfParallelism, configuration.MemoryAllocator);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Advanced/ParallelUtils/ParallelHelper.cs
similarity index 77%
rename from src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs
rename to src/ImageSharp/Advanced/ParallelUtils/ParallelHelper.cs
index 1e7299720d..c56337bffe 100644
--- a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs
+++ b/src/ImageSharp/Advanced/ParallelUtils/ParallelHelper.cs
@@ -10,29 +10,25 @@ using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
using SixLabors.Primitives;
-namespace SixLabors.ImageSharp.ParallelUtils
+namespace SixLabors.ImageSharp.Advanced.ParallelUtils
{
///
/// Utility methods for batched processing of pixel row intervals.
- /// Parallel execution is optimized for image processing.
- /// Use this instead of direct calls!
+ /// Parallel execution is optimized for image processing based on values defined
+ /// or .
+ /// Using this class is preferred over direct usage of utility methods.
///
- internal static class ParallelHelper
+ public static class ParallelHelper
{
- ///
- /// Get the default for a
- ///
- public static ParallelExecutionSettings GetParallelSettings(this Configuration configuration)
- {
- return new ParallelExecutionSettings(configuration.MaxDegreeOfParallelism, configuration.MemoryAllocator);
- }
-
///
/// Iterate through the rows of a rectangle in optimized batches defined by -s.
///
+ /// The .
+ /// The to get the parallel settings from.
+ /// The method body defining the iteration logic on a single .
public static void IterateRows(Rectangle rectangle, Configuration configuration, Action body)
{
- ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings();
+ ParallelExecutionSettings parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
IterateRows(rectangle, parallelSettings, body);
}
@@ -40,6 +36,9 @@ namespace SixLabors.ImageSharp.ParallelUtils
///
/// Iterate through the rows of a rectangle in optimized batches defined by -s.
///
+ /// The .
+ /// The .
+ /// The method body defining the iteration logic on a single .
public static void IterateRows(
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
@@ -47,7 +46,9 @@ namespace SixLabors.ImageSharp.ParallelUtils
{
ValidateRectangle(rectangle);
- int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask);
+ int maxSteps = DivideCeil(
+ rectangle.Width * rectangle.Height,
+ parallelSettings.MinimumPixelsProcessedPerTask);
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
@@ -81,7 +82,7 @@ namespace SixLabors.ImageSharp.ParallelUtils
/// Iterate through the rows of a rectangle in optimized batches defined by -s
/// instantiating a temporary buffer for each invocation.
///
- public static void IterateRowsWithTempBuffer(
+ internal static void IterateRowsWithTempBuffer(
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
Action> body)
@@ -133,13 +134,13 @@ namespace SixLabors.ImageSharp.ParallelUtils
/// Iterate through the rows of a rectangle in optimized batches defined by -s
/// instantiating a temporary buffer for each invocation.
///
- public static void IterateRowsWithTempBuffer(
+ internal static void IterateRowsWithTempBuffer(
Rectangle rectangle,
Configuration configuration,
Action> body)
where T : unmanaged
{
- IterateRowsWithTempBuffer(rectangle, configuration.GetParallelSettings(), body);
+ IterateRowsWithTempBuffer(rectangle, ParallelExecutionSettings.FromConfiguration(configuration), body);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/src/ImageSharp/Color/Color.NamedColors.cs b/src/ImageSharp/Color/Color.NamedColors.cs
index 8811516c1c..0575a3e99e 100644
--- a/src/ImageSharp/Color/Color.NamedColors.cs
+++ b/src/ImageSharp/Color/Color.NamedColors.cs
@@ -174,9 +174,9 @@ namespace SixLabors.ImageSharp
public static readonly Color DarkSalmon = FromRgba(233, 150, 122, 255);
///
- /// Represents a matching the W3C definition that has an hex value of #8FBC8B.
+ /// Represents a matching the W3C definition that has an hex value of #8FBC8F.
///
- public static readonly Color DarkSeaGreen = FromRgba(143, 188, 139, 255);
+ public static readonly Color DarkSeaGreen = FromRgba(143, 188, 143, 255);
///
/// Represents a matching the W3C definition that has an hex value of #483D8B.
@@ -718,4 +718,4 @@ namespace SixLabors.ImageSharp
///
public static readonly Color YellowGreen = FromRgba(154, 205, 50, 255);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs
index 4bdbe088ca..76f3995171 100644
--- a/src/ImageSharp/Color/Color.cs
+++ b/src/ImageSharp/Color/Color.cs
@@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(InliningOptions.ShortMethod)]
public static Color FromHex(string hex)
{
- Rgba32 rgba = Rgba32.FromHex(hex);
+ var rgba = Rgba32.FromHex(hex);
return new Color(rgba);
}
@@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp
where TPixel : struct, IPixel
{
ReadOnlySpan rgba64Span = MemoryMarshal.Cast(source);
- PixelOperations.Instance.FromRgba64(Configuration.Default, rgba64Span, destination);
+ PixelOperations.Instance.FromRgba64(configuration, rgba64Span, destination);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs
index 761313b7e0..97465e526a 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs
@@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
}
else
{
- s = chroma / (2F - chroma);
+ s = chroma / (2F - max - min);
}
return new Hsl(h, s, l);
@@ -157,4 +157,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
return value;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Common/Exceptions/UnknownImageFormatException.cs b/src/ImageSharp/Common/Exceptions/UnknownImageFormatException.cs
index fa13700787..82aa8cf09f 100644
--- a/src/ImageSharp/Common/Exceptions/UnknownImageFormatException.cs
+++ b/src/ImageSharp/Common/Exceptions/UnknownImageFormatException.cs
@@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System;
-
namespace SixLabors.ImageSharp
{
///
@@ -20,17 +18,5 @@ namespace SixLabors.ImageSharp
: base(errorMessage)
{
}
-
- ///
- /// Initializes a new instance of the class with a specified
- /// error message and the exception that is the cause of this exception.
- ///
- /// The error message that explains the reason for this exception.
- /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic)
- /// if no inner exception is specified.
- public UnknownImageFormatException(string errorMessage, Exception innerException)
- : base(errorMessage, innerException)
- {
- }
}
}
diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs
index 43eebeac87..356dd419b5 100644
--- a/src/ImageSharp/Common/Helpers/DebugGuard.cs
+++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs
@@ -1,168 +1,17 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
// TODO: These should just call the guard equivalents
-namespace SixLabors.ImageSharp
+namespace SixLabors
{
///
/// Provides methods to protect against invalid parameters for a DEBUG build.
///
- [DebuggerStepThrough]
- internal static class DebugGuard
+ internal static partial class DebugGuard
{
- ///
- /// Verifies, that the method parameter with specified object value is not null
- /// and throws an exception if it is found to be so.
- ///
- /// The target object, which cannot be null.
- /// The name of the parameter that is to be checked.
- /// is null
- [Conditional("DEBUG")]
- public static void NotNull(T value, string parameterName)
- where T : class
- {
- if (value is null)
- {
- throw new ArgumentNullException(parameterName);
- }
- }
-
- ///
- /// Verifies that the specified value is less than a maximum value
- /// and throws an exception if it is not.
- ///
- /// The target value, which should be validated.
- /// The maximum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is greater than the maximum value.
- ///
- [Conditional("DEBUG")]
- public static void MustBeLessThan(TValue value, TValue max, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(max) >= 0)
- {
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than {max}.");
- }
- }
-
- ///
- /// Verifies that the specified value is less than or equal to a maximum value
- /// and throws an exception if it is not.
- ///
- /// The target value, which should be validated.
- /// The maximum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is greater than the maximum value.
- ///
- [Conditional("DEBUG")]
- public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(max) > 0)
- {
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than or equal to {max}.");
- }
- }
-
- ///
- /// Verifies that the specified value is greater than a minimum value
- /// and throws an exception if it is not.
- ///
- /// The target value, which should be validated.
- /// The minimum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is less than the minimum value.
- ///
- [Conditional("DEBUG")]
- public static void MustBeGreaterThan(TValue value, TValue min, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(min) <= 0)
- {
- throw new ArgumentOutOfRangeException(
- parameterName,
- $"Value must be greater than {min}.");
- }
- }
-
- ///
- /// Verifies that the specified value is greater than or equal to a minimum value
- /// and throws an exception if it is not.
- ///
- /// The target value, which should be validated.
- /// The minimum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is less than the minimum value.
- ///
- [Conditional("DEBUG")]
- public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(min) < 0)
- {
- throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than or equal to {min}.");
- }
- }
-
- ///
- /// Verifies that the specified value is greater than or equal to a minimum value and less than
- /// or equal to a maximum value and throws an exception if it is not.
- ///
- /// The target value, which should be validated.
- /// The minimum value.
- /// The maximum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is less than the minimum value of greater than the maximum value.
- ///
- [Conditional("DEBUG")]
- public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0)
- {
- throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}.");
- }
- }
-
- ///
- /// Verifies, that the method parameter with specified target value is true
- /// and throws an exception if it is found to be so.
- ///
- ///
- /// The target value, which cannot be false.
- ///
- ///
- /// The name of the parameter that is to be checked.
- ///
- ///
- /// The error message, if any to add to the exception.
- ///
- ///
- /// is false
- ///
- [Conditional("DEBUG")]
- public static void IsTrue(bool target, string parameterName, string message)
- {
- if (!target)
- {
- throw new ArgumentException(message, parameterName);
- }
- }
-
///
/// Verifies whether a specific condition is met, throwing an exception if it's false.
///
@@ -177,25 +26,6 @@ namespace SixLabors.ImageSharp
}
}
- ///
- /// Verifies, that the method parameter with specified target value is false
- /// and throws an exception if it is found to be so.
- ///
- /// The target value, which cannot be true.
- /// The name of the parameter that is to be checked.
- /// The error message, if any to add to the exception.
- ///
- /// is true
- ///
- [Conditional("DEBUG")]
- public static void IsFalse(bool target, string parameterName, string message)
- {
- if (target)
- {
- throw new ArgumentException(message, parameterName);
- }
- }
-
///
/// Verifies, that the target span is of same size than the 'other' span.
///
@@ -236,4 +66,4 @@ namespace SixLabors.ImageSharp
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs
deleted file mode 100644
index 7dc683c37f..0000000000
--- a/src/ImageSharp/Common/Helpers/Guard.cs
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-
-namespace SixLabors.ImageSharp
-{
- ///
- /// Provides methods to protect against invalid parameters.
- ///
- [DebuggerStepThrough]
- internal static class Guard
- {
- ///
- /// Ensures that the value is not null.
- ///
- /// The target object, which cannot be null.
- /// The name of the parameter that is to be checked.
- /// is null
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void NotNull(T value, string parameterName)
- where T : class
- {
- if (value is null)
- {
- ThrowArgumentNullException(parameterName);
- }
- }
-
- ///
- /// Ensures that the target value is not null, empty, or whitespace.
- ///
- /// The target string, which should be checked against being null or empty.
- /// Name of the parameter.
- /// is null.
- /// is empty or contains only blanks.
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void NotNullOrWhiteSpace(string value, string parameterName)
- {
- if (value is null)
- {
- ThrowArgumentNullException(parameterName);
- }
-
- if (string.IsNullOrWhiteSpace(value))
- {
- ThrowArgumentException("Must not be empty or whitespace.", parameterName);
- }
- }
-
- ///
- /// Ensures that the specified value is less than a maximum value.
- ///
- /// The target value, which should be validated.
- /// The maximum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is greater than the maximum value.
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void MustBeLessThan(TValue value, TValue max, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(max) >= 0)
- {
- ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}.");
- }
- }
-
- ///
- /// Verifies that the specified value is less than or equal to a maximum value
- /// and throws an exception if it is not.
- ///
- /// The target value, which should be validated.
- /// The maximum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is greater than the maximum value.
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(max) > 0)
- {
- ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}.");
- }
- }
-
- ///
- /// Verifies that the specified value is greater than a minimum value
- /// and throws an exception if it is not.
- ///
- /// The target value, which should be validated.
- /// The minimum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is less than the minimum value.
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void MustBeGreaterThan(TValue value, TValue min, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(min) <= 0)
- {
- ThrowArgumentOutOfRangeException(
- parameterName,
- $"Value {value} must be greater than {min}.");
- }
- }
-
- ///
- /// Verifies that the specified value is greater than or equal to a minimum value
- /// and throws an exception if it is not.
- ///
- /// The target value, which should be validated.
- /// The minimum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is less than the minimum value.
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(min) < 0)
- {
- ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}.");
- }
- }
-
- ///
- /// Verifies that the specified value is greater than or equal to a minimum value and less than
- /// or equal to a maximum value and throws an exception if it is not.
- ///
- /// The target value, which should be validated.
- /// The minimum value.
- /// The maximum value.
- /// The name of the parameter that is to be checked.
- /// The type of the value.
- ///
- /// is less than the minimum value of greater than the maximum value.
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName)
- where TValue : IComparable
- {
- if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0)
- {
- ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}.");
- }
- }
-
- ///
- /// Verifies, that the method parameter with specified target value is true
- /// and throws an exception if it is found to be so.
- ///
- /// The target value, which cannot be false.
- /// The name of the parameter that is to be checked.
- /// The error message, if any to add to the exception.
- ///
- /// is false
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void IsTrue(bool target, string parameterName, string message)
- {
- if (!target)
- {
- ThrowArgumentException(message, parameterName);
- }
- }
-
- ///
- /// Verifies, that the method parameter with specified target value is false
- /// and throws an exception if it is found to be so.
- ///
- /// The target value, which cannot be true.
- /// The name of the parameter that is to be checked.
- /// The error message, if any to add to the exception.
- ///
- /// is true
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void IsFalse(bool target, string parameterName, string message)
- {
- if (target)
- {
- ThrowArgumentException(message, parameterName);
- }
- }
-
- ///
- /// Verifies, that the `source` span has the length of 'minLength', or longer.
- ///
- /// The element type of the spans
- /// The source span.
- /// The minimum length.
- /// The name of the parameter that is to be checked.
- ///
- /// has less than items
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName)
- {
- if (source.Length < minLength)
- {
- ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
- }
- }
-
- ///
- /// Verifies that the 'destination' span is not shorter than 'source'.
- ///
- /// The source element type
- /// The destination element type
- /// The source span
- /// The destination span
- /// The name of the argument for 'destination'
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void DestinationShouldNotBeTooShort(
- ReadOnlySpan source,
- Span destination,
- string destinationParamName)
- {
- if (destination.Length < source.Length)
- {
- ThrowArgumentException("Destination span is too short!", destinationParamName);
- }
- }
-
- ///
- /// Verifies that the 'destination' span is not shorter than 'source'.
- ///
- /// The source element type
- /// The destination element type
- /// The source span
- /// The destination span
- /// The name of the argument for 'destination'
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void DestinationShouldNotBeTooShort(
- Span source,
- Span destination,
- string destinationParamName)
- {
- if (destination.Length < source.Length)
- {
- ThrowArgumentException("Destination span is too short!", destinationParamName);
- }
- }
-
- ///
- /// Verifies, that the `source` span has the length of 'minLength', or longer.
- ///
- /// The element type of the spans
- /// The target span.
- /// The minimum length.
- /// The name of the parameter that is to be checked.
- ///
- /// has less than items
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName)
- {
- if (source.Length < minLength)
- {
- ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
- }
- }
-
- [MethodImpl(InliningOptions.ColdPath)]
- private static void ThrowArgumentException(string message, string parameterName)
- {
- throw new ArgumentException(message, parameterName);
- }
-
- [MethodImpl(InliningOptions.ColdPath)]
- private static void ThrowArgumentOutOfRangeException(string parameterName, string message)
- {
- throw new ArgumentOutOfRangeException(parameterName, message);
- }
-
- [MethodImpl(InliningOptions.ColdPath)]
- private static void ThrowArgumentNullException(string parameterName)
- {
- throw new ArgumentNullException(parameterName);
- }
- }
-}
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
index 5aa0b21ec1..bc07fbf317 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
@@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp
{
public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture;
+#if !SUPPORTS_EXTENDED_INTRINSICS
///
/// as many elements as possible, slicing them down (keeping the remainder).
///
@@ -74,6 +75,7 @@ namespace SixLabors.ImageSharp
dest = dest.Slice(adjustedCount);
}
}
+#endif
///
/// SIMD optimized implementation for .
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index 0d44db8d87..ae20490c77 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp
get => this.maxDegreeOfParallelism;
set
{
- if (value <= 0)
+ if (value == 0 || value < -1)
{
throw new ArgumentOutOfRangeException(nameof(this.MaxDegreeOfParallelism));
}
@@ -161,4 +161,4 @@ namespace SixLabors.ImageSharp
new BmpConfigurationModule());
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs
index 13c89c82cf..34fe1aecbd 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs
@@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
[MethodImpl(InliningOptions.ShortMethod)]
public void CheckBits()
{
- if (this.remainingBits < 16)
+ if (this.remainingBits < JpegConstants.Huffman.MinBits)
{
this.FillBuffer();
}
@@ -85,8 +85,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
// Attempt to load at least the minimum number of required bits into the buffer.
// We fail to do so only if we hit a marker or reach the end of the input stream.
- this.remainingBits += 48;
- this.data = (this.data << 48) | this.GetBytes();
+ this.remainingBits += JpegConstants.Huffman.FetchBits;
+ this.data = (this.data << JpegConstants.Huffman.FetchBits) | this.GetBytes();
}
[MethodImpl(InliningOptions.ShortMethod)]
@@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private ulong GetBytes()
{
ulong temp = 0;
- for (int i = 0; i < 6; i++)
+ for (int i = 0; i < JpegConstants.Huffman.FetchLoop; i++)
{
int b = this.ReadStream();
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs
index 4685ba2895..6025930169 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs
@@ -82,12 +82,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Figure C.1: make table of Huffman code length for each symbol
int p = 0;
- for (int l = 1; l <= 16; l++)
+ for (int j = 1; j <= 16; j++)
{
- int i = this.Sizes[l];
+ int i = this.Sizes[j];
while (i-- != 0)
{
- huffSize[p++] = (char)l;
+ huffSize[p++] = (char)j;
}
}
@@ -111,20 +111,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// Figure F.15: generate decoding tables for bit-sequential decoding
p = 0;
- for (int l = 1; l <= 16; l++)
+ for (int j = 1; j <= 16; j++)
{
- if (this.Sizes[l] != 0)
+ if (this.Sizes[j] != 0)
{
- int offset = p - (int)huffCode[p];
- this.ValOffset[l] = offset;
- p += this.Sizes[l];
- this.MaxCode[l] = huffCode[p - 1]; // Maximum code of length l
- this.MaxCode[l] <<= 64 - l; // Left justify
- this.MaxCode[l] |= (1ul << (64 - l)) - 1;
+ this.ValOffset[j] = p - (int)huffCode[p];
+ p += this.Sizes[j];
+ this.MaxCode[j] = huffCode[p - 1]; // Maximum code of length l
+ this.MaxCode[j] <<= JpegConstants.Huffman.RegisterSize - j; // Left justify
+ this.MaxCode[j] |= (1ul << (JpegConstants.Huffman.RegisterSize - j)) - 1;
}
else
{
- this.MaxCode[l] = 0;
+ this.MaxCode[j] = 0;
}
}
@@ -142,11 +141,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
p = 0;
for (int length = 1; length <= JpegConstants.Huffman.LookupBits; length++)
{
+ int jShift = JpegConstants.Huffman.LookupBits - length;
for (int i = 1; i <= this.Sizes[length]; i++, p++)
{
// length = current code's length, p = its index in huffCode[] & Values[].
// Generate left-justified code followed by all possible bit sequences
- int lookBits = (int)(huffCode[p] << (JpegConstants.Huffman.LookupBits - length));
+ int lookBits = (int)(huffCode[p] << jShift);
for (int ctr = 1 << (JpegConstants.Huffman.LookupBits - length); ctr > 0; ctr--)
{
this.LookaheadSize[lookBits] = (byte)length;
diff --git a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs
index a39480e126..9f50e2cab1 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
+using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
namespace SixLabors.ImageSharp.Formats.Jpeg
{
@@ -249,6 +250,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
///
public const int RegisterSize = 64;
+ ///
+ /// The number of bits to fetch when filling the buffer.
+ ///
+ public const int FetchBits = 48;
+
+ ///
+ /// The number of times to read the input stream when filling the buffer.
+ ///
+ public const int FetchLoop = FetchBits / 8;
+
+ ///
+ /// The minimum number of bits allowed before by the before fetching.
+ ///
+ public const int MinBits = RegisterSize - FetchBits;
+
///
/// If the next Huffman code is no more than this number of bits, we can obtain its length
/// and the corresponding symbol directly from this tables.
@@ -266,4 +282,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
public const int LookupSize = 1 << LookupBits;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 9bc5a5079d..037f648f0a 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -5,6 +5,7 @@ using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
+using System.IO.Compression;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
@@ -175,11 +176,7 @@ namespace SixLabors.ImageSharp.Formats.Png
this.InitializeImage(metadata, out image);
}
- using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk))
- {
- deframeStream.AllocateNewBytes(chunk.Length);
- this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame, pngMetadata);
- }
+ this.ReadScanlines(chunk, image.Frames.RootFrame, pngMetadata);
break;
case PngChunkType.Palette:
@@ -465,19 +462,25 @@ namespace SixLabors.ImageSharp.Formats.Png
/// Reads the scanlines within the image.
///
/// The pixel format.
- /// The containing data.
+ /// The png chunk containing the compressed scanline data.
/// The pixel data.
/// The png metadata
- private void ReadScanlines(Stream dataStream, ImageFrame image, PngMetadata pngMetadata)
+ private void ReadScanlines(PngChunk chunk, ImageFrame image, PngMetadata pngMetadata)
where TPixel : struct, IPixel
{
- if (this.header.InterlaceMethod == PngInterlaceMode.Adam7)
- {
- this.DecodeInterlacedPixelData(dataStream, image, pngMetadata);
- }
- else
+ using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk))
{
- this.DecodePixelData(dataStream, image, pngMetadata);
+ deframeStream.AllocateNewBytes(chunk.Length, true);
+ DeflateStream dataStream = deframeStream.CompressedStream;
+
+ if (this.header.InterlaceMethod == PngInterlaceMode.Adam7)
+ {
+ this.DecodeInterlacedPixelData(dataStream, image, pngMetadata);
+ }
+ else
+ {
+ this.DecodePixelData(dataStream, image, pngMetadata);
+ }
}
}
@@ -924,7 +927,11 @@ namespace SixLabors.ImageSharp.Formats.Png
}
ReadOnlySpan compressedData = data.Slice(zeroIndex + 2);
- metadata.TextData.Add(new PngTextData(name, this.UncompressTextData(compressedData, PngConstants.Encoding), string.Empty, string.Empty));
+
+ if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string uncompressed))
+ {
+ metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty));
+ }
}
///
@@ -987,7 +994,11 @@ namespace SixLabors.ImageSharp.Formats.Png
if (compressionFlag == 1)
{
ReadOnlySpan compressedData = data.Slice(dataStartIdx);
- metadata.TextData.Add(new PngTextData(keyword, this.UncompressTextData(compressedData, PngConstants.TranslatedEncoding), language, translatedKeyword));
+
+ if (this.TryUncompressTextData(compressedData, PngConstants.TranslatedEncoding, out string uncompressed))
+ {
+ metadata.TextData.Add(new PngTextData(keyword, uncompressed, language, translatedKeyword));
+ }
}
else
{
@@ -1001,13 +1012,19 @@ namespace SixLabors.ImageSharp.Formats.Png
///
/// Compressed text data bytes.
/// The string encoding to use.
- /// A string.
- private string UncompressTextData(ReadOnlySpan compressedData, Encoding encoding)
+ /// The uncompressed value.
+ /// The .
+ private bool TryUncompressTextData(ReadOnlySpan compressedData, Encoding encoding, out string value)
{
using (var memoryStream = new MemoryStream(compressedData.ToArray()))
- using (var inflateStream = new ZlibInflateStream(memoryStream, () => 0))
+ using (var inflateStream = new ZlibInflateStream(memoryStream))
{
- inflateStream.AllocateNewBytes(compressedData.Length);
+ if (!inflateStream.AllocateNewBytes(compressedData.Length, false))
+ {
+ value = null;
+ return false;
+ }
+
var uncompressedBytes = new List();
// Note: this uses the a buffer which is only 4 bytes long to read the stream, maybe allocating a larger buffer makes sense here.
@@ -1018,7 +1035,8 @@ namespace SixLabors.ImageSharp.Formats.Png
bytesRead = inflateStream.CompressedStream.Read(this.buffer, 0, this.buffer.Length);
}
- return encoding.GetString(uncompressedBytes.ToArray());
+ value = encoding.GetString(uncompressedBytes.ToArray());
+ return true;
}
}
diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs
index 405eeafeb9..3eb34b8617 100644
--- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs
+++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs
@@ -13,21 +13,21 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
internal sealed class ZlibInflateStream : Stream
{
///
- /// Used to read the Adler-32 and Crc-32 checksums
+ /// Used to read the Adler-32 and Crc-32 checksums.
/// We don't actually use this for anything so it doesn't
/// have to be threadsafe.
///
private static readonly byte[] ChecksumBuffer = new byte[4];
///
- /// The inner raw memory stream
+ /// A default delegate to get more data from the inner stream.
///
- private readonly Stream innerStream;
+ private static readonly Func GetDataNoOp = () => 0;
///
- /// The compressed stream sitting over the top of the deframer
+ /// The inner raw memory stream.
///
- private DeflateStream compressedStream;
+ private readonly Stream innerStream;
///
/// A value indicating whether this instance of the given entity has been disposed.
@@ -43,20 +43,29 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
private bool isDisposed;
///
- /// The current data remaining to be read
+ /// The current data remaining to be read.
///
private int currentDataRemaining;
///
- /// Delegate to get more data once we've exhausted the current data remaining
+ /// Delegate to get more data once we've exhausted the current data remaining.
///
private readonly Func getData;
///
/// Initializes a new instance of the class.
///
- /// The inner raw stream
- /// A delegate to get more data from the inner stream
+ /// The inner raw stream.
+ public ZlibInflateStream(Stream innerStream)
+ : this(innerStream, GetDataNoOp)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The inner raw stream.
+ /// A delegate to get more data from the inner stream.
public ZlibInflateStream(Stream innerStream, Func getData)
{
this.innerStream = innerStream;
@@ -76,31 +85,32 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
public override long Length => throw new NotSupportedException();
///
- public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+ public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
///
- /// Gets the compressed stream over the deframed inner stream
+ /// Gets the compressed stream over the deframed inner stream.
///
- public DeflateStream CompressedStream => this.compressedStream;
+ public DeflateStream CompressedStream { get; private set; }
///
- /// Adds new bytes from a frame found in the original stream
+ /// Adds new bytes from a frame found in the original stream.
///
- /// blabla
- public void AllocateNewBytes(int bytes)
+ /// The current remaining data according to the chunk length.
+ /// Whether the chunk to be inflated is a critical chunk.
+ /// The .
+ public bool AllocateNewBytes(int bytes, bool isCriticalChunk)
{
this.currentDataRemaining = bytes;
- if (this.compressedStream is null)
+ if (this.CompressedStream is null)
{
- this.InitializeInflateStream();
+ return this.InitializeInflateStream(isCriticalChunk);
}
+
+ return true;
}
///
- public override void Flush()
- {
- throw new NotSupportedException();
- }
+ public override void Flush() => throw new NotSupportedException();
///
public override int ReadByte()
@@ -114,7 +124,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
if (this.currentDataRemaining == 0)
{
- // last buffer was read in its entirety, let's make sure we don't actually have more
+ // Last buffer was read in its entirety, let's make sure we don't actually have more in additional IDAT chunks.
this.currentDataRemaining = this.getData();
if (this.currentDataRemaining == 0)
@@ -125,32 +135,35 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
int bytesToRead = Math.Min(count, this.currentDataRemaining);
this.currentDataRemaining -= bytesToRead;
- int bytesRead = this.innerStream.Read(buffer, offset, bytesToRead);
- long length = this.innerStream.Length;
+ int totalBytesRead = this.innerStream.Read(buffer, offset, bytesToRead);
+ long innerStreamLength = this.innerStream.Length;
- // Keep reading data until we've reached the end of the stream or filled the buffer
- while (this.currentDataRemaining == 0 && bytesRead < count)
+ // Keep reading data until we've reached the end of the stream or filled the buffer.
+ int bytesRead = 0;
+ offset += totalBytesRead;
+ while (this.currentDataRemaining == 0 && totalBytesRead < count)
{
this.currentDataRemaining = this.getData();
if (this.currentDataRemaining == 0)
{
- return bytesRead;
+ return totalBytesRead;
}
offset += bytesRead;
- if (offset >= length || offset >= count)
+ if (offset >= innerStreamLength || offset >= count)
{
- return bytesRead;
+ return totalBytesRead;
}
- bytesToRead = Math.Min(count - bytesRead, this.currentDataRemaining);
+ bytesToRead = Math.Min(count - totalBytesRead, this.currentDataRemaining);
this.currentDataRemaining -= bytesToRead;
- bytesRead += this.innerStream.Read(buffer, offset, bytesToRead);
+ bytesRead = this.innerStream.Read(buffer, offset, bytesToRead);
+ totalBytesRead += bytesRead;
}
- return bytesRead;
+ return totalBytesRead;
}
///
@@ -181,11 +194,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
if (disposing)
{
- // dispose managed resources
- if (this.compressedStream != null)
+ // Dispose managed resources.
+ if (this.CompressedStream != null)
{
- this.compressedStream.Dispose();
- this.compressedStream = null;
+ this.CompressedStream.Dispose();
+ this.CompressedStream = null;
}
}
@@ -197,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.isDisposed = true;
}
- private void InitializeInflateStream()
+ private bool InitializeInflateStream(bool isCriticalChunk)
{
// Read the zlib header : http://tools.ietf.org/html/rfc1950
// CMF(Compression Method and flags)
@@ -215,7 +228,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.currentDataRemaining -= 2;
if (cmf == -1 || flag == -1)
{
- return;
+ return false;
}
if ((cmf & 0x0F) == 8)
@@ -225,14 +238,28 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
if (cinfo > 7)
{
- // Values of CINFO above 7 are not allowed in RFC1950.
- // CINFO is not defined in this specification for CM not equal to 8.
- throw new ImageFormatException($"Invalid window size for ZLIB header: cinfo={cinfo}");
+ if (isCriticalChunk)
+ {
+ // Values of CINFO above 7 are not allowed in RFC1950.
+ // CINFO is not defined in this specification for CM not equal to 8.
+ throw new ImageFormatException($"Invalid window size for ZLIB header: cinfo={cinfo}");
+ }
+ else
+ {
+ return false;
+ }
}
}
else
{
- throw new ImageFormatException($"Bad method for ZLIB header: cmf={cmf}");
+ if (isCriticalChunk)
+ {
+ throw new ImageFormatException($"Bad method for ZLIB header: cmf={cmf}");
+ }
+ else
+ {
+ return false;
+ }
}
// The preset dictionary.
@@ -246,7 +273,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
// Initialize the deflate Stream.
- this.compressedStream = new DeflateStream(this, CompressionMode.Decompress, true);
+ this.CompressedStream = new DeflateStream(this, CompressionMode.Decompress, true);
+
+ return true;
}
}
}
diff --git a/src/ImageSharp/IImage.cs b/src/ImageSharp/IImage.cs
index b9e2cee616..0d4dc3c9d9 100644
--- a/src/ImageSharp/IImage.cs
+++ b/src/ImageSharp/IImage.cs
@@ -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;
@@ -11,4 +11,4 @@ namespace SixLabors.ImageSharp
public interface IImage : IImageInfo, IDisposable
{
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs
index 57f60f2e75..d7fed90164 100644
--- a/src/ImageSharp/Image.cs
+++ b/src/ImageSharp/Image.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
using System.IO;
using SixLabors.ImageSharp.Advanced;
@@ -80,21 +81,11 @@ namespace SixLabors.ImageSharp
///
Configuration IConfigurable.Configuration => this.Configuration;
- ///
- /// Gets a value indicating whether the image instance is disposed.
- ///
- public bool IsDisposed { get; private set; }
-
///
public void Dispose()
{
- if (this.IsDisposed)
- {
- return;
- }
-
- this.IsDisposed = true;
- this.DisposeImpl();
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
}
///
@@ -109,8 +100,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(encoder, nameof(encoder));
this.EnsureNotDisposed();
- EncodeVisitor visitor = new EncodeVisitor(encoder, stream);
- this.AcceptVisitor(visitor);
+ this.AcceptVisitor(new EncodeVisitor(encoder, stream));
}
///
@@ -130,13 +120,6 @@ namespace SixLabors.ImageSharp
public abstract Image CloneAs(Configuration configuration)
where TPixel2 : struct, IPixel;
- ///
- /// Accept a .
- /// Implemented by invoking
- /// with the pixel type of the image.
- ///
- internal abstract void AcceptVisitor(IImageVisitor visitor);
-
///
/// Update the size of the image after mutation.
///
@@ -144,9 +127,23 @@ namespace SixLabors.ImageSharp
protected void UpdateSize(Size size) => this.size = size;
///
- /// Implements the Dispose logic.
+ /// Disposes the object and frees resources for the Garbage Collector.
+ ///
+ /// Whether to dispose of managed and unmanaged objects.
+ protected abstract void Dispose(bool disposing);
+
+ ///
+ /// Throws if the image is disposed.
+ ///
+ internal abstract void EnsureNotDisposed();
+
+ ///
+ /// Accepts a .
+ /// Implemented by invoking
+ /// with the pixel type of the image.
///
- protected abstract void DisposeImpl();
+ /// The visitor.
+ internal abstract void Accept(IImageVisitor visitor);
private class EncodeVisitor : IImageVisitor
{
diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs
index 6ea2b234c5..6cdc948d40 100644
--- a/src/ImageSharp/ImageExtensions.cs
+++ b/src/ImageSharp/ImageExtensions.cs
@@ -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;
@@ -119,16 +119,5 @@ namespace SixLabors.ImageSharp
return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}";
}
}
-
- ///
- /// Throws if the image is disposed.
- ///
- internal static void EnsureNotDisposed(this Image image)
- {
- if (image.IsDisposed)
- {
- throw new ObjectDisposedException(nameof(image), "Trying to execute an operation on a disposed image.");
- }
- }
}
}
diff --git a/src/ImageSharp/ImageFrame.cs b/src/ImageSharp/ImageFrame.cs
index f3fe1ed8d4..91872b21d6 100644
--- a/src/ImageSharp/ImageFrame.cs
+++ b/src/ImageSharp/ImageFrame.cs
@@ -74,7 +74,17 @@ namespace SixLabors.ImageSharp
public Rectangle Bounds() => new Rectangle(0, 0, this.Width, this.Height);
///
- public abstract void Dispose();
+ public void Dispose()
+ {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Disposes the object and frees resources for the Garbage Collector.
+ ///
+ /// Whether to dispose of managed and unmanaged objects.
+ protected abstract void Dispose(bool disposing);
internal abstract void CopyPixelsTo(Span destination)
where TDestinationPixel : struct, IPixel;
diff --git a/src/ImageSharp/ImageFrameCollection{TPixel}.cs b/src/ImageSharp/ImageFrameCollection{TPixel}.cs
index 893a7a4a80..722a4ddea8 100644
--- a/src/ImageSharp/ImageFrameCollection{TPixel}.cs
+++ b/src/ImageSharp/ImageFrameCollection{TPixel}.cs
@@ -351,7 +351,7 @@ namespace SixLabors.ImageSharp
this.parent.GetConfiguration(),
source.Size(),
source.Metadata.DeepClone());
- source.CopyPixelsTo(result.PixelBuffer.Span);
+ source.CopyPixelsTo(result.PixelBuffer.GetSpan());
return result;
}
}
diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs
index 5c9ff489e1..64f37a3407 100644
--- a/src/ImageSharp/ImageFrame{TPixel}.cs
+++ b/src/ImageSharp/ImageFrame{TPixel}.cs
@@ -6,9 +6,9 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Advanced.ParallelUtils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
-using SixLabors.ImageSharp.ParallelUtils;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives;
@@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp
/// In all other cases it is the only frame of the image.
///
/// The pixel format.
- public sealed class ImageFrame : ImageFrame, IPixelSource, IDisposable
+ public sealed class ImageFrame : ImageFrame, IPixelSource
where TPixel : struct, IPixel
{
private bool isDisposed;
@@ -196,20 +196,20 @@ namespace SixLabors.ImageSharp
this.UpdateSize(this.PixelBuffer.Size());
}
- ///
- /// Disposes the object and frees resources for the Garbage Collector.
- ///
- public override void Dispose()
+ ///
+ protected override void Dispose(bool disposing)
{
if (this.isDisposed)
{
return;
}
- this.PixelBuffer?.Dispose();
- this.PixelBuffer = null;
+ if (disposing)
+ {
+ this.PixelBuffer?.Dispose();
+ this.PixelBuffer = null;
+ }
- // Note disposing is done.
this.isDisposed = true;
}
@@ -218,10 +218,10 @@ namespace SixLabors.ImageSharp
if (typeof(TPixel) == typeof(TDestinationPixel))
{
Span dest1 = MemoryMarshal.Cast(destination);
- this.PixelBuffer.Span.CopyTo(dest1);
+ this.PixelBuffer.GetSpan().CopyTo(dest1);
}
- PixelOperations.Instance.To(this.Configuration, this.PixelBuffer.Span, destination);
+ PixelOperations.Instance.To(this.Configuration, this.PixelBuffer.GetSpan(), destination);
}
///
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index 8dff3b9779..86b0848663 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -19,6 +19,15 @@
SixLabors.ImageSharp
+
+
+ $(DefineConstants);SUPPORTS_MATHF
+
+
+
+ $(DefineConstants);SUPPORTS_HASHCODE
+
+
$(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS
@@ -27,6 +36,10 @@
+
+
+
+
True
diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs
index a7ea58652c..3f733479dc 100644
--- a/src/ImageSharp/Image{TPixel}.cs
+++ b/src/ImageSharp/Image{TPixel}.cs
@@ -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;
@@ -21,6 +21,8 @@ namespace SixLabors.ImageSharp
public sealed class Image : Image
where TPixel : struct, IPixel
{
+ private bool isDisposed;
+
///
/// Initializes a new instance of the class
/// with the height and the width of the image.
@@ -185,19 +187,41 @@ namespace SixLabors.ImageSharp
}
///
- protected override void DisposeImpl() => this.Frames.Dispose();
+ protected override void Dispose(bool disposing)
+ {
+ if (this.isDisposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ this.Frames.Dispose();
+ }
+
+ this.isDisposed = true;
+ }
+
+ ///
+ internal override void EnsureNotDisposed()
+ {
+ if (this.isDisposed)
+ {
+ throw new ObjectDisposedException("Trying to execute an operation on a disposed image.");
+ }
+ }
+
+ ///
+ public override string ToString() => $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}";
///
- internal override void AcceptVisitor(IImageVisitor visitor)
+ internal override void Accept(IImageVisitor visitor)
{
this.EnsureNotDisposed();
visitor.Visit(this);
}
- ///
- public override string ToString() => $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}";
-
///
/// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer.
///
diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs
index 59247aa2d2..35d55ba590 100644
--- a/src/ImageSharp/Memory/Buffer2DExtensions.cs
+++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs
@@ -13,13 +13,69 @@ namespace SixLabors.ImageSharp.Memory
///
/// Defines extension methods for .
///
- internal static class Buffer2DExtensions
+ public static class Buffer2DExtensions
{
+ ///
+ /// Gets a to the backing buffer of .
+ ///
+ /// The .
+ /// The value type.
+ /// The referencing the memory area.
+ public static Span GetSpan(this Buffer2D buffer)
+ where T : struct
+ {
+ Guard.NotNull(buffer, nameof(buffer));
+ return buffer.MemorySource.GetSpan();
+ }
+
+ ///
+ /// Gets the holding the backing buffer of .
+ ///
+ /// The .
+ /// The value type.
+ /// The .
+ public static Memory GetMemory(this Buffer2D buffer)
+ where T : struct
+ {
+ Guard.NotNull(buffer, nameof(buffer));
+ return buffer.MemorySource.Memory;
+ }
+
+ ///
+ /// Gets a to the row 'y' beginning from the pixel at the first pixel on that row.
+ ///
+ /// The buffer
+ /// The y (row) coordinate
+ /// The element type
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span GetRowSpan(this Buffer2D buffer, int y)
+ where T : struct
+ {
+ Guard.NotNull(buffer, nameof(buffer));
+ return buffer.GetSpan().Slice(y * buffer.Width, buffer.Width);
+ }
+
+ ///
+ /// Gets a to the row 'y' beginning from the pixel at the first pixel on that row.
+ ///
+ /// The buffer
+ /// The y (row) coordinate
+ /// The element type
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Memory GetRowMemory(this Buffer2D buffer, int y)
+ where T : struct
+ {
+ Guard.NotNull(buffer, nameof(buffer));
+ return buffer.MemorySource.Memory.Slice(y * buffer.Width, buffer.Width);
+ }
+
///
/// Copy columns of inplace,
/// from positions starting at to positions at .
///
- public static unsafe void CopyColumns(
+ internal static unsafe void CopyColumns(
this Buffer2D buffer,
int sourceIndex,
int destIndex,
@@ -37,7 +93,7 @@ namespace SixLabors.ImageSharp.Memory
int dOffset = destIndex * elementSize;
long count = columnCount * elementSize;
- Span span = MemoryMarshal.AsBytes(buffer.Memory.Span);
+ Span span = MemoryMarshal.AsBytes(buffer.GetMemory().Span);
fixed (byte* ptr = span)
{
@@ -60,7 +116,7 @@ namespace SixLabors.ImageSharp.Memory
/// The element type
/// The
/// The
- public static Rectangle FullRectangle(this Buffer2D buffer)
+ internal static Rectangle FullRectangle(this Buffer2D buffer)
where T : struct
{
return new Rectangle(0, 0, buffer.Width, buffer.Height);
@@ -73,11 +129,11 @@ namespace SixLabors.ImageSharp.Memory
/// The
/// The rectangle subarea
/// The
- public static BufferArea GetArea(this Buffer2D buffer, in Rectangle rectangle)
+ internal static BufferArea GetArea(this Buffer2D buffer, in Rectangle rectangle)
where T : struct =>
new BufferArea(buffer, rectangle);
- public static BufferArea GetArea(this Buffer2D buffer, int x, int y, int width, int height)
+ internal static BufferArea GetArea(this Buffer2D buffer, int x, int y, int width, int height)
where T : struct =>
new BufferArea(buffer, new Rectangle(x, y, width, height));
@@ -87,64 +143,17 @@ namespace SixLabors.ImageSharp.Memory
/// The element type
/// The
/// The
- public static BufferArea GetArea(this Buffer2D buffer)
+ internal static BufferArea GetArea(this Buffer2D buffer)
where T : struct =>
new BufferArea(buffer);
- public static BufferArea GetAreaBetweenRows(this Buffer2D buffer, int minY, int maxY)
- where T : struct =>
- new BufferArea(buffer, new Rectangle(0, minY, buffer.Width, maxY - minY));
-
///
/// Gets a span for all the pixels in defined by
///
- public static Span GetMultiRowSpan(this Buffer2D buffer, in RowInterval rows)
+ internal static Span GetMultiRowSpan(this Buffer2D buffer, in RowInterval rows)
where T : struct
{
- return buffer.Span.Slice(rows.Min * buffer.Width, rows.Height * buffer.Width);
- }
-
- ///
- /// Gets a to the row 'y' beginning from the pixel at the first pixel on that row.
- ///
- /// The buffer
- /// The y (row) coordinate
- /// The element type
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Memory GetRowMemory(this Buffer2D buffer, int y)
- where T : struct
- {
- return buffer.MemorySource.Memory.Slice(y * buffer.Width, buffer.Width);
- }
-
- ///
- /// Gets a to the row 'y' beginning from the pixel at 'x'.
- ///
- /// The buffer
- /// The x coordinate (position in the row)
- /// The y (row) coordinate
- /// The element type
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span GetRowSpan(this Buffer2D buffer, int x, int y)
- where T : struct
- {
- return buffer.GetSpan().Slice((y * buffer.Width) + x, buffer.Width - x);
- }
-
- ///
- /// Gets a to the row 'y' beginning from the pixel at the first pixel on that row.
- ///
- /// The buffer
- /// The y (row) coordinate
- /// The element type
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span GetRowSpan(this Buffer2D buffer, int y)
- where T : struct
- {
- return buffer.GetSpan().Slice(y * buffer.Width, buffer.Width);
+ return buffer.GetSpan().Slice(rows.Min * buffer.Width, rows.Height * buffer.Width);
}
///
@@ -153,21 +162,12 @@ namespace SixLabors.ImageSharp.Memory
/// The element type
/// The
/// The of the buffer
- public static Size Size(this Buffer2D buffer)
+ internal static Size Size(this Buffer2D buffer)
where T : struct
{
return new Size(buffer.Width, buffer.Height);
}
- ///
- /// Gets a to the backing buffer of .
- ///
- internal static Span GetSpan(this Buffer2D buffer)
- where T : struct
- {
- return buffer.MemorySource.GetSpan();
- }
-
[Conditional("DEBUG")]
private static void CheckColumnRegionsDoNotOverlap(
Buffer2D buffer,
diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs
index 82a98bfc63..06cfdf5607 100644
--- a/src/ImageSharp/Memory/Buffer2D{T}.cs
+++ b/src/ImageSharp/Memory/Buffer2D{T}.cs
@@ -12,8 +12,12 @@ namespace SixLabors.ImageSharp.Memory
/// Represents a buffer of value type objects
/// interpreted as a 2D region of x elements.
///
+ ///
+ /// Before RC1, this class might be target of API changes, use it on your own risk!
+ ///
/// The value type.
- internal sealed class Buffer2D : IDisposable
+ // TODO: Consider moving this type to the SixLabors.Memory namespace (SixLabors.Core).
+ public sealed class Buffer2D : IDisposable
where T : struct
{
private MemorySource memorySource;
@@ -24,7 +28,7 @@ namespace SixLabors.ImageSharp.Memory
/// The buffer to wrap
/// The number of elements in a row
/// The number of rows
- public Buffer2D(MemorySource memorySource, int width, int height)
+ internal Buffer2D(MemorySource memorySource, int width, int height)
{
this.memorySource = memorySource;
this.Width = width;
@@ -44,11 +48,7 @@ namespace SixLabors.ImageSharp.Memory
///
/// Gets the backing
///
- public MemorySource MemorySource => this.memorySource;
-
- public Memory Memory => this.MemorySource.Memory;
-
- public Span Span => this.Memory.Span;
+ internal MemorySource MemorySource => this.memorySource;
///
/// Gets a reference to the element at the specified position.
@@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Memory
/// The x coordinate (row)
/// The y coordinate (position at row)
/// A reference to the element.
- public ref T this[int x, int y]
+ internal ref T this[int x, int y]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
@@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Memory
DebugGuard.MustBeLessThan(x, this.Width, nameof(x));
DebugGuard.MustBeLessThan(y, this.Height, nameof(y));
- Span span = this.Span;
+ Span span = this.GetSpan();
return ref span[(this.Width * y) + x];
}
}
@@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Memory
DebugGuard.MustBeGreaterThan(h, 0, nameof(h));
DebugGuard.MustBeLessThanOrEqualTo(y + h, this.Height, nameof(h));
- Memory slice = this.Memory.Slice(y * this.Width, h * this.Width);
+ Memory slice = this.GetMemory().Slice(y * this.Width, h * this.Width);
var memory = new MemorySource(slice);
return new Buffer2D(memory, this.Width, h);
}
@@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Memory
/// Swaps the contents of 'destination' with 'source' if the buffers are owned (1),
/// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2!
///
- public static void SwapOrCopyContent(Buffer2D destination, Buffer2D source)
+ internal static void SwapOrCopyContent(Buffer2D destination, Buffer2D source)
{
MemorySource.SwapOrCopyContent(ref destination.memorySource, ref source.memorySource);
SwapDimensionData(destination, source);
diff --git a/src/ImageSharp/Memory/BufferArea{T}.cs b/src/ImageSharp/Memory/BufferArea{T}.cs
index f71a281390..38f0b8129d 100644
--- a/src/ImageSharp/Memory/BufferArea{T}.cs
+++ b/src/ImageSharp/Memory/BufferArea{T}.cs
@@ -23,10 +23,10 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferArea(Buffer2D destinationBuffer, Rectangle rectangle)
{
- ImageSharp.DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle));
- ImageSharp.DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle));
- ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, destinationBuffer.Width, nameof(rectangle));
- ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, destinationBuffer.Height, nameof(rectangle));
+ DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle));
+ DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle));
+ DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, destinationBuffer.Width, nameof(rectangle));
+ DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, destinationBuffer.Height, nameof(rectangle));
this.DestinationBuffer = destinationBuffer;
this.Rectangle = rectangle;
@@ -122,8 +122,8 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferArea GetSubArea(Rectangle rectangle)
{
- ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, this.Rectangle.Width, nameof(rectangle));
- ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, this.Rectangle.Height, nameof(rectangle));
+ DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, this.Rectangle.Width, nameof(rectangle));
+ DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, this.Rectangle.Height, nameof(rectangle));
int x = this.Rectangle.X + rectangle.X;
int y = this.Rectangle.Y + rectangle.Y;
@@ -161,4 +161,4 @@ namespace SixLabors.ImageSharp.Memory
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Memory/MemoryOwnerExtensions.cs b/src/ImageSharp/Memory/MemoryOwnerExtensions.cs
index d82e3aaee7..6d4468f788 100644
--- a/src/ImageSharp/Memory/MemoryOwnerExtensions.cs
+++ b/src/ImageSharp/Memory/MemoryOwnerExtensions.cs
@@ -13,7 +13,6 @@ namespace SixLabors.ImageSharp.Memory
///
internal static class MemoryOwnerExtensions
{
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span GetSpan(this IMemoryOwner buffer)
=> buffer.Memory.Span;
diff --git a/src/ImageSharp/Memory/RowInterval.cs b/src/ImageSharp/Memory/RowInterval.cs
index 815918754a..13037c889f 100644
--- a/src/ImageSharp/Memory/RowInterval.cs
+++ b/src/ImageSharp/Memory/RowInterval.cs
@@ -10,26 +10,32 @@ namespace SixLabors.ImageSharp.Memory
///
/// Represents an interval of rows in a and/or
///
- internal readonly struct RowInterval : IEquatable
+ ///
+ /// Before RC1, this class might be target of API changes, use it on your own risk!
+ ///
+ // TODO: Consider moving this type to the SixLabors.Memory namespace (SixLabors.Core).
+ public readonly struct RowInterval : IEquatable
{
///
/// Initializes a new instance of the struct.
///
+ /// The inclusive minimum row.
+ /// The exclusive maximum row.
public RowInterval(int min, int max)
{
- DebugGuard.MustBeLessThan(min, max, nameof(min));
+ Guard.MustBeLessThan(min, max, nameof(min));
this.Min = min;
this.Max = max;
}
///
- /// Gets the INCLUSIVE minimum.
+ /// Gets the inclusive minimum row.
///
public int Min { get; }
///
- /// Gets the EXCLUSIVE maximum.
+ /// Gets the exclusive maximum row.
///
public int Max { get; }
@@ -38,33 +44,48 @@ namespace SixLabors.ImageSharp.Memory
///
public int Height => this.Max - this.Min;
+ ///
+ /// Returns a boolean indicating whether the given two -s are equal.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// True if the given -s are equal; False otherwise.
public static bool operator ==(RowInterval left, RowInterval right)
{
return left.Equals(right);
}
+ ///
+ /// Returns a boolean indicating whether the given two -s are not equal.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// True if the given -s are not equal; False otherwise.
public static bool operator !=(RowInterval left, RowInterval right)
{
return !left.Equals(right);
}
///
- public override string ToString() => $"RowInterval [{this.Min}->{this.Max}]";
-
- public RowInterval Slice(int start) => new RowInterval(this.Min + start, this.Max);
-
- public RowInterval Slice(int start, int length) => new RowInterval(this.Min + start, this.Min + start + length);
-
public bool Equals(RowInterval other)
{
return this.Min == other.Min && this.Max == other.Max;
}
+ ///
public override bool Equals(object obj)
{
return !ReferenceEquals(null, obj) && obj is RowInterval other && this.Equals(other);
}
+ ///
public override int GetHashCode() => HashCode.Combine(this.Min, this.Max);
+
+ ///
+ public override string ToString() => $"RowInterval [{this.Min}->{this.Max}]";
+
+ internal RowInterval Slice(int start) => new RowInterval(this.Min + start, this.Max);
+
+ internal RowInterval Slice(int start, int length) => new RowInterval(this.Min + start, this.Min + start + length);
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifTagDescriptionAttribute.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifTagDescriptionAttribute.cs
index 0188c662ed..845e4ee734 100644
--- a/src/ImageSharp/MetaData/Profiles/Exif/ExifTagDescriptionAttribute.cs
+++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifTagDescriptionAttribute.cs
@@ -12,9 +12,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
internal sealed class ExifTagDescriptionAttribute : Attribute
{
- private readonly object value;
- private readonly string description;
-
///
/// Initializes a new instance of the class.
///
@@ -22,8 +19,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// The description for the value of the exif tag.
public ExifTagDescriptionAttribute(object value, string description)
{
- this.value = value;
- this.description = description;
}
///
diff --git a/src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs b/src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs
index 62dc0fcf59..b2f6261ef5 100644
--- a/src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs
+++ b/src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs
@@ -9,17 +9,17 @@ namespace SixLabors.ImageSharp.PixelFormats
public enum PixelAlphaCompositionMode
{
///
- /// returns the destination over the source.
+ /// Returns the destination over the source.
///
SrcOver = 0,
///
- /// returns the source colors.
+ /// Returns the source colors.
///
Src,
///
- /// returns the source over the destination.
+ /// Returns the source over the destination.
///
SrcAtop,
diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
index e94ea452be..51ee5d12d9 100644
--- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
+++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
@@ -26,7 +26,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
where TPixel : struct, IPixel
{
- internal class NormalSrc : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "NormalSrc" composition equation.
+ ///
+ public class NormalSrc : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -61,7 +65,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class MultiplySrc : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "MultiplySrc" composition equation.
+ ///
+ public class MultiplySrc : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -96,7 +104,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class AddSrc : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "AddSrc" composition equation.
+ ///
+ public class AddSrc : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -131,7 +143,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class SubtractSrc : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "SubtractSrc" composition equation.
+ ///
+ public class SubtractSrc : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -166,7 +182,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class ScreenSrc : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "ScreenSrc" composition equation.
+ ///
+ public class ScreenSrc : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -201,7 +221,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class DarkenSrc : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "DarkenSrc" composition equation.
+ ///
+ public class DarkenSrc : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -236,7 +260,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class LightenSrc : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "LightenSrc" composition equation.
+ ///
+ public class LightenSrc : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -271,7 +299,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class OverlaySrc : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "OverlaySrc" composition equation.
+ ///
+ public class OverlaySrc : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -306,7 +338,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class HardLightSrc : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "HardLightSrc" composition equation.
+ ///
+ public class HardLightSrc : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -341,7 +377,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class NormalSrcAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "NormalSrcAtop" composition equation.
+ ///
+ public class NormalSrcAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -376,7 +416,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class MultiplySrcAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "MultiplySrcAtop" composition equation.
+ ///
+ public class MultiplySrcAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -411,7 +455,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class AddSrcAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "AddSrcAtop" composition equation.
+ ///
+ public class AddSrcAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -446,7 +494,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class SubtractSrcAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "SubtractSrcAtop" composition equation.
+ ///
+ public class SubtractSrcAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -481,7 +533,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class ScreenSrcAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "ScreenSrcAtop" composition equation.
+ ///
+ public class ScreenSrcAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -516,7 +572,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class DarkenSrcAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "DarkenSrcAtop" composition equation.
+ ///
+ public class DarkenSrcAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -551,7 +611,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class LightenSrcAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "LightenSrcAtop" composition equation.
+ ///
+ public class LightenSrcAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -586,7 +650,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class OverlaySrcAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "OverlaySrcAtop" composition equation.
+ ///
+ public class OverlaySrcAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -621,7 +689,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class HardLightSrcAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "HardLightSrcAtop" composition equation.
+ ///
+ public class HardLightSrcAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -656,7 +728,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class NormalSrcOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "NormalSrcOver" composition equation.
+ ///
+ public class NormalSrcOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -691,7 +767,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class MultiplySrcOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "MultiplySrcOver" composition equation.
+ ///
+ public class MultiplySrcOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -726,7 +806,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class AddSrcOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "AddSrcOver" composition equation.
+ ///
+ public class AddSrcOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -761,7 +845,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class SubtractSrcOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "SubtractSrcOver" composition equation.
+ ///
+ public class SubtractSrcOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -796,7 +884,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class ScreenSrcOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "ScreenSrcOver" composition equation.
+ ///
+ public class ScreenSrcOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -831,7 +923,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class DarkenSrcOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "DarkenSrcOver" composition equation.
+ ///
+ public class DarkenSrcOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -866,7 +962,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class LightenSrcOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "LightenSrcOver" composition equation.
+ ///
+ public class LightenSrcOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -901,7 +1001,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class OverlaySrcOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "OverlaySrcOver" composition equation.
+ ///
+ public class OverlaySrcOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -936,7 +1040,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class HardLightSrcOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "HardLightSrcOver" composition equation.
+ ///
+ public class HardLightSrcOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -971,7 +1079,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class NormalSrcIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "NormalSrcIn" composition equation.
+ ///
+ public class NormalSrcIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1006,7 +1118,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class MultiplySrcIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "MultiplySrcIn" composition equation.
+ ///
+ public class MultiplySrcIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1041,7 +1157,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class AddSrcIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "AddSrcIn" composition equation.
+ ///
+ public class AddSrcIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1076,7 +1196,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class SubtractSrcIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "SubtractSrcIn" composition equation.
+ ///
+ public class SubtractSrcIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1111,7 +1235,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class ScreenSrcIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "ScreenSrcIn" composition equation.
+ ///
+ public class ScreenSrcIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1146,7 +1274,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class DarkenSrcIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "DarkenSrcIn" composition equation.
+ ///
+ public class DarkenSrcIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1181,7 +1313,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class LightenSrcIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "LightenSrcIn" composition equation.
+ ///
+ public class LightenSrcIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1216,7 +1352,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class OverlaySrcIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "OverlaySrcIn" composition equation.
+ ///
+ public class OverlaySrcIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1251,7 +1391,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class HardLightSrcIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "HardLightSrcIn" composition equation.
+ ///
+ public class HardLightSrcIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1286,7 +1430,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class NormalSrcOut : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "NormalSrcOut" composition equation.
+ ///
+ public class NormalSrcOut : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1321,7 +1469,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class MultiplySrcOut : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "MultiplySrcOut" composition equation.
+ ///
+ public class MultiplySrcOut : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1356,7 +1508,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class AddSrcOut : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "AddSrcOut" composition equation.
+ ///
+ public class AddSrcOut : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1391,7 +1547,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class SubtractSrcOut : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "SubtractSrcOut" composition equation.
+ ///
+ public class SubtractSrcOut : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1426,7 +1586,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class ScreenSrcOut : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "ScreenSrcOut" composition equation.
+ ///
+ public class ScreenSrcOut : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1461,7 +1625,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class DarkenSrcOut : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "DarkenSrcOut" composition equation.
+ ///
+ public class DarkenSrcOut : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1496,7 +1664,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class LightenSrcOut : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "LightenSrcOut" composition equation.
+ ///
+ public class LightenSrcOut : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1531,7 +1703,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class OverlaySrcOut : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "OverlaySrcOut" composition equation.
+ ///
+ public class OverlaySrcOut : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1566,7 +1742,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class HardLightSrcOut : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "HardLightSrcOut" composition equation.
+ ///
+ public class HardLightSrcOut : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1601,7 +1781,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class NormalDest : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "NormalDest" composition equation.
+ ///
+ public class NormalDest : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1636,7 +1820,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class MultiplyDest : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "MultiplyDest" composition equation.
+ ///
+ public class MultiplyDest : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1671,7 +1859,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class AddDest : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "AddDest" composition equation.
+ ///
+ public class AddDest : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1706,7 +1898,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class SubtractDest : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "SubtractDest" composition equation.
+ ///
+ public class SubtractDest : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1741,7 +1937,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class ScreenDest : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "ScreenDest" composition equation.
+ ///
+ public class ScreenDest : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1776,7 +1976,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class DarkenDest : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "DarkenDest" composition equation.
+ ///
+ public class DarkenDest : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1811,7 +2015,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class LightenDest : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "LightenDest" composition equation.
+ ///
+ public class LightenDest : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1846,7 +2054,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class OverlayDest : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "OverlayDest" composition equation.
+ ///
+ public class OverlayDest : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1881,7 +2093,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class HardLightDest : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "HardLightDest" composition equation.
+ ///
+ public class HardLightDest : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1916,7 +2132,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class NormalDestAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "NormalDestAtop" composition equation.
+ ///
+ public class NormalDestAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1951,7 +2171,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class MultiplyDestAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "MultiplyDestAtop" composition equation.
+ ///
+ public class MultiplyDestAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -1986,7 +2210,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class AddDestAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "AddDestAtop" composition equation.
+ ///
+ public class AddDestAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2021,7 +2249,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class SubtractDestAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "SubtractDestAtop" composition equation.
+ ///
+ public class SubtractDestAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2056,7 +2288,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class ScreenDestAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "ScreenDestAtop" composition equation.
+ ///
+ public class ScreenDestAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2091,7 +2327,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class DarkenDestAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "DarkenDestAtop" composition equation.
+ ///
+ public class DarkenDestAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2126,7 +2366,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class LightenDestAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "LightenDestAtop" composition equation.
+ ///
+ public class LightenDestAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2161,7 +2405,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class OverlayDestAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "OverlayDestAtop" composition equation.
+ ///
+ public class OverlayDestAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2196,7 +2444,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class HardLightDestAtop : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "HardLightDestAtop" composition equation.
+ ///
+ public class HardLightDestAtop : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2231,7 +2483,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class NormalDestOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "NormalDestOver" composition equation.
+ ///
+ public class NormalDestOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2266,7 +2522,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class MultiplyDestOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "MultiplyDestOver" composition equation.
+ ///
+ public class MultiplyDestOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2301,7 +2561,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class AddDestOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "AddDestOver" composition equation.
+ ///
+ public class AddDestOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2336,7 +2600,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class SubtractDestOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "SubtractDestOver" composition equation.
+ ///
+ public class SubtractDestOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2371,7 +2639,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class ScreenDestOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "ScreenDestOver" composition equation.
+ ///
+ public class ScreenDestOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2406,7 +2678,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class DarkenDestOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "DarkenDestOver" composition equation.
+ ///
+ public class DarkenDestOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2441,7 +2717,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class LightenDestOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "LightenDestOver" composition equation.
+ ///
+ public class LightenDestOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2476,7 +2756,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class OverlayDestOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "OverlayDestOver" composition equation.
+ ///
+ public class OverlayDestOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2511,7 +2795,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class HardLightDestOver : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "HardLightDestOver" composition equation.
+ ///
+ public class HardLightDestOver : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2546,7 +2834,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class NormalDestIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "NormalDestIn" composition equation.
+ ///
+ public class NormalDestIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2581,7 +2873,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class MultiplyDestIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "MultiplyDestIn" composition equation.
+ ///
+ public class MultiplyDestIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2616,7 +2912,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class AddDestIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "AddDestIn" composition equation.
+ ///
+ public class AddDestIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2651,7 +2951,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class SubtractDestIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "SubtractDestIn" composition equation.
+ ///
+ public class SubtractDestIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2686,7 +2990,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class ScreenDestIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "ScreenDestIn" composition equation.
+ ///
+ public class ScreenDestIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2721,7 +3029,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class DarkenDestIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "DarkenDestIn" composition equation.
+ ///
+ public class DarkenDestIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2756,7 +3068,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class LightenDestIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "LightenDestIn" composition equation.
+ ///
+ public class LightenDestIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2791,7 +3107,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class OverlayDestIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "OverlayDestIn" composition equation.
+ ///
+ public class OverlayDestIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2826,7 +3146,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class HardLightDestIn : PixelBlender
+
+ ///
+ /// A pixel blender that implements the "HardLightDestIn" composition equation.
+ ///
+ public class HardLightDestIn : PixelBlender
{
///
/// Gets the static instance of this blender.
@@ -2861,7 +3185,11 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
}
}
- internal class NormalDestOut : PixelBlender