diff --git a/.editorconfig b/.editorconfig index fa43757a9f..b725c5cce3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,4 +13,8 @@ dotnet_style_predefined_type_for_locals_parameters_members = true:warning dotnet_style_predefined_type_for_member_access = true:warning dotnet_style_qualification_for_field = true:warning dotnet_style_qualification_for_method = true:warning -dotnet_style_qualification_for_property = true:warning \ No newline at end of file +dotnet_style_qualification_for_property = true:warning + +[*.tt] +indent_style = space +indent_size = 4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index fb8af2320c..8034c8c89c 100644 --- a/.gitignore +++ b/.gitignore @@ -217,3 +217,4 @@ artifacts/ #CodeCoverage **/CodeCoverage/* docs/ +/samples/AvatarWithRoundedCorner/output diff --git a/ImageSharp.sln b/ImageSharp.sln index 468bbbf862..d67e869327 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26403.7 +VisualStudioVersion = 15.0.26430.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}" ProjectSection(SolutionItems) = preProject @@ -43,7 +43,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Tests", "tests\I EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "tests\ImageSharp.Benchmarks\ImageSharp.Benchmarks.csproj", "{2BF743D8-2A06-412D-96D7-F448F00C5EA5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{7CC6D57E-B916-43B8-B315-A0BB92F260A2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvatarWithRoundedCorner", "samples\AvatarWithRoundedCorner\AvatarWithRoundedCorner.csproj", "{844FC582-4E78-4371-847D-EFD4D1103578}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChangeDefaultEncoderOptions", "samples\ChangeDefaultEncoderOptions\ChangeDefaultEncoderOptions.csproj", "{07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Formats.Tiff.Tests", "tests\ImageSharp.Formats.Tiff.Tests\ImageSharp.Formats.Tiff.Tests.csproj", "{F74D25AB-1E5C-4272-9FD3-6DBBD3E207AC}" EndProject @@ -141,6 +147,30 @@ Global {F74D25AB-1E5C-4272-9FD3-6DBBD3E207AC}.Release|x64.Build.0 = Release|x64 {F74D25AB-1E5C-4272-9FD3-6DBBD3E207AC}.Release|x86.ActiveCfg = Release|x86 {F74D25AB-1E5C-4272-9FD3-6DBBD3E207AC}.Release|x86.Build.0 = Release|x86 + {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|Any CPU.Build.0 = Debug|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x64.ActiveCfg = Debug|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x64.Build.0 = Debug|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x86.ActiveCfg = Debug|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Debug|x86.Build.0 = Debug|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Release|Any CPU.ActiveCfg = Release|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Release|Any CPU.Build.0 = Release|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x64.ActiveCfg = Release|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x64.Build.0 = Release|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x86.ActiveCfg = Release|Any CPU + {844FC582-4E78-4371-847D-EFD4D1103578}.Release|x86.Build.0 = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|x64.ActiveCfg = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|x64.Build.0 = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|x86.ActiveCfg = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Debug|x86.Build.0 = Debug|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|Any CPU.Build.0 = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|x64.ActiveCfg = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|x64.Build.0 = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|x86.ActiveCfg = Release|Any CPU + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -154,5 +184,7 @@ Global {2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {F74D25AB-1E5C-4272-9FD3-6DBBD3E207AC} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} + {844FC582-4E78-4371-847D-EFD4D1103578} = {7CC6D57E-B916-43B8-B315-A0BB92F260A2} + {07EE511D-4BAB-4323-BAFC-3AF2BF9366F0} = {7CC6D57E-B916-43B8-B315-A0BB92F260A2} EndGlobalSection EndGlobal diff --git a/README.md b/README.md index 5617681994..e46b113793 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ Setting individual pixel values can be perfomed as follows: ```csharp // Individual pixels -using (Image image = new Image(400, 400) +using (Image image = new Image(400, 400)) { image[200, 200] = Rgba32.White; } @@ -213,4 +213,4 @@ Become a sponsor and get your logo on our README on Github with a link to your s - \ No newline at end of file + diff --git a/samples/AvatarWithRoundedCorner/AvatarWithRoundedCorner.csproj b/samples/AvatarWithRoundedCorner/AvatarWithRoundedCorner.csproj new file mode 100644 index 0000000000..e000aacf10 --- /dev/null +++ b/samples/AvatarWithRoundedCorner/AvatarWithRoundedCorner.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp1.1 + + + + + + + \ No newline at end of file diff --git a/samples/AvatarWithRoundedCorner/Program.cs b/samples/AvatarWithRoundedCorner/Program.cs new file mode 100644 index 0000000000..b164c8d3bc --- /dev/null +++ b/samples/AvatarWithRoundedCorner/Program.cs @@ -0,0 +1,71 @@ + + +namespace AvatarWithRoundedCorner +{ + using System; + using System.Numerics; + using ImageSharp; + using SixLabors.Primitives; + using SixLabors.Shapes; + + class Program + { + static void Main(string[] args) + { + System.IO.Directory.CreateDirectory("output"); + + GenerateAvatar("fb.jpg", "output/fb.png", new Size(200, 200), 20); + GenerateAvatar("fb.jpg", "output/fb-round.png", new Size(200, 200), 100); + GenerateAvatar("fb.jpg", "output/fb-rounder.png", new Size(200, 200), 150); + } + + private static void GenerateAvatar(string source, string destination, Size size, float cornerRadius) + { + using (var image = Image.Load(source)) + { + image.Resize(new ImageSharp.Processing.ResizeOptions + { + Size = size, + Mode = ImageSharp.Processing.ResizeMode.Crop + }); + + ApplyRoundedCourners(image, cornerRadius); + image.Save(destination); + } + } + + public static void ApplyRoundedCourners(Image img, float cornerRadius) + { + var corners = BuildCorners(img.Width, img.Height, cornerRadius); + // now we have our corners time to draw them + img.Fill(Rgba32.Transparent, corners, new GraphicsOptions(true) + { + BlenderMode = ImageSharp.PixelFormats.PixelBlenderMode.Src // enforces that any part of this shape that has color is punched out of the background + }); + } + + public static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius) + { + // first create a square + var rect = new SixLabors.Shapes.RectangularePolygon(-0.5f, -0.5f, cornerRadius, cornerRadius); + + // then cut out of the square a circle so we are left with a corner + var cornerToptLeft = rect.Clip(new SixLabors.Shapes.EllipsePolygon(cornerRadius-0.5f, cornerRadius - 0.5f, cornerRadius)); + + // corner is now a corner shape positions top left + //lets make 3 more positioned correctly, we cando that by translating the orgional artound the center of the image + var center = new Vector2(imageWidth / 2, imageHeight / 2); + var angle = Math.PI / 2f; + + float rightPos = imageWidth - cornerToptLeft.Bounds.Width +1; + float bottomPos = imageHeight - cornerToptLeft.Bounds.Height + 1; + + // move it across the widthof the image - the width of the shape + var cornerTopRight = cornerToptLeft.RotateDegree(90).Translate(rightPos, 0); + var cornerBottomLeft = cornerToptLeft.RotateDegree(-90).Translate(0, bottomPos); + var cornerBottomRight = cornerToptLeft.RotateDegree(180).Translate(rightPos, bottomPos); + + return new PathCollection(cornerToptLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight); + } + } +} \ No newline at end of file diff --git a/samples/AvatarWithRoundedCorner/fb.jpg b/samples/AvatarWithRoundedCorner/fb.jpg new file mode 100644 index 0000000000..7241890e2e --- /dev/null +++ b/samples/AvatarWithRoundedCorner/fb.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93bb4d6281dc1e845db57e836e0dca30b7a4062e81044efb27ad4d8b1a33130c +size 15787 diff --git a/samples/ChangeDefaultEncoderOptions/ChangeDefaultEncoderOptions.csproj b/samples/ChangeDefaultEncoderOptions/ChangeDefaultEncoderOptions.csproj new file mode 100644 index 0000000000..5797be0f56 --- /dev/null +++ b/samples/ChangeDefaultEncoderOptions/ChangeDefaultEncoderOptions.csproj @@ -0,0 +1,12 @@ + + + + Exe + netcoreapp1.1 + + + + + + + \ No newline at end of file diff --git a/samples/ChangeDefaultEncoderOptions/Program.cs b/samples/ChangeDefaultEncoderOptions/Program.cs new file mode 100644 index 0000000000..dab8d445ca --- /dev/null +++ b/samples/ChangeDefaultEncoderOptions/Program.cs @@ -0,0 +1,20 @@ +using System; +using ImageSharp; +using ImageSharp.Formats; + +namespace ChangeDefaultEncoderOptions +{ + class Program + { + static void Main(string[] args) + { + // lets switch out the default encoder for jpeg to one + // that saves at 90 quality and ignores the matadata + Configuration.Default.SetEncoder(ImageFormats.Jpeg, new ImageSharp.Formats.JpegEncoder() + { + Quality = 90, + IgnoreMetadata = true + }); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Brushes/IBrush.cs b/src/ImageSharp.Drawing/Brushes/IBrush.cs index 8cb7317823..33b516e5c2 100644 --- a/src/ImageSharp.Drawing/Brushes/IBrush.cs +++ b/src/ImageSharp.Drawing/Brushes/IBrush.cs @@ -7,6 +7,7 @@ namespace ImageSharp.Drawing { using ImageSharp.PixelFormats; using Processors; + using SixLabors.Primitives; /// /// Brush represents a logical configuration of a brush which can be used to source pixel colors diff --git a/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs index 59dbd39266..57fcd8ffa6 100644 --- a/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Drawing.Brushes using ImageSharp.Memory; using ImageSharp.PixelFormats; using Processors; + using SixLabors.Primitives; /// /// Provides an implementation of an image brush for painting images within areas. diff --git a/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs index 5dd57bda66..5fcb92bdc7 100644 --- a/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Drawing.Brushes using ImageSharp.Memory; using ImageSharp.PixelFormats; using Processors; + using SixLabors.Primitives; /// /// Provides an implementation of a pattern brush for painting patterns. diff --git a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs index 96d824b2fc..27aa99b975 100644 --- a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Drawing.Brushes using ImageSharp.Memory; using ImageSharp.PixelFormats; using Processors; + using SixLabors.Primitives; /// /// Provides an implementation of a brush that can recolor an image diff --git a/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs index 453b4d29ef..21ebb88a04 100644 --- a/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Drawing.Brushes using ImageSharp.Memory; using ImageSharp.PixelFormats; using Processors; + using SixLabors.Primitives; /// /// Provides an implementation of a solid brush for painting solid color areas. diff --git a/src/ImageSharp.Drawing/DrawImage.cs b/src/ImageSharp.Drawing/DrawImage.cs index db40132c8a..03eb7be289 100644 --- a/src/ImageSharp.Drawing/DrawImage.cs +++ b/src/ImageSharp.Drawing/DrawImage.cs @@ -7,6 +7,7 @@ namespace ImageSharp { using Drawing.Processors; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 13500b65af..10562b08ca 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -36,7 +36,7 @@ - + All diff --git a/src/ImageSharp.Drawing/Paths/DrawBeziers.cs b/src/ImageSharp.Drawing/Paths/DrawBeziers.cs index c4ea8c3785..59bcf40363 100644 --- a/src/ImageSharp.Drawing/Paths/DrawBeziers.cs +++ b/src/ImageSharp.Drawing/Paths/DrawBeziers.cs @@ -10,6 +10,7 @@ namespace ImageSharp using Drawing.Brushes; using Drawing.Pens; using ImageSharp.PixelFormats; + using SixLabors.Primitives; using SixLabors.Shapes; /// @@ -27,10 +28,10 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image DrawBeziers(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) + public static Image DrawBeziers(this Image source, IBrush brush, float thickness, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { - return source.Draw(new Pen(brush, thickness), new Path(new BezierLineSegment(points)), options); + return source.Draw(new Pen(brush, thickness), new Path(new CubicBezierLineSegment(points)), options); } /// @@ -42,10 +43,10 @@ namespace ImageSharp /// The thickness. /// The points. /// The . - public static Image DrawBeziers(this Image source, IBrush brush, float thickness, Vector2[] points) + public static Image DrawBeziers(this Image source, IBrush brush, float thickness, PointF[] points) where TPixel : struct, IPixel { - return source.Draw(new Pen(brush, thickness), new Path(new BezierLineSegment(points))); + return source.Draw(new Pen(brush, thickness), new Path(new CubicBezierLineSegment(points))); } /// @@ -57,7 +58,7 @@ namespace ImageSharp /// The thickness. /// The points. /// The . - public static Image DrawBeziers(this Image source, TPixel color, float thickness, Vector2[] points) + public static Image DrawBeziers(this Image source, TPixel color, float thickness, PointF[] points) where TPixel : struct, IPixel { return source.DrawBeziers(new SolidBrush(color), thickness, points); @@ -73,7 +74,7 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image DrawBeziers(this Image source, TPixel color, float thickness, Vector2[] points, GraphicsOptions options) + public static Image DrawBeziers(this Image source, TPixel color, float thickness, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { return source.DrawBeziers(new SolidBrush(color), thickness, points, options); @@ -88,10 +89,10 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image DrawBeziers(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) + public static Image DrawBeziers(this Image source, IPen pen, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { - return source.Draw(pen, new Path(new BezierLineSegment(points)), options); + return source.Draw(pen, new Path(new CubicBezierLineSegment(points)), options); } /// @@ -102,10 +103,10 @@ namespace ImageSharp /// The pen. /// The points. /// The . - public static Image DrawBeziers(this Image source, IPen pen, Vector2[] points) + public static Image DrawBeziers(this Image source, IPen pen, PointF[] points) where TPixel : struct, IPixel { - return source.Draw(pen, new Path(new BezierLineSegment(points))); + return source.Draw(pen, new Path(new CubicBezierLineSegment(points))); } } } diff --git a/src/ImageSharp.Drawing/Paths/DrawLines.cs b/src/ImageSharp.Drawing/Paths/DrawLines.cs index e8c463638f..3ce0dc4da6 100644 --- a/src/ImageSharp.Drawing/Paths/DrawLines.cs +++ b/src/ImageSharp.Drawing/Paths/DrawLines.cs @@ -10,6 +10,7 @@ namespace ImageSharp using Drawing.Brushes; using Drawing.Pens; using ImageSharp.PixelFormats; + using SixLabors.Primitives; using SixLabors.Shapes; /// @@ -27,7 +28,7 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image DrawLines(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) + public static Image DrawLines(this Image source, IBrush brush, float thickness, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { return source.Draw(new Pen(brush, thickness), new Path(new LinearLineSegment(points)), options); @@ -42,7 +43,7 @@ namespace ImageSharp /// The thickness. /// The points. /// The . - public static Image DrawLines(this Image source, IBrush brush, float thickness, Vector2[] points) + public static Image DrawLines(this Image source, IBrush brush, float thickness, PointF[] points) where TPixel : struct, IPixel { return source.Draw(new Pen(brush, thickness), new Path(new LinearLineSegment(points))); @@ -57,7 +58,7 @@ namespace ImageSharp /// The thickness. /// The points. /// The . - public static Image DrawLines(this Image source, TPixel color, float thickness, Vector2[] points) + public static Image DrawLines(this Image source, TPixel color, float thickness, PointF[] points) where TPixel : struct, IPixel { return source.DrawLines(new SolidBrush(color), thickness, points); @@ -73,7 +74,7 @@ namespace ImageSharp /// The points. /// The options. /// The .> - public static Image DrawLines(this Image source, TPixel color, float thickness, Vector2[] points, GraphicsOptions options) + public static Image DrawLines(this Image source, TPixel color, float thickness, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { return source.DrawLines(new SolidBrush(color), thickness, points, options); @@ -88,7 +89,7 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image DrawLines(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) + public static Image DrawLines(this Image source, IPen pen, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { return source.Draw(pen, new Path(new LinearLineSegment(points)), options); @@ -102,7 +103,7 @@ namespace ImageSharp /// The pen. /// The points. /// The . - public static Image DrawLines(this Image source, IPen pen, Vector2[] points) + public static Image DrawLines(this Image source, IPen pen, PointF[] points) where TPixel : struct, IPixel { return source.Draw(pen, new Path(new LinearLineSegment(points))); diff --git a/src/ImageSharp.Drawing/Paths/DrawPolygon.cs b/src/ImageSharp.Drawing/Paths/DrawPolygon.cs index 4b99e60c02..4fa469a496 100644 --- a/src/ImageSharp.Drawing/Paths/DrawPolygon.cs +++ b/src/ImageSharp.Drawing/Paths/DrawPolygon.cs @@ -10,6 +10,7 @@ namespace ImageSharp using Drawing.Brushes; using Drawing.Pens; using ImageSharp.PixelFormats; + using SixLabors.Primitives; using SixLabors.Shapes; /// @@ -27,7 +28,7 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image DrawPolygon(this Image source, IBrush brush, float thickness, Vector2[] points, GraphicsOptions options) + public static Image DrawPolygon(this Image source, IBrush brush, float thickness, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { return source.Draw(new Pen(brush, thickness), new Polygon(new LinearLineSegment(points)), options); @@ -42,7 +43,7 @@ namespace ImageSharp /// The thickness. /// The points. /// The . - public static Image DrawPolygon(this Image source, IBrush brush, float thickness, Vector2[] points) + public static Image DrawPolygon(this Image source, IBrush brush, float thickness, PointF[] points) where TPixel : struct, IPixel { return source.Draw(new Pen(brush, thickness), new Polygon(new LinearLineSegment(points))); @@ -57,7 +58,7 @@ namespace ImageSharp /// The thickness. /// The points. /// The . - public static Image DrawPolygon(this Image source, TPixel color, float thickness, Vector2[] points) + public static Image DrawPolygon(this Image source, TPixel color, float thickness, PointF[] points) where TPixel : struct, IPixel { return source.DrawPolygon(new SolidBrush(color), thickness, points); @@ -73,7 +74,7 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image DrawPolygon(this Image source, TPixel color, float thickness, Vector2[] points, GraphicsOptions options) + public static Image DrawPolygon(this Image source, TPixel color, float thickness, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { return source.DrawPolygon(new SolidBrush(color), thickness, points, options); @@ -87,7 +88,7 @@ namespace ImageSharp /// The pen. /// The points. /// The . - public static Image DrawPolygon(this Image source, IPen pen, Vector2[] points) + public static Image DrawPolygon(this Image source, IPen pen, PointF[] points) where TPixel : struct, IPixel { return source.Draw(pen, new Polygon(new LinearLineSegment(points)), GraphicsOptions.Default); @@ -102,7 +103,7 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image DrawPolygon(this Image source, IPen pen, Vector2[] points, GraphicsOptions options) + public static Image DrawPolygon(this Image source, IPen pen, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { return source.Draw(pen, new Polygon(new LinearLineSegment(points)), options); diff --git a/src/ImageSharp.Drawing/Paths/DrawRectangle.cs b/src/ImageSharp.Drawing/Paths/DrawRectangle.cs index 0fefc6cab4..b3f0e6fc3b 100644 --- a/src/ImageSharp.Drawing/Paths/DrawRectangle.cs +++ b/src/ImageSharp.Drawing/Paths/DrawRectangle.cs @@ -9,6 +9,7 @@ namespace ImageSharp using Drawing.Brushes; using Drawing.Pens; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Extension methods for the type. @@ -24,10 +25,10 @@ namespace ImageSharp /// The shape. /// The options. /// The . - public static Image Draw(this Image source, IPen pen, Rectangle shape, GraphicsOptions options) + public static Image Draw(this Image source, IPen pen, RectangleF shape, GraphicsOptions options) where TPixel : struct, IPixel { - return source.Draw(pen, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options); + return source.Draw(pen, new SixLabors.Shapes.RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height), options); } /// @@ -38,7 +39,7 @@ namespace ImageSharp /// The pen. /// The shape. /// The . - public static Image Draw(this Image source, IPen pen, Rectangle shape) + public static Image Draw(this Image source, IPen pen, RectangleF shape) where TPixel : struct, IPixel { return source.Draw(pen, shape, GraphicsOptions.Default); @@ -54,7 +55,7 @@ namespace ImageSharp /// The shape. /// The options. /// The . - public static Image Draw(this Image source, IBrush brush, float thickness, Rectangle shape, GraphicsOptions options) + public static Image Draw(this Image source, IBrush brush, float thickness, RectangleF shape, GraphicsOptions options) where TPixel : struct, IPixel { return source.Draw(new Pen(brush, thickness), shape, options); @@ -69,7 +70,7 @@ namespace ImageSharp /// The thickness. /// The shape. /// The . - public static Image Draw(this Image source, IBrush brush, float thickness, Rectangle shape) + public static Image Draw(this Image source, IBrush brush, float thickness, RectangleF shape) where TPixel : struct, IPixel { return source.Draw(new Pen(brush, thickness), shape); @@ -85,7 +86,7 @@ namespace ImageSharp /// The shape. /// The options. /// The . - public static Image Draw(this Image source, TPixel color, float thickness, Rectangle shape, GraphicsOptions options) + public static Image Draw(this Image source, TPixel color, float thickness, RectangleF shape, GraphicsOptions options) where TPixel : struct, IPixel { return source.Draw(new SolidBrush(color), thickness, shape, options); @@ -100,7 +101,7 @@ namespace ImageSharp /// The thickness. /// The shape. /// The . - public static Image Draw(this Image source, TPixel color, float thickness, Rectangle shape) + public static Image Draw(this Image source, TPixel color, float thickness, RectangleF shape) where TPixel : struct, IPixel { return source.Draw(new SolidBrush(color), thickness, shape); diff --git a/src/ImageSharp.Drawing/Paths/FillPathBuilder.cs b/src/ImageSharp.Drawing/Paths/FillPathBuilder.cs new file mode 100644 index 0000000000..abb5ef73a7 --- /dev/null +++ b/src/ImageSharp.Drawing/Paths/FillPathBuilder.cs @@ -0,0 +1,80 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using Drawing; + using Drawing.Brushes; + using ImageSharp.PixelFormats; + using SixLabors.Shapes; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush.. + /// + /// The type of the color. + /// The image this method extends. + /// The brush. + /// The shape. + /// The graphics options. + /// The . + public static Image Fill(this Image source, IBrush brush, Action path, GraphicsOptions options) + where TPixel : struct, IPixel + { + var pb = new PathBuilder(); + path(pb); + + return source.Fill(brush, pb.Build(), options); + } + + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush. + /// + /// The type of the color. + /// The image this method extends. + /// The brush. + /// The path. + /// The . + public static Image Fill(this Image source, IBrush brush, Action path) + where TPixel : struct, IPixel + { + return source.Fill(brush, path, GraphicsOptions.Default); + } + + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush.. + /// + /// The type of the color. + /// The image this method extends. + /// The color. + /// The path. + /// The options. + /// The . + public static Image Fill(this Image source, TPixel color, Action path, GraphicsOptions options) + where TPixel : struct, IPixel + { + return source.Fill(new SolidBrush(color), path, options); + } + + /// + /// Flood fills the image in the shape of the provided polygon with the specified brush.. + /// + /// The type of the color. + /// The image this method extends. + /// The color. + /// The path. + /// The . + public static Image Fill(this Image source, TPixel color, Action path) + where TPixel : struct, IPixel + { + return source.Fill(new SolidBrush(color), path); + } + } +} diff --git a/src/ImageSharp.Drawing/Paths/FillPolygon.cs b/src/ImageSharp.Drawing/Paths/FillPolygon.cs index 3360cff13c..6266d3bd64 100644 --- a/src/ImageSharp.Drawing/Paths/FillPolygon.cs +++ b/src/ImageSharp.Drawing/Paths/FillPolygon.cs @@ -10,6 +10,7 @@ namespace ImageSharp using Drawing; using Drawing.Brushes; using ImageSharp.PixelFormats; + using SixLabors.Primitives; using SixLabors.Shapes; /// @@ -26,7 +27,7 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image FillPolygon(this Image source, IBrush brush, Vector2[] points, GraphicsOptions options) + public static Image FillPolygon(this Image source, IBrush brush, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { return source.Fill(brush, new Polygon(new LinearLineSegment(points)), options); @@ -40,7 +41,7 @@ namespace ImageSharp /// The brush. /// The points. /// The . - public static Image FillPolygon(this Image source, IBrush brush, Vector2[] points) + public static Image FillPolygon(this Image source, IBrush brush, PointF[] points) where TPixel : struct, IPixel { return source.Fill(brush, new Polygon(new LinearLineSegment(points))); @@ -55,7 +56,7 @@ namespace ImageSharp /// The points. /// The options. /// The . - public static Image FillPolygon(this Image source, TPixel color, Vector2[] points, GraphicsOptions options) + public static Image FillPolygon(this Image source, TPixel color, PointF[] points, GraphicsOptions options) where TPixel : struct, IPixel { return source.Fill(new SolidBrush(color), new Polygon(new LinearLineSegment(points)), options); @@ -69,7 +70,7 @@ namespace ImageSharp /// The color. /// The points. /// The . - public static Image FillPolygon(this Image source, TPixel color, Vector2[] points) + public static Image FillPolygon(this Image source, TPixel color, PointF[] points) where TPixel : struct, IPixel { return source.Fill(new SolidBrush(color), new Polygon(new LinearLineSegment(points))); diff --git a/src/ImageSharp.Drawing/Paths/FillRectangle.cs b/src/ImageSharp.Drawing/Paths/FillRectangle.cs index 07ff4c69c5..bd6460cf90 100644 --- a/src/ImageSharp.Drawing/Paths/FillRectangle.cs +++ b/src/ImageSharp.Drawing/Paths/FillRectangle.cs @@ -8,6 +8,7 @@ namespace ImageSharp using Drawing; using Drawing.Brushes; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Extension methods for the type. @@ -23,10 +24,10 @@ namespace ImageSharp /// The shape. /// The options. /// The . - public static Image Fill(this Image source, IBrush brush, Rectangle shape, GraphicsOptions options) + public static Image Fill(this Image source, IBrush brush, RectangleF shape, GraphicsOptions options) where TPixel : struct, IPixel { - return source.Fill(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options); + return source.Fill(brush, new SixLabors.Shapes.RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height), options); } /// @@ -37,10 +38,10 @@ namespace ImageSharp /// The brush. /// The shape. /// The . - public static Image Fill(this Image source, IBrush brush, Rectangle shape) + public static Image Fill(this Image source, IBrush brush, RectangleF shape) where TPixel : struct, IPixel { - return source.Fill(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height)); + return source.Fill(brush, new SixLabors.Shapes.RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height)); } /// @@ -52,7 +53,7 @@ namespace ImageSharp /// The shape. /// The options. /// The . - public static Image Fill(this Image source, TPixel color, Rectangle shape, GraphicsOptions options) + public static Image Fill(this Image source, TPixel color, RectangleF shape, GraphicsOptions options) where TPixel : struct, IPixel { return source.Fill(new SolidBrush(color), shape, options); @@ -66,7 +67,7 @@ namespace ImageSharp /// The color. /// The shape. /// The . - public static Image Fill(this Image source, TPixel color, Rectangle shape) + public static Image Fill(this Image source, TPixel color, RectangleF shape) where TPixel : struct, IPixel { return source.Fill(new SolidBrush(color), shape); diff --git a/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs b/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs deleted file mode 100644 index 1b5df75742..0000000000 --- a/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Drawing -{ - using System; - - /// - /// Extension methods for helping to bridge Shaper2D and ImageSharp primitives. - /// - internal static class RectangleExtensions - { - /// - /// Converts a Shaper2D to an ImageSharp by creating a the entirely surrounds the source. - /// - /// The image this method extends. - /// A representation of this - public static Rectangle Convert(this SixLabors.Shapes.Rectangle source) - { - int left = (int)MathF.Floor(source.Left); - int right = (int)MathF.Ceiling(source.Right); - int top = (int)MathF.Floor(source.Top); - int bottom = (int)MathF.Ceiling(source.Bottom); - return new Rectangle(left, top, right - left, bottom - top); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Paths/ShapePath.cs b/src/ImageSharp.Drawing/Paths/ShapePath.cs index 63c814f2d5..ec4f222e09 100644 --- a/src/ImageSharp.Drawing/Paths/ShapePath.cs +++ b/src/ImageSharp.Drawing/Paths/ShapePath.cs @@ -11,8 +11,6 @@ namespace ImageSharp.Drawing using SixLabors.Shapes; - using Rectangle = ImageSharp.Rectangle; - /// /// A mapping between a and a region. /// diff --git a/src/ImageSharp.Drawing/Paths/ShapeRegion.cs b/src/ImageSharp.Drawing/Paths/ShapeRegion.cs index 9dbf52285b..a7a72c4f3c 100644 --- a/src/ImageSharp.Drawing/Paths/ShapeRegion.cs +++ b/src/ImageSharp.Drawing/Paths/ShapeRegion.cs @@ -8,11 +8,10 @@ namespace ImageSharp.Drawing using System; using System.Buffers; using System.Numerics; - + using ImageSharp.Memory; + using SixLabors.Primitives; using SixLabors.Shapes; - using Rectangle = ImageSharp.Rectangle; - /// /// A mapping between a and a region. /// @@ -25,7 +24,12 @@ namespace ImageSharp.Drawing public ShapeRegion(IPath shape) { this.Shape = shape.AsClosedPath(); - this.Bounds = shape.Bounds.Convert(); + int left = (int)MathF.Floor(shape.Bounds.Left); + int top = (int)MathF.Floor(shape.Bounds.Top); + + int right = (int)MathF.Ceiling(shape.Bounds.Right); + int bottom = (int)MathF.Ceiling(shape.Bounds.Bottom); + this.Bounds = Rectangle.FromLTRB(left, top, right, bottom); } /// @@ -42,24 +46,20 @@ namespace ImageSharp.Drawing /// public override int Scan(float y, Span buffer) { - Vector2 start = new Vector2(this.Bounds.Left - 1, y); - Vector2 end = new Vector2(this.Bounds.Right + 1, y); - Vector2[] innerbuffer = ArrayPool.Shared.Rent(buffer.Length); - try + var start = new PointF(this.Bounds.Left - 1, y); + var end = new PointF(this.Bounds.Right + 1, y); + using (var innerBuffer = new Buffer(buffer.Length)) { - int count = this.Shape.FindIntersections(start, end, innerbuffer, buffer.Length, 0); + var span = innerBuffer.Span; + int count = this.Shape.FindIntersections(start, end, span); for (int i = 0; i < count; i++) { - buffer[i] = innerbuffer[i].X; + buffer[i] = span[i].X; } return count; } - finally - { - ArrayPool.Shared.Return(innerbuffer); - } } } -} +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs index ed45417fc9..62344b1012 100644 --- a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs @@ -12,6 +12,7 @@ namespace ImageSharp.Drawing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; using ImageSharp.Processing; + using SixLabors.Primitives; /// /// Combines two images together by blending the pixels. diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs index 8c7cd4e8c5..6eb12cf488 100644 --- a/src/ImageSharp.Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillProcessor.cs @@ -14,6 +14,7 @@ namespace ImageSharp.Drawing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; using ImageSharp.Processing; + using SixLabors.Primitives; /// /// Using the bursh as a source of pixels colors blends the brush color with source. diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index f2e09d2897..c398824323 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -13,6 +13,7 @@ namespace ImageSharp.Drawing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; using ImageSharp.Processing; + using SixLabors.Primitives; /// /// Usinf a brsuh and a shape fills shape with contents of brush the diff --git a/src/ImageSharp.Drawing/Region.cs b/src/ImageSharp.Drawing/Region.cs index 687ee23fdd..23028b9a8f 100644 --- a/src/ImageSharp.Drawing/Region.cs +++ b/src/ImageSharp.Drawing/Region.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Drawing { using System; + using SixLabors.Primitives; /// /// Represents a region of an image. diff --git a/src/ImageSharp.Drawing/Text/DrawText.Path.cs b/src/ImageSharp.Drawing/Text/DrawText.Path.cs index 2bc23b64bc..523813188a 100644 --- a/src/ImageSharp.Drawing/Text/DrawText.Path.cs +++ b/src/ImageSharp.Drawing/Text/DrawText.Path.cs @@ -166,13 +166,15 @@ namespace ImageSharp public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, IPath path, TextGraphicsOptions options) where TPixel : struct, IPixel { - Vector2 dpi = DefaultTextDpi; + float dpiX = DefaultTextDpi; + float dpiY = DefaultTextDpi; if (options.UseImageResolution) { - dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution); + dpiX = (float)source.MetaData.HorizontalResolution; + dpiY = (float)source.MetaData.VerticalResolution; } - var style = new FontSpan(font, dpi) + var style = new RendererOptions(font, dpiX, dpiY) { ApplyKerning = options.ApplyKerning, TabWidth = options.TabWidth, diff --git a/src/ImageSharp.Drawing/Text/DrawText.cs b/src/ImageSharp.Drawing/Text/DrawText.cs index 3b0d3db411..6352836a9c 100644 --- a/src/ImageSharp.Drawing/Text/DrawText.cs +++ b/src/ImageSharp.Drawing/Text/DrawText.cs @@ -12,6 +12,7 @@ namespace ImageSharp using Drawing.Pens; using ImageSharp.PixelFormats; using SixLabors.Fonts; + using SixLabors.Primitives; using SixLabors.Shapes; /// @@ -19,7 +20,7 @@ namespace ImageSharp /// public static partial class ImageExtensions { - private static readonly Vector2 DefaultTextDpi = new Vector2(72); + private static readonly int DefaultTextDpi = 72; /// /// Draws the text onto the the image filled via the brush. @@ -33,7 +34,7 @@ namespace ImageSharp /// /// The . /// - public static Image DrawText(this Image source, string text, Font font, TPixel color, Vector2 location) + public static Image DrawText(this Image source, string text, Font font, TPixel color, PointF location) where TPixel : struct, IPixel { return source.DrawText(text, font, color, location, TextGraphicsOptions.Default); @@ -52,7 +53,7 @@ namespace ImageSharp /// /// The . /// - public static Image DrawText(this Image source, string text, Font font, TPixel color, Vector2 location, TextGraphicsOptions options) + public static Image DrawText(this Image source, string text, Font font, TPixel color, PointF location, TextGraphicsOptions options) where TPixel : struct, IPixel { return source.DrawText(text, font, Brushes.Solid(color), null, location, options); @@ -70,7 +71,7 @@ namespace ImageSharp /// /// The . /// - public static Image DrawText(this Image source, string text, Font font, IBrush brush, Vector2 location) + public static Image DrawText(this Image source, string text, Font font, IBrush brush, PointF location) where TPixel : struct, IPixel { return source.DrawText(text, font, brush, location, TextGraphicsOptions.Default); @@ -89,7 +90,7 @@ namespace ImageSharp /// /// The . /// - public static Image DrawText(this Image source, string text, Font font, IBrush brush, Vector2 location, TextGraphicsOptions options) + public static Image DrawText(this Image source, string text, Font font, IBrush brush, PointF location, TextGraphicsOptions options) where TPixel : struct, IPixel { return source.DrawText(text, font, brush, null, location, options); @@ -107,7 +108,7 @@ namespace ImageSharp /// /// The . /// - public static Image DrawText(this Image source, string text, Font font, IPen pen, Vector2 location) + public static Image DrawText(this Image source, string text, Font font, IPen pen, PointF location) where TPixel : struct, IPixel { return source.DrawText(text, font, pen, location, TextGraphicsOptions.Default); @@ -126,7 +127,7 @@ namespace ImageSharp /// /// The . /// - public static Image DrawText(this Image source, string text, Font font, IPen pen, Vector2 location, TextGraphicsOptions options) + public static Image DrawText(this Image source, string text, Font font, IPen pen, PointF location, TextGraphicsOptions options) where TPixel : struct, IPixel { return source.DrawText(text, font, null, pen, location, options); @@ -145,7 +146,7 @@ namespace ImageSharp /// /// The . /// - public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, Vector2 location) + public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, PointF location) where TPixel : struct, IPixel { return source.DrawText(text, font, brush, pen, location, TextGraphicsOptions.Default); @@ -165,16 +166,18 @@ namespace ImageSharp /// /// The . /// - public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, Vector2 location, TextGraphicsOptions options) + public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, PointF location, TextGraphicsOptions options) where TPixel : struct, IPixel { - Vector2 dpi = DefaultTextDpi; + float dpiX = DefaultTextDpi; + float dpiY = DefaultTextDpi; if (options.UseImageResolution) { - dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution); + dpiX = (float)source.MetaData.HorizontalResolution; + dpiY = (float)source.MetaData.VerticalResolution; } - var style = new FontSpan(font, dpi) + var style = new RendererOptions(font, dpiX, dpiY, location) { ApplyKerning = options.ApplyKerning, TabWidth = options.TabWidth, @@ -183,7 +186,7 @@ namespace ImageSharp VerticalAlignment = options.VerticalAlignment }; - IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, location, style); + IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, style); var pathOptions = (GraphicsOptions)options; if (brush != null) diff --git a/src/ImageSharp/Common/Exceptions/ImageFormatException.cs b/src/ImageSharp/Common/Exceptions/ImageFormatException.cs index 70491ba22e..32a0854359 100644 --- a/src/ImageSharp/Common/Exceptions/ImageFormatException.cs +++ b/src/ImageSharp/Common/Exceptions/ImageFormatException.cs @@ -11,7 +11,7 @@ namespace ImageSharp /// The exception that is thrown when the library tries to load /// an image, which has an invalid format. /// - public class ImageFormatException : Exception + public sealed class ImageFormatException : Exception { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs index a59be9ca8f..ef84a1e393 100644 --- a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs +++ b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs @@ -10,7 +10,7 @@ namespace ImageSharp /// /// The exception that is thrown when an error occurs when applying a process to an image. /// - public class ImageProcessingException : Exception + public sealed class ImageProcessingException : Exception { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 9c4dee5033..367aa12d00 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -11,6 +11,7 @@ namespace ImageSharp using System.Runtime.CompilerServices; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides common mathematical methods. diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 57cd66eb43..226d451325 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -6,8 +6,8 @@ namespace ImageSharp { using System; + using System.Collections.Concurrent; using System.Collections.Generic; - using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; @@ -17,22 +17,32 @@ namespace ImageSharp /// /// Provides initialization code which allows extending the library. /// - public class Configuration + public sealed class Configuration { /// /// A lazily initialized configuration default instance. /// - private static readonly Lazy Lazy = new Lazy(() => CreateDefaultInstance()); + private static readonly Lazy Lazy = new Lazy(CreateDefaultInstance); /// - /// An object that can be used to synchronize access to the . + /// The list of supported keyed to mime types. /// - private readonly object syncRoot = new object(); + private readonly ConcurrentDictionary mimeTypeEncoders = new ConcurrentDictionary(); /// - /// The list of supported . + /// The list of supported keyed to mime types. /// - private readonly List imageFormatsList = new List(); + private readonly ConcurrentDictionary mimeTypeDecoders = new ConcurrentDictionary(); + + /// + /// The list of supported s. + /// + private readonly List imageFormatDetectors = new List(); + + /// + /// The list of supported s. + /// + private readonly HashSet imageFormats = new HashSet(); /// /// Initializes a new instance of the class. @@ -44,12 +54,15 @@ namespace ImageSharp /// /// Initializes a new instance of the class. /// - /// The inital set of image formats. - public Configuration(params IImageFormat[] providers) + /// A collection of configuration modules to register + public Configuration(params IConfigurationModule[] configurationModules) { - foreach (IImageFormat p in providers) + if (configurationModules != null) { - this.AddImageFormat(p); + foreach (IConfigurationModule p in configurationModules) + { + p.Configure(this); + } } } @@ -58,21 +71,36 @@ namespace ImageSharp /// public static Configuration Default { get; } = Lazy.Value; - /// - /// Gets the collection of supported - /// - public IReadOnlyCollection ImageFormats => new ReadOnlyCollection(this.imageFormatsList); - /// /// Gets the global parallel options for processing tasks in parallel. /// public ParallelOptions ParallelOptions { get; } = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; /// - /// Gets the maximum header size of all formats. + /// Gets the maximum header size of all the formats. /// internal int MaxHeaderSize { get; private set; } + /// + /// Gets the currently registered s. + /// + internal IEnumerable FormatDetectors => this.imageFormatDetectors; + + /// + /// Gets the currently registered s. + /// + internal IEnumerable> ImageDecoders => this.mimeTypeDecoders; + + /// + /// Gets the currently registered s. + /// + internal IEnumerable> ImageEncoders => this.mimeTypeEncoders; + + /// + /// Gets the currently registered s. + /// + internal IEnumerable ImageFormats => this.imageFormats; + #if !NETSTANDARD1_1 /// /// Gets or sets the fielsystem helper for accessing the local file system. @@ -81,127 +109,147 @@ namespace ImageSharp #endif /// - /// Adds a new to the collection of supported image formats. + /// Registers a new format provider. /// - /// The new format to add. + /// The configuration provider to call configure on. + public void Configure(IConfigurationModule configuration) + { + Guard.NotNull(configuration, nameof(configuration)); + configuration.Configure(this); + } + + /// + /// Registers a new format provider. + /// + /// The format to register as a well know format. public void AddImageFormat(IImageFormat format) { Guard.NotNull(format, nameof(format)); - Guard.NotNull(format.Encoder, nameof(format), "The encoder should not be null."); - Guard.NotNull(format.Decoder, nameof(format), "The decoder should not be null."); - Guard.NotNullOrEmpty(format.MimeType, nameof(format), "The mime type should not be null or empty."); - Guard.NotNullOrEmpty(format.Extension, nameof(format), "The extension should not be null or empty."); - Guard.NotNullOrEmpty(format.SupportedExtensions, nameof(format), "The supported extensions not be null or empty."); + Guard.NotNull(format.MimeTypes, nameof(format.MimeTypes)); + Guard.NotNull(format.FileExtensions, nameof(format.FileExtensions)); + this.imageFormats.Add(format); + } - this.AddImageFormatLocked(format); + /// + /// For the specified file extensions type find the e . + /// + /// The extension to discover + /// The if found otherwise null + public IImageFormat FindFormatByFileExtensions(string extension) + { + return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); } /// - /// Creates the default instance, with Png, Jpeg, Gif and Bmp preregisterd (if they have been referenced) + /// For the specified mime type find the . /// - /// The default configuration of - internal static Configuration CreateDefaultInstance() + /// The mime-type to discover + /// The if found otherwise null + public IImageFormat FindFormatByMimeType(string mimeType) { - Configuration config = new Configuration(); - - // lets try auto loading the known image formats - config.AddImageFormat(new Formats.PngFormat()); - config.AddImageFormat(new Formats.JpegFormat()); - config.AddImageFormat(new Formats.GifFormat()); - config.AddImageFormat(new Formats.BmpFormat()); - config.AddImageFormat(new Formats.TiffFormat()); - return config; + return this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase)); } /// - /// Tries the add image format. + /// Sets a specific image encoder as the encoder for a specific image format. /// - /// Name of the type. - /// True if type discoverd and is a valid - internal bool TryAddImageFormat(string typeName) + /// The image format to register the encoder for. + /// The encoder to use, + public void SetEncoder(IImageFormat imageFormat, IImageEncoder encoder) { - Type type = Type.GetType(typeName, false); - if (type != null) - { - IImageFormat format = Activator.CreateInstance(type) as IImageFormat; - if (format != null - && format.Encoder != null - && format.Decoder != null - && !string.IsNullOrEmpty(format.MimeType) - && format.SupportedExtensions?.Any() == true) - { - // we can use the locked version as we have already validated in the if. - this.AddImageFormatLocked(format); - return true; - } - } + Guard.NotNull(imageFormat, nameof(imageFormat)); + Guard.NotNull(encoder, nameof(encoder)); + this.AddImageFormat(imageFormat); + this.mimeTypeEncoders.AddOrUpdate(imageFormat, encoder, (s, e) => encoder); + } - return false; + /// + /// Sets a specific image decoder as the decoder for a specific image format. + /// + /// The image format to register the encoder for. + /// The decoder to use, + public void SetDecoder(IImageFormat imageFormat, IImageDecoder decoder) + { + Guard.NotNull(imageFormat, nameof(imageFormat)); + Guard.NotNull(decoder, nameof(decoder)); + this.AddImageFormat(imageFormat); + this.mimeTypeDecoders.AddOrUpdate(imageFormat, decoder, (s, e) => decoder); } /// - /// Adds image format. The class is locked to make it thread safe. + /// Removes all the registered image format detectors. /// - /// The image format. - private void AddImageFormatLocked(IImageFormat format) + public void ClearImageFormatDetectors() { - lock (this.syncRoot) - { - if (this.GuardDuplicate(format)) - { - this.imageFormatsList.Add(format); + this.imageFormatDetectors.Clear(); + } - this.SetMaxHeaderSize(); - } - } + /// + /// Adds a new detector for detecting mime types. + /// + /// The detector to add + public void AddImageFormatDetector(IImageFormatDetector detector) + { + Guard.NotNull(detector, nameof(detector)); + this.imageFormatDetectors.Add(detector); + this.SetMaxHeaderSize(); } /// - /// Checks to ensure duplicate image formats are not added. + /// Creates the default instance with the following s preregistered: + /// + /// + /// + /// /// - /// The image format. - /// Thrown if a duplicate is added. - /// - /// The . - /// - private bool GuardDuplicate(IImageFormat format) + /// The default configuration of + internal static Configuration CreateDefaultInstance() { - if (!format.SupportedExtensions.Contains(format.Extension, StringComparer.OrdinalIgnoreCase)) - { - throw new ArgumentException("The supported extensions should contain the default extension.", nameof(format)); - } + return new Configuration( + new PngConfigurationModule(), + new JpegConfigurationModule(), + new GifConfigurationModule(), + new BmpConfigurationModule()); + } - // ReSharper disable once ConvertClosureToMethodGroup - // Prevents method group allocation - if (format.SupportedExtensions.Any(e => string.IsNullOrWhiteSpace(e))) + /// + /// For the specified mime type find the decoder. + /// + /// The format to discover + /// The if found otherwise null + internal IImageDecoder FindDecoder(IImageFormat format) + { + Guard.NotNull(format, nameof(format)); + if (this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder)) { - throw new ArgumentException("The supported extensions should not contain empty values.", nameof(format)); + return decoder; } - // If there is already a format with the same extension or a format that supports that - // extension return false. - foreach (IImageFormat imageFormat in this.imageFormatsList) - { - if (imageFormat.Extension.Equals(format.Extension, StringComparison.OrdinalIgnoreCase)) - { - return false; - } + return null; + } - if (imageFormat.SupportedExtensions.Intersect(format.SupportedExtensions, StringComparer.OrdinalIgnoreCase).Any()) - { - return false; - } + /// + /// For the specified mime type find the encoder. + /// + /// The format to discover + /// The if found otherwise null + internal IImageEncoder FindEncoder(IImageFormat format) + { + Guard.NotNull(format, nameof(format)); + if (this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder)) + { + return encoder; } - return true; + return null; } /// - /// Sets max header size. + /// Sets the max header size. /// private void SetMaxHeaderSize() { - this.MaxHeaderSize = this.imageFormatsList.Max(x => x.HeaderSize); + this.MaxHeaderSize = this.imageFormatDetectors.Max(x => x.HeaderSize); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs new file mode 100644 index 0000000000..f70ff1a56d --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs @@ -0,0 +1,21 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Registers the image encoders, decoders and mime type detectors for the bmp format. + /// + public sealed class BmpConfigurationModule : IConfigurationModule + { + /// + public void Configure(Configuration config) + { + config.SetEncoder(ImageFormats.Bitmap, new BmpEncoder()); + config.SetDecoder(ImageFormats.Bitmap, new BmpDecoder()); + config.AddImageFormatDetector(new BmpImageFormatDetector()); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpConstants.cs b/src/ImageSharp/Formats/Bmp/BmpConstants.cs new file mode 100644 index 0000000000..d394b61f6e --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpConstants.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Collections.Generic; + + /// + /// Defines constants relating to BMPs + /// + internal static class BmpConstants + { + /// + /// The list of mimetypes that equate to a bmp. + /// + public static readonly IEnumerable MimeTypes = new[] { "image/bmp", "image/x-windows-bmp" }; + + /// + /// The list of file extensions that equate to a bmp. + /// + public static readonly IEnumerable FileExtensions = new[] { "bm", "bmp", "dip" }; + } +} diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index 9090e9a8cd..5baf1b1a5a 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -25,16 +26,16 @@ namespace ImageSharp.Formats /// Formats will be supported in a later releases. We advise always /// to use only 24 Bit Windows bitmaps. /// - public class BmpDecoder : IImageDecoder + public sealed class BmpDecoder : IImageDecoder, IBmpDecoderOptions { /// - public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) + public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { Guard.NotNull(stream, "stream"); - return new BmpDecoderCore(configuration).Decode(stream); + return new BmpDecoderCore(configuration, this).Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 997a77d6c5..817d00f7e7 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -52,7 +52,8 @@ namespace ImageSharp.Formats /// Initializes a new instance of the class. /// /// The configuration. - public BmpDecoderCore(Configuration configuration) + /// The options + public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options) { this.configuration = configuration; } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index dc2bc0e972..dfba0b41c0 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -14,28 +15,18 @@ namespace ImageSharp.Formats /// Image encoder for writing an image to a stream as a Windows bitmap. /// /// The encoder can currently only write 24-bit rgb images to streams. - public class BmpEncoder : IImageEncoder + public sealed class BmpEncoder : IImageEncoder, IBmpEncoderOptions { - /// - public void Encode(Image image, Stream stream, IEncoderOptions options) - where TPixel : struct, IPixel - { - IBmpEncoderOptions bmpOptions = BmpEncoderOptions.Create(options); - - this.Encode(image, stream, bmpOptions); - } - /// - /// Encodes the image to the specified stream from the . + /// Gets or sets the number of bits per pixel. /// - /// The pixel format. - /// The to encode from. - /// The to encode the image data to. - /// The options for the encoder. - public void Encode(Image image, Stream stream, IBmpEncoderOptions options) + public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; + + /// + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - BmpEncoderCore encoder = new BmpEncoderCore(options); + var encoder = new BmpEncoderCore(this); encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 617edde8eb..e41c295012 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -18,22 +18,22 @@ namespace ImageSharp.Formats internal sealed class BmpEncoderCore { /// - /// The options for the encoder. + /// The amount to pad each row by. /// - private readonly IBmpEncoderOptions options; + private int padding; /// - /// The amount to pad each row by. + /// Gets or sets the number of bits per pixel. /// - private int padding; + private BmpBitsPerPixel bitsPerPixel; /// /// Initializes a new instance of the class. /// - /// The options for the encoder. + /// The encoder options public BmpEncoderCore(IBmpEncoderOptions options) { - this.options = options ?? new BmpEncoderOptions(); + this.bitsPerPixel = options.BitsPerPixel; } /// @@ -49,9 +49,9 @@ namespace ImageSharp.Formats Guard.NotNull(stream, nameof(stream)); // Cast to int will get the bytes per pixel - short bpp = (short)(8 * (int)this.options.BitsPerPixel); + short bpp = (short)(8 * (int)this.bitsPerPixel); int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32); - this.padding = bytesPerLine - (image.Width * (int)this.options.BitsPerPixel); + this.padding = bytesPerLine - (image.Width * (int)this.bitsPerPixel); // Do not use IDisposable pattern here as we want to preserve the stream. EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); @@ -136,7 +136,7 @@ namespace ImageSharp.Formats { using (PixelAccessor pixels = image.Lock()) { - switch (this.options.BitsPerPixel) + switch (this.bitsPerPixel) { case BmpBitsPerPixel.Pixel32: this.Write32Bit(writer, pixels); diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderOptions.cs deleted file mode 100644 index a0f9ff8e05..0000000000 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderOptions.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - /// - /// Encapsulates the options for the . - /// - public sealed class BmpEncoderOptions : EncoderOptions, IBmpEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public BmpEncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the encoder. - private BmpEncoderOptions(IEncoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the number of bits per pixel. - /// - public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; - - /// - /// Converts the options to a instance with a cast - /// or by creating a new instance with the specfied options. - /// - /// The options for the encoder. - /// The options for the . - internal static IBmpEncoderOptions Create(IEncoderOptions options) - { - return options as IBmpEncoderOptions ?? new BmpEncoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs index 4be602f4b1..f9b20a48f8 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Formats /// All of the other integer values are stored in little-endian format /// (i.e. least-significant byte first). /// - internal class BmpFileHeader + internal sealed class BmpFileHeader { /// /// Defines of the data structure in the bitmap file. diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs index bf73d31621..fb65f34d7d 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -8,34 +8,20 @@ namespace ImageSharp.Formats using System.Collections.Generic; /// - /// Encapsulates the means to encode and decode bitmap images. + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// - public class BmpFormat : IImageFormat + internal sealed class BmpFormat : IImageFormat { /// - public string MimeType => "image/bmp"; + public string Name => "BMP"; /// - public string Extension => "bmp"; + public string DefaultMimeType => "image/bmp"; /// - public IEnumerable SupportedExtensions => new string[] { "bmp", "dip" }; + public IEnumerable MimeTypes => BmpConstants.MimeTypes; /// - public IImageDecoder Decoder => new BmpDecoder(); - - /// - public IImageEncoder Encoder => new BmpEncoder(); - - /// - public int HeaderSize => 2; - - /// - public bool IsSupportedFileFormat(byte[] header) - { - return header.Length >= this.HeaderSize && - header[0] == 0x42 && // B - header[1] == 0x4D; // M - } + public IEnumerable FileExtensions => BmpConstants.FileExtensions; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs new file mode 100644 index 0000000000..697ee0f981 --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -0,0 +1,37 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + + /// + /// Detects bmp file headers + /// + public sealed class BmpImageFormatDetector : IImageFormatDetector + { + /// + public int HeaderSize => 2; + + /// + public IImageFormat DetectFormat(ReadOnlySpan header) + { + if (this.IsSupportedFileFormat(header)) + { + return ImageFormats.Bitmap; + } + + return null; + } + + private bool IsSupportedFileFormat(ReadOnlySpan header) + { + // TODO: This should be in constants + return header.Length >= this.HeaderSize && + header[0] == 0x42 && // B + header[1] == 0x4D; // M + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index e652cb5044..dc6a489d34 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -10,7 +10,7 @@ namespace ImageSharp.Formats /// the screen. /// /// - internal class BmpInfoHeader + internal sealed class BmpInfoHeader { /// /// Defines of the data structure in the bitmap file. diff --git a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs new file mode 100644 index 0000000000..9285b9cf7a --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs @@ -0,0 +1,21 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + + /// + /// Image decoder options for decoding Windows bitmap streams. + /// + internal interface IBmpDecoderOptions + { + // added this for consistancy so we can add stuff as required, no options currently availible + } +} diff --git a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs index 6cf37cbae3..dd17043fad 100644 --- a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs +++ b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs @@ -1,14 +1,21 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { + using System; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + /// - /// Encapsulates the options for the . + /// Configuration options for use during bmp encoding /// - public interface IBmpEncoderOptions : IEncoderOptions + /// The encoder can currently only write 24-bit rgb images to streams. + internal interface IBmpEncoderOptions { /// /// Gets the number of bits per pixel. diff --git a/src/ImageSharp/Formats/DecoderOptions.cs b/src/ImageSharp/Formats/DecoderOptions.cs deleted file mode 100644 index 5257b07b39..0000000000 --- a/src/ImageSharp/Formats/DecoderOptions.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - /// - /// Encapsulates the shared decoder options. - /// - public class DecoderOptions : IDecoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public DecoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The decoder options - protected DecoderOptions(IDecoderOptions options) - { - if (options != null) - { - this.IgnoreMetadata = options.IgnoreMetadata; - } - } - - /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. - /// - public bool IgnoreMetadata { get; set; } = false; - } -} diff --git a/src/ImageSharp/Formats/EncoderOptions.cs b/src/ImageSharp/Formats/EncoderOptions.cs deleted file mode 100644 index 27a7e9781d..0000000000 --- a/src/ImageSharp/Formats/EncoderOptions.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - /// - /// Encapsulates the shared encoder options. - /// - public class EncoderOptions : IEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public EncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The encoder options - protected EncoderOptions(IEncoderOptions options) - { - if (options != null) - { - this.IgnoreMetadata = options.IgnoreMetadata; - } - } - - /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. - /// - public bool IgnoreMetadata { get; set; } = false; - } -} diff --git a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs new file mode 100644 index 0000000000..ee134d66cd --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs @@ -0,0 +1,22 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Registers the image encoders, decoders and mime type detectors for the gif format. + /// + public sealed class GifConfigurationModule : IConfigurationModule + { + /// + public void Configure(Configuration config) + { + config.SetEncoder(ImageFormats.Gif, new GifEncoder()); + config.SetDecoder(ImageFormats.Gif, new GifDecoder()); + + config.AddImageFormatDetector(new GifImageFormatDetector()); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index 4af291c2ba..9bec6c48f9 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -5,6 +5,7 @@ namespace ImageSharp.Formats { + using System.Collections.Generic; using System.Text; /// @@ -90,6 +91,16 @@ namespace ImageSharp.Formats /// /// Gets the default encoding to use when reading comments. /// - public static Encoding DefaultEncoding { get; } = Encoding.GetEncoding("ASCII"); + public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); + + /// + /// The list of mimetypes that equate to a gif. + /// + public static readonly IEnumerable MimeTypes = new[] { "image/gif" }; + + /// + /// The list of file extensions that equate to a gif. + /// + public static readonly IEnumerable FileExtensions = new[] { "gif" }; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index 88aaccf6a4..927289094f 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -6,37 +6,32 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; - + using System.Text; using ImageSharp.PixelFormats; /// /// Decoder for generating an image out of a gif encoded stream. /// - public class GifDecoder : IImageDecoder + public sealed class GifDecoder : IImageDecoder, IGifDecoderOptions { - /// - public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) - - where TPixel : struct, IPixel - { - IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options); - - return this.Decode(configuration, stream, gifOptions); - } + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } = false; /// - /// Decodes the image from the specified stream to the . + /// Gets or sets the encoding that should be used when reading comments. /// - /// The pixel format. - /// The configuration. - /// The containing image data. - /// The options for the decoder. - /// The image thats been decoded. - public Image Decode(Configuration configuration, Stream stream, IGifDecoderOptions options) + public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; + + /// + public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { - return new GifDecoderCore(options, configuration).Decode(stream); + var decoder = new GifDecoderCore(configuration, this); + return decoder.Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 5b56c4c02f..bb230beac7 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -12,12 +12,13 @@ namespace ImageSharp.Formats using System.Text; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Performs the gif decoding operation. /// /// The pixel format. - internal class GifDecoderCore + internal sealed class GifDecoderCore where TPixel : struct, IPixel { /// @@ -25,11 +26,6 @@ namespace ImageSharp.Formats /// private readonly byte[] buffer = new byte[16]; - /// - /// The decoder options. - /// - private readonly IGifDecoderOptions options; - /// /// The global configuration. /// @@ -83,14 +79,25 @@ namespace ImageSharp.Formats /// /// Initializes a new instance of the class. /// - /// The decoder options. /// The configuration. - public GifDecoderCore(IGifDecoderOptions options, Configuration configuration) + /// The decoder options. + public GifDecoderCore(Configuration configuration, IGifDecoderOptions options) { - this.options = options ?? new GifDecoderOptions(); + this.TextEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding; + this.IgnoreMetadata = options.IgnoreMetadata; this.configuration = configuration ?? Configuration.Default; } + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; internal set; } + + /// + /// Gets the text encoding + /// + public Encoding TextEncoding { get; private set; } + /// /// Decodes the stream to the image. /// @@ -268,7 +275,7 @@ namespace ImageSharp.Formats throw new ImageFormatException($"Gif comment length '{length}' exceeds max '{GifConstants.MaxCommentLength}'"); } - if (this.options.IgnoreMetadata) + if (this.IgnoreMetadata) { this.currentStream.Seek(length, SeekOrigin.Current); continue; @@ -279,7 +286,7 @@ namespace ImageSharp.Formats try { this.currentStream.Read(commentsBuffer, 0, length); - string comments = this.options.TextEncoding.GetString(commentsBuffer, 0, length); + string comments = this.TextEncoding.GetString(commentsBuffer, 0, length); this.metaData.Properties.Add(new ImageProperty(GifConstants.Comments, comments)); } finally @@ -363,8 +370,6 @@ namespace ImageSharp.Formats if (this.previousFrame == null) { - this.metaData.Quality = colorTableLength / 3; - // This initializes the image to become fully transparent because the alpha channel is zero. this.image = new Image(this.configuration, imageWidth, imageHeight, this.metaData); diff --git a/src/ImageSharp/Formats/Gif/GifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/GifDecoderOptions.cs deleted file mode 100644 index bc7709f759..0000000000 --- a/src/ImageSharp/Formats/Gif/GifDecoderOptions.cs +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Text; - - /// - /// Encapsulates the options for the . - /// - public sealed class GifDecoderOptions : DecoderOptions, IGifDecoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public GifDecoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the decoder. - private GifDecoderOptions(IDecoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the encoding that should be used when reading comments. - /// - public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; - - /// - /// Converts the options to a instance with a cast - /// or by creating a new instance with the specfied options. - /// - /// The options for the decoder. - /// The options for the . - internal static IGifDecoderOptions Create(IDecoderOptions options) - { - return options as IGifDecoderOptions ?? new GifDecoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index b5cadd834e..b48db56356 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -6,35 +6,47 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; - + using System.Text; using ImageSharp.PixelFormats; + using ImageSharp.Quantizers; /// /// Image encoder for writing image data to a stream in gif format. /// - public class GifEncoder : IImageEncoder + public sealed class GifEncoder : IImageEncoder, IGifEncoderOptions { - /// - public void Encode(Image image, Stream stream, IEncoderOptions options) - where TPixel : struct, IPixel - { - IGifEncoderOptions gifOptions = GifEncoderOptions.Create(options); + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. + /// + public bool IgnoreMetadata { get; set; } = false; - this.Encode(image, stream, gifOptions); - } + /// + /// Gets or sets the encoding that should be used when writing comments. + /// + public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; /// - /// Encodes the image to the specified stream from the . + /// Gets or sets the size of the color palette to use. For gifs the value ranges from 1 to 256. Leave as zero for default size. /// - /// The pixel format. - /// The to encode from. - /// The to encode the image data to. - /// The options for the encoder. - public void Encode(Image image, Stream stream, IGifEncoderOptions options) + public int PaletteSize { get; set; } = 0; + + /// + /// Gets or sets the transparency threshold. + /// + public byte Threshold { get; set; } = 128; + + /// + /// Gets or sets the quantizer for reducing the color count. + /// + public IQuantizer Quantizer { get; set; } + + /// + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - GifEncoderCore encoder = new GifEncoderCore(options); + GifEncoderCore encoder = new GifEncoderCore(this); encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 5ef7ca1658..81b3cfba4a 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -9,7 +9,7 @@ namespace ImageSharp.Formats using System.Buffers; using System.IO; using System.Linq; - + using System.Text; using ImageSharp.PixelFormats; using IO; @@ -25,11 +25,6 @@ namespace ImageSharp.Formats /// private readonly byte[] buffer = new byte[16]; - /// - /// The options for the encoder. - /// - private readonly IGifEncoderOptions options; - /// /// The number of bits requires to store the image palette. /// @@ -40,19 +35,44 @@ namespace ImageSharp.Formats /// private bool hasFrames; + /// + /// Gets the TextEncoding + /// + private Encoding textEncoding; + + /// + /// Gets or sets the quantizer for reducing the color count. + /// + private IQuantizer quantizer; + + /// + /// Gets or sets the threshold. + /// + private byte threshold; + + /// + /// Gets or sets the size of the color palette to use. + /// + private int paletteSize; + + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + private bool ignoreMetadata; + /// /// Initializes a new instance of the class. /// /// The options for the encoder. public GifEncoderCore(IGifEncoderOptions options) { - this.options = options ?? new GifEncoderOptions(); - } + this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding; - /// - /// Gets or sets the quantizer for reducing the color count. - /// - public IQuantizer Quantizer { get; set; } + this.quantizer = options.Quantizer; + this.threshold = options.Threshold; + this.paletteSize = options.PaletteSize; + this.ignoreMetadata = options.IgnoreMetadata; + } /// /// Encodes the image to the specified stream from the . @@ -66,26 +86,26 @@ namespace ImageSharp.Formats Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.Quantizer = this.options.Quantizer ?? new OctreeQuantizer(); + this.quantizer = this.quantizer ?? new OctreeQuantizer(); // Do not use IDisposable pattern here as we want to preserve the stream. var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); - // Ensure that quality can be set but has a fallback. - int quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; - quality = quality > 0 ? quality.Clamp(1, 256) : 256; + // Ensure that pallete size can be set but has a fallback. + int paletteSize = this.paletteSize; + paletteSize = paletteSize > 0 ? paletteSize.Clamp(1, 256) : 256; // Get the number of bits. - this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quality); + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(paletteSize); - // Quantize the image returning a palette. this.hasFrames = image.Frames.Any(); // Dithering when animating gifs is a bad idea as we introduce pixel tearing across frames. - var ditheredQuantizer = (IQuantizer)this.Quantizer; + var ditheredQuantizer = (IQuantizer)this.quantizer; ditheredQuantizer.Dither = !this.hasFrames; - QuantizedImage quantized = ditheredQuantizer.Quantize(image, quality); + // Quantize the image returning a palette. + QuantizedImage quantized = ditheredQuantizer.Quantize(image, paletteSize); int index = this.GetTransparentIndex(quantized); @@ -111,7 +131,7 @@ namespace ImageSharp.Formats for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; - QuantizedImage quantizedFrame = ditheredQuantizer.Quantize(frame, quality); + QuantizedImage quantizedFrame = ditheredQuantizer.Quantize(frame, paletteSize); this.WriteGraphicalControlExtension(frame.MetaData, writer, this.GetTransparentIndex(quantizedFrame)); this.WriteImageDescriptor(frame, writer); @@ -240,7 +260,7 @@ namespace ImageSharp.Formats private void WriteComments(Image image, EndianBinaryWriter writer) where TPixel : struct, IPixel { - if (this.options.IgnoreMetadata) + if (this.ignoreMetadata) { return; } @@ -251,7 +271,7 @@ namespace ImageSharp.Formats return; } - byte[] comments = this.options.TextEncoding.GetBytes(property.Value); + byte[] comments = this.textEncoding.GetBytes(property.Value); int count = Math.Min(comments.Length, 255); diff --git a/src/ImageSharp/Formats/Gif/GifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/GifEncoderOptions.cs deleted file mode 100644 index 5d7c6e40b6..0000000000 --- a/src/ImageSharp/Formats/Gif/GifEncoderOptions.cs +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Text; - - using Quantizers; - - /// - /// Encapsulates the options for the . - /// - public sealed class GifEncoderOptions : EncoderOptions, IGifEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public GifEncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the encoder. - private GifEncoderOptions(IEncoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the encoding that should be used when writing comments. - /// - public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding; - - /// - /// Gets or sets the quality of output for images. - /// - /// For gifs the value ranges from 1 to 256. - public int Quality { get; set; } - - /// - /// Gets or sets the transparency threshold. - /// - public byte Threshold { get; set; } = 128; - - /// - /// Gets or sets the quantizer for reducing the color count. - /// - public IQuantizer Quantizer { get; set; } - - /// - /// Converts the options to a instance with a - /// cast or by creating a new instance with the specfied options. - /// - /// The options for the encoder. - /// The options for the . - internal static IGifEncoderOptions Create(IEncoderOptions options) - { - return options as IGifEncoderOptions ?? new GifEncoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs index 2851b0b6b2..ea7b72d327 100644 --- a/src/ImageSharp/Formats/Gif/GifFormat.cs +++ b/src/ImageSharp/Formats/Gif/GifFormat.cs @@ -8,38 +8,20 @@ namespace ImageSharp.Formats using System.Collections.Generic; /// - /// Encapsulates the means to encode and decode gif images. + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// - public class GifFormat : IImageFormat + internal sealed class GifFormat : IImageFormat { /// - public string Extension => "gif"; + public string Name => "GIF"; /// - public string MimeType => "image/gif"; + public string DefaultMimeType => "image/gif"; /// - public IEnumerable SupportedExtensions => new string[] { "gif" }; + public IEnumerable MimeTypes => GifConstants.MimeTypes; /// - public IImageDecoder Decoder => new GifDecoder(); - - /// - public IImageEncoder Encoder => new GifEncoder(); - - /// - public int HeaderSize => 6; - - /// - public bool IsSupportedFileFormat(byte[] header) - { - return header.Length >= this.HeaderSize && - header[0] == 0x47 && // G - header[1] == 0x49 && // I - header[2] == 0x46 && // F - header[3] == 0x38 && // 8 - (header[4] == 0x39 || header[4] == 0x37) && // 9 or 7 - header[5] == 0x61; // a - } + public IEnumerable FileExtensions => GifConstants.FileExtensions; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs new file mode 100644 index 0000000000..04fcfc516c --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs @@ -0,0 +1,41 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + + /// + /// Detects gif file headers + /// + public sealed class GifImageFormatDetector : IImageFormatDetector + { + /// + public int HeaderSize => 6; + + /// + public IImageFormat DetectFormat(ReadOnlySpan header) + { + if (this.IsSupportedFileFormat(header)) + { + return ImageFormats.Gif; + } + + return null; + } + + private bool IsSupportedFileFormat(ReadOnlySpan header) + { + // TODO: This should be in constants + return header.Length >= this.HeaderSize && + header[0] == 0x47 && // G + header[1] == 0x49 && // I + header[2] == 0x46 && // F + header[3] == 0x38 && // 8 + (header[4] == 0x39 || header[4] == 0x37) && // 9 or 7 + header[5] == 0x61; // a + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs index 729bf1d111..caaa8932bb 100644 --- a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs +++ b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs @@ -1,17 +1,26 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { + using System; + using System.Collections.Generic; + using System.IO; using System.Text; + using ImageSharp.PixelFormats; /// - /// Encapsulates the options for the . + /// Decoder for generating an image out of a gif encoded stream. /// - public interface IGifDecoderOptions : IDecoderOptions + internal interface IGifDecoderOptions { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + bool IgnoreMetadata { get; } + /// /// Gets the encoding that should be used when reading comments. /// diff --git a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs index c1d6b7ad86..c38ec7e451 100644 --- a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs +++ b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs @@ -1,29 +1,36 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { + using System; + using System.Collections.Generic; + using System.IO; using System.Text; - - using Quantizers; + using ImageSharp.PixelFormats; + using ImageSharp.Quantizers; /// - /// Encapsulates the options for the . + /// The configuration options used for encoding gifs /// - public interface IGifEncoderOptions : IEncoderOptions + internal interface IGifEncoderOptions { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being encoded. + /// + bool IgnoreMetadata { get; } + /// /// Gets the encoding that should be used when writing comments. /// Encoding TextEncoding { get; } /// - /// Gets the quality of output for images. + /// Gets the size of the color palette to use. For gifs the value ranges from 1 to 256. Leave as zero for default size. /// - /// For gifs the value ranges from 1 to 256. - int Quality { get; } + int PaletteSize { get; } /// /// Gets the transparency threshold. @@ -33,6 +40,6 @@ namespace ImageSharp.Formats /// /// Gets the quantizer for reducing the color count. /// - IQuantizer Quantizer { get; } + IQuantizer Quantizer { get; } } } diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index d64203f6ce..ea9c9b5047 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -39,16 +39,16 @@ namespace ImageSharp /// The pixel format. /// The image this method extends. /// The stream to save the image to. - /// The options for the encoder. + /// The options for the encoder. /// Thrown if the stream is null. /// /// The . /// - public static Image SaveAsGif(this Image source, Stream stream, IGifEncoderOptions options) + public static Image SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel { - GifEncoder encoder = new GifEncoder(); - encoder.Encode(source, stream, options); + encoder = encoder ?? new GifEncoder(); + encoder.Encode(source, stream); return source; } diff --git a/src/ImageSharp/Formats/IEncoderOptions.cs b/src/ImageSharp/Formats/IEncoderOptions.cs deleted file mode 100644 index 0fd3d1c438..0000000000 --- a/src/ImageSharp/Formats/IEncoderOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - /// - /// Encapsulates the shared encoder options. - /// - public interface IEncoderOptions - { - /// - /// Gets a value indicating whether the metadata should be ignored when the image is being encoded. - /// - bool IgnoreMetadata { get; } - } -} diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs index 4fd25df13e..66eabb1b82 100644 --- a/src/ImageSharp/Formats/IImageDecoder.cs +++ b/src/ImageSharp/Formats/IImageDecoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -21,9 +22,8 @@ namespace ImageSharp.Formats /// The pixel format. /// The configuration for the image. /// The containing image data. - /// The options for the decoder. /// The decoded image - Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) + Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Formats/IImageEncoder.cs b/src/ImageSharp/Formats/IImageEncoder.cs index a28511c173..4ad41ebc27 100644 --- a/src/ImageSharp/Formats/IImageEncoder.cs +++ b/src/ImageSharp/Formats/IImageEncoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -21,8 +22,7 @@ namespace ImageSharp.Formats /// The pixel format. /// The to encode from. /// The to encode the image data to. - /// The options for the encoder. - void Encode(Image image, Stream stream, IEncoderOptions options) + void Encode(Image image, Stream stream) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index de2e400fa0..d6ddc0b0bb 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -8,53 +8,28 @@ namespace ImageSharp.Formats using System.Collections.Generic; /// - /// Encapsulates a supported image format, providing means to encode and decode an image. - /// Individual formats implements in this interface must be registered in the + /// Describes an image format. /// public interface IImageFormat { /// - /// Gets the standard identifier used on the Internet to indicate the type of data that a file contains. + /// Gets the name that describes this image format. /// - string MimeType { get; } + string Name { get; } /// - /// Gets the default file extension for this format. + /// Gets the default mimetype that the image foramt uses /// - string Extension { get; } + string DefaultMimeType { get; } /// - /// Gets the supported file extensions for this format. + /// Gets all the mimetypes that have been used by this image foramt. /// - /// - /// The supported file extension. - /// - IEnumerable SupportedExtensions { get; } + IEnumerable MimeTypes { get; } /// - /// Gets the image encoder for encoding an image from a stream. + /// Gets the file extensions this image format commonly uses. /// - IImageEncoder Encoder { get; } - - /// - /// Gets the image decoder for decoding an image from a stream. - /// - IImageDecoder Decoder { get; } - - /// - /// Gets the size of the header for this image type. - /// - /// The size of the header. - int HeaderSize { get; } - - /// - /// Returns a value indicating whether the supports the specified - /// file header. - /// - /// The containing the file header. - /// - /// True if the decoder supports the file header; otherwise, false. - /// - bool IsSupportedFileFormat(byte[] header); + IEnumerable FileExtensions { get; } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/IImageFormatDetector.cs b/src/ImageSharp/Formats/IImageFormatDetector.cs new file mode 100644 index 0000000000..a53da07e8b --- /dev/null +++ b/src/ImageSharp/Formats/IImageFormatDetector.cs @@ -0,0 +1,30 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + using System.Collections.Generic; + using System.Text; + + /// + /// Used for detecting mime types from a file header + /// + public interface IImageFormatDetector + { + /// + /// Gets the size of the header for this image type. + /// + /// The size of the header. + int HeaderSize { get; } + + /// + /// Detect mimetype + /// + /// The containing the file header. + /// returns the mime type of detected othersie returns null + IImageFormat DetectFormat(ReadOnlySpan header); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs index 89e327f0db..c9cc327b86 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs @@ -8,6 +8,7 @@ namespace ImageSharp.Formats.Jpg using System.Buffers; using ImageSharp.Memory; + using SixLabors.Primitives; /// /// Represents an image made up of three color components (luminance, blue chroma, red chroma) diff --git a/src/ImageSharp/Formats/IDecoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs similarity index 53% rename from src/ImageSharp/Formats/IDecoderOptions.cs rename to src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs index cdfd90d5e2..6830e2e4a5 100644 --- a/src/ImageSharp/Formats/IDecoderOptions.cs +++ b/src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs @@ -1,14 +1,20 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // -namespace ImageSharp +namespace ImageSharp.Formats { + using System; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + /// - /// Encapsulates the shared decoder options. + /// Image decoder for generating an image out of a jpg stream. /// - public interface IDecoderOptions + internal interface IJpegDecoderOptions { /// /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. diff --git a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs index a545179653..947c98ee2a 100644 --- a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs +++ b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs @@ -1,15 +1,26 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { + using System; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + /// - /// Encapsulates the options for the . + /// Encoder for writing the data image to a stream in jpeg format. /// - public interface IJpegEncoderOptions : IEncoderOptions + internal interface IJpegEncoderOptions { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + bool IgnoreMetadata { get; } + /// /// Gets the quality, that will be used to encode the image. Quality /// index must be between 0 and 100 (compression from max to min). diff --git a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs index 420af6b742..8fbf9e5a74 100644 --- a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs @@ -39,16 +39,16 @@ namespace ImageSharp /// The pixel format. /// The image this method extends. /// The stream to save the image to. - /// The options for the encoder. + /// The options for the encoder. /// Thrown if the stream is null. /// /// The . /// - public static Image SaveAsJpeg(this Image source, Stream stream, IJpegEncoderOptions options) + public static Image SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) where TPixel : struct, IPixel { - JpegEncoder encoder = new JpegEncoder(); - encoder.Encode(source, stream, options); + encoder = encoder ?? new JpegEncoder(); + encoder.Encode(source, stream); return source; } diff --git a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs new file mode 100644 index 0000000000..bb8c4e83f2 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs @@ -0,0 +1,22 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. + /// + public sealed class JpegConfigurationModule : IConfigurationModule + { + /// + public void Configure(Configuration config) + { + config.SetEncoder(ImageFormats.Jpeg, new JpegEncoder()); + config.SetDecoder(ImageFormats.Jpeg, new JpegDecoder()); + + config.AddImageFormatDetector(new JpegImageFormatDetector()); + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs index dcda39842e..99c0399dcc 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs @@ -5,6 +5,8 @@ namespace ImageSharp.Formats { + using System.Collections.Generic; + /// /// Defines jpeg constants defined in the specification. /// @@ -15,6 +17,16 @@ namespace ImageSharp.Formats /// public const ushort MaxLength = 65535; + /// + /// The list of mimetypes that equate to a jpeg. + /// + public static readonly IEnumerable MimeTypes = new[] { "image/jpeg", "image/pjpeg" }; + + /// + /// The list of file extensions that equate to a jpeg. + /// + public static readonly IEnumerable FileExtensions = new[] { "jpg", "jpeg", "jfif" }; + /// /// Represents high detail chroma horizontal subsampling. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index 56d025504d..b3caddeca7 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -13,15 +14,20 @@ namespace ImageSharp.Formats /// /// Image decoder for generating an image out of a jpg stream. /// - public class JpegDecoder : IImageDecoder + public sealed class JpegDecoder : IImageDecoder, IJpegDecoderOptions { + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } + /// - public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) + public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { Guard.NotNull(stream, "stream"); - using (JpegDecoderCore decoder = new JpegDecoderCore(options, configuration)) + using (JpegDecoderCore decoder = new JpegDecoderCore(configuration, this)) { return decoder.Decode(stream); } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 9716843719..0ce927e516 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Formats /// /// Performs the jpeg decoding operation. /// - internal unsafe class JpegDecoderCore : IDisposable + internal sealed unsafe class JpegDecoderCore : IDisposable { /// /// The maximum number of color components @@ -45,11 +45,6 @@ namespace ImageSharp.Formats /// private static YCbCrToRgbTables yCbCrToRgbTables = YCbCrToRgbTables.Create(); - /// - /// The decoder options. - /// - private readonly IDecoderOptions options; - /// /// The global configuration /// @@ -103,12 +98,12 @@ namespace ImageSharp.Formats /// /// Initializes a new instance of the class. /// - /// The decoder options. /// The configuration. - public JpegDecoderCore(IDecoderOptions options, Configuration configuration) + /// The options. + public JpegDecoderCore(Configuration configuration, IJpegDecoderOptions options) { + this.IgnoreMetadata = options.IgnoreMetadata; this.configuration = configuration ?? Configuration.Default; - this.options = options ?? new DecoderOptions(); this.HuffmanTrees = HuffmanTree.CreateHuffmanTrees(); this.QuantizationTables = new Block8x8F[MaxTq + 1]; this.Temp = new byte[2 * Block8x8F.ScalarCount]; @@ -190,6 +185,11 @@ namespace ImageSharp.Formats /// public int TotalMCUCount => this.MCUCountX * this.MCUCountY; + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; private set; } + /// /// Decodes the image from the specified and sets /// the data to image. @@ -938,7 +938,7 @@ namespace ImageSharp.Formats /// The image. private void ProcessApp1Marker(int remaining, ImageMetaData metadata) { - if (remaining < 6 || this.options.IgnoreMetadata) + if (remaining < 6 || this.IgnoreMetadata) { this.InputProcessor.Skip(remaining); return; @@ -968,7 +968,7 @@ namespace ImageSharp.Formats { // Length is 14 though we only need to check 12. const int Icclength = 14; - if (remaining < Icclength || this.options.IgnoreMetadata) + if (remaining < Icclength || this.IgnoreMetadata) { this.InputProcessor.Skip(remaining); return; diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index 152fd2c64c..6c6561468f 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -5,6 +5,8 @@ namespace ImageSharp.Formats { + using System; + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; @@ -12,16 +14,25 @@ namespace ImageSharp.Formats /// /// Encoder for writing the data image to a stream in jpeg format. /// - public class JpegEncoder : IImageEncoder + public sealed class JpegEncoder : IImageEncoder, IJpegEncoderOptions { - /// - public void Encode(Image image, Stream stream, IEncoderOptions options) - where TPixel : struct, IPixel - { - IJpegEncoderOptions gifOptions = JpegEncoderOptions.Create(options); + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } - this.Encode(image, stream, gifOptions); - } + /// + /// Gets or sets the quality, that will be used to encode the image. Quality + /// index must be between 0 and 100 (compression from max to min). + /// + /// The quality of the jpg image from 0 to 100. + public int Quality { get; set; } + + /// + /// Gets or sets the subsample ration, that will be used to encode the image. + /// + /// The subsample ratio of the jpg image. + public JpegSubsample? Subsample { get; set; } /// /// Encodes the image to the specified stream from the . @@ -29,12 +40,11 @@ namespace ImageSharp.Formats /// The pixel format. /// The to encode from. /// The to encode the image data to. - /// The options for the encoder. - public void Encode(Image image, Stream stream, IJpegEncoderOptions options) - where TPixel : struct, IPixel + public void Encode(Image image, Stream stream) + where TPixel : struct, IPixel { - JpegEncoderCore encode = new JpegEncoderCore(options); - encode.Encode(image, stream); + var encoder = new JpegEncoderCore(this); + encoder.Encode(image, stream); } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index b65a56e73d..d2b7d2d7c4 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -17,7 +17,7 @@ namespace ImageSharp.Formats /// /// Image encoder for writing an image to a stream as a jpeg. /// - internal unsafe class JpegEncoderCore + internal sealed unsafe class JpegEncoderCore { /// /// The number of quantization tables. @@ -124,11 +124,6 @@ namespace ImageSharp.Formats /// private readonly byte[] huffmanBuffer = new byte[179]; - /// - /// The options for the encoder. - /// - private readonly IJpegEncoderOptions options; - /// /// The accumulated bits to write to the stream. /// @@ -155,17 +150,38 @@ namespace ImageSharp.Formats private Stream outputStream; /// - /// The subsampling method to use. + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + private bool ignoreMetadata = false; + + /// + /// Gets or sets the quality, that will be used to encode the image. Quality + /// index must be between 0 and 100 (compression from max to min). /// - private JpegSubsample subsample; + /// The quality of the jpg image from 0 to 100. + private int quality = 0; + + /// + /// Gets or sets the subsampling method to use. + /// + private JpegSubsample? subsample; /// /// Initializes a new instance of the class. /// - /// The options for the encoder. + /// The options public JpegEncoderCore(IJpegEncoderOptions options) { - this.options = options ?? new JpegEncoderOptions(); + int quality = options.Quality; + if (quality == 0) + { + quality = 75; + } + + this.quality = quality; + this.subsample = options.Subsample ?? (quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); + + this.ignoreMetadata = options.IgnoreMetadata; } /// @@ -186,21 +202,13 @@ namespace ImageSharp.Formats throw new ImageFormatException($"Image is too large to encode at {image.Width}x{image.Height}."); } - // Ensure that quality can be set but has a fallback. - int quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; - if (quality == 0) - { - quality = 75; - } - - quality = quality.Clamp(1, 100); - this.outputStream = stream; - this.subsample = this.options.Subsample ?? (quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); + + int quality = this.quality.Clamp(1, 100); // Convert from a quality rating to a scaling factor. int scale; - if (quality < 50) + if (this.quality < 50) { scale = 5000 / quality; } @@ -788,7 +796,7 @@ namespace ImageSharp.Formats private void WriteProfiles(Image image) where TPixel : struct, IPixel { - if (this.options.IgnoreMetadata) + if (this.ignoreMetadata) { return; } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderOptions.cs deleted file mode 100644 index 73e483164c..0000000000 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderOptions.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - /// - /// Encapsulates the options for the . - /// - public sealed class JpegEncoderOptions : EncoderOptions, IJpegEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public JpegEncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the encoder. - private JpegEncoderOptions(IEncoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the quality, that will be used to encode the image. Quality - /// index must be between 0 and 100 (compression from max to min). - /// - /// - /// If the quality is less than or equal to 90, the subsampling ratio will switch to - /// - /// The quality of the jpg image from 0 to 100. - public int Quality { get; set; } - - /// - /// Gets or sets the subsample ration, that will be used to encode the image. - /// - /// The subsample ratio of the jpg image. - public JpegSubsample? Subsample { get; set; } - - /// - /// Converts the options to a instance with a - /// cast or by creating a new instance with the specfied options. - /// - /// The options for the encoder. - /// The options for the . - internal static IJpegEncoderOptions Create(IEncoderOptions options) - { - return options as IJpegEncoderOptions ?? new JpegEncoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs index b93c6ae690..23cd5d8752 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs @@ -8,82 +8,20 @@ namespace ImageSharp.Formats using System.Collections.Generic; /// - /// Encapsulates the means to encode and decode jpeg images. + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// - public class JpegFormat : IImageFormat + internal sealed class JpegFormat : IImageFormat { /// - public string MimeType => "image/jpeg"; + public string Name => "JPEG"; /// - public string Extension => "jpg"; + public string DefaultMimeType => "image/jpeg"; /// - public IEnumerable SupportedExtensions => new string[] { "jpg", "jpeg", "jfif" }; + public IEnumerable MimeTypes => JpegConstants.MimeTypes; /// - public IImageDecoder Decoder => new JpegDecoder(); - - /// - public IImageEncoder Encoder => new JpegEncoder(); - - /// - public int HeaderSize => 11; - - /// - public bool IsSupportedFileFormat(byte[] header) - { - return header.Length >= this.HeaderSize && - (IsJfif(header) || IsExif(header) || IsJpeg(header)); - } - - /// - /// Returns a value indicating whether the given bytes identify Jfif data. - /// - /// The bytes representing the file header. - /// The - private static bool IsJfif(byte[] header) - { - bool isJfif = - header[6] == 0x4A && // J - header[7] == 0x46 && // F - header[8] == 0x49 && // I - header[9] == 0x46 && // F - header[10] == 0x00; - - return isJfif; - } - - /// - /// Returns a value indicating whether the given bytes identify EXIF data. - /// - /// The bytes representing the file header. - /// The - private static bool IsExif(byte[] header) - { - bool isExif = - header[6] == 0x45 && // E - header[7] == 0x78 && // X - header[8] == 0x69 && // I - header[9] == 0x66 && // F - header[10] == 0x00; - - return isExif; - } - - /// - /// Returns a value indicating whether the given bytes identify Jpeg data. - /// This is a last chance resort for jpegs that contain ICC information. - /// - /// The bytes representing the file header. - /// The - private static bool IsJpeg(byte[] header) - { - bool isJpg = - header[0] == 0xFF && // 255 - header[1] == 0xD8; // 216 - - return isJpg; - } + public IEnumerable FileExtensions => JpegConstants.FileExtensions; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs new file mode 100644 index 0000000000..b72b290c04 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs @@ -0,0 +1,87 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + + /// + /// Detects Jpeg file headers + /// + public sealed class JpegImageFormatDetector : IImageFormatDetector + { + /// + public int HeaderSize => 11; + + /// + public IImageFormat DetectFormat(ReadOnlySpan header) + { + if (this.IsSupportedFileFormat(header)) + { + return ImageFormats.Jpeg; + } + + return null; + } + + private bool IsSupportedFileFormat(ReadOnlySpan header) + { + return header.Length >= this.HeaderSize && + (this.IsJfif(header) || this.IsExif(header) || this.IsJpeg(header)); + } + + /// + /// Returns a value indicating whether the given bytes identify Jfif data. + /// + /// The bytes representing the file header. + /// The + private bool IsJfif(ReadOnlySpan header) + { + // TODO: This should be in constants + bool isJfif = + header[6] == 0x4A && // J + header[7] == 0x46 && // F + header[8] == 0x49 && // I + header[9] == 0x46 && // F + header[10] == 0x00; + + return isJfif; + } + + /// + /// Returns a value indicating whether the given bytes identify EXIF data. + /// + /// The bytes representing the file header. + /// The + private bool IsExif(ReadOnlySpan header) + { + // TODO: This should be in constants + bool isExif = + header[6] == 0x45 && // E + header[7] == 0x78 && // X + header[8] == 0x69 && // I + header[9] == 0x66 && // F + header[10] == 0x00; + + return isExif; + } + + /// + /// Returns a value indicating whether the given bytes identify Jpeg data. + /// This is a last chance resort for jpegs that contain ICC information. + /// + /// The bytes representing the file header. + /// The + private bool IsJpeg(ReadOnlySpan header) + { + // TODO: This should be in constants + bool isJpg = + header[0] == 0xFF && // 255 + header[1] == 0xD8; // 216 + + return isJpg; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs index cc6d194bfc..de163ba7e5 100644 --- a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs @@ -1,17 +1,26 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { + using System; + using System.Collections.Generic; + using System.IO; using System.Text; + using ImageSharp.PixelFormats; /// - /// Encapsulates the options for the . + /// The optioas for decoding png images /// - public interface IPngDecoderOptions : IDecoderOptions + internal interface IPngDecoderOptions { + /// + /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + bool IgnoreMetadata { get; } + /// /// Gets the encoding that should be used when reading text chunks. /// diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 0008080d3f..8f0a4cd829 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -1,21 +1,30 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { - using Quantizers; + using System.Collections.Generic; + using System.IO; + + using ImageSharp.PixelFormats; + using ImageSharp.Quantizers; /// - /// Encapsulates the options for the . + /// The options availible for manipulating the encoder pipeline /// - public interface IPngEncoderOptions : IEncoderOptions + internal interface IPngEncoderOptions { /// - /// Gets the quality of output for images. + /// Gets a value indicating whether the metadata should be ignored when the image is being encoded. + /// + bool IgnoreMetadata { get; } + + /// + /// Gets the size of the color palette to use. Set to zero to leav png encoding to use pixel data. /// - int Quality { get; } + int PaletteSize { get; } /// /// Gets the png color type @@ -24,19 +33,20 @@ namespace ImageSharp.Formats /// /// Gets the compression level 1-9. + /// Defaults to 6. /// int CompressionLevel { get; } /// /// Gets the gamma value, that will be written /// the the stream, when the property - /// is set to true. + /// is set to true. The default value is 2.2F. /// /// The gamma value of the image. float Gamma { get; } /// - /// Gets quantizer for reducing the color count. + /// Gets quantizer for reducing the color count. /// IQuantizer Quantizer { get; } @@ -47,7 +57,7 @@ namespace ImageSharp.Formats /// /// Gets a value indicating whether this instance should write - /// gamma information to the stream. + /// gamma information to the stream. The default value is false. /// bool WriteGamma { get; } } diff --git a/src/ImageSharp/Formats/Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs index 44f242b3f8..c817385760 100644 --- a/src/ImageSharp/Formats/Png/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Png/ImageExtensions.cs @@ -38,16 +38,16 @@ namespace ImageSharp /// The pixel format. /// The image this method extends. /// The stream to save the image to. - /// The options for the encoder. + /// The options for the encoder. /// Thrown if the stream is null. /// /// The . /// - public static Image SaveAsPng(this Image source, Stream stream, IPngEncoderOptions options) + public static Image SaveAsPng(this Image source, Stream stream, PngEncoder encoder) where TPixel : struct, IPixel { - PngEncoder encoder = new PngEncoder(); - encoder.Encode(source, stream, options); + encoder = encoder ?? new PngEncoder(); + encoder.Encode(source, stream); return source; } diff --git a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs new file mode 100644 index 0000000000..bb1c2086cc --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs @@ -0,0 +1,21 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + /// + /// Registers the image encoders, decoders and mime type detectors for the png format. + /// + public sealed class PngConfigurationModule : IConfigurationModule + { + /// + public void Configure(Configuration host) + { + host.SetEncoder(ImageFormats.Png, new PngEncoder()); + host.SetDecoder(ImageFormats.Png, new PngDecoder()); + host.AddImageFormatDetector(new PngImageFormatDetector()); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngConstants.cs b/src/ImageSharp/Formats/Png/PngConstants.cs new file mode 100644 index 0000000000..84e76a3419 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngConstants.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Collections.Generic; + using System.Text; + + /// + /// Defines png constants defined in the specification. + /// + internal static class PngConstants + { + /// + /// The default encoding for text metadata. + /// + public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); + + /// + /// The list of mimetypes that equate to a png. + /// + public static readonly IEnumerable MimeTypes = new[] { "image/png" }; + + /// + /// The list of file extensions that equate to a png. + /// + public static readonly IEnumerable FileExtensions = new[] { "png" }; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index 3a34147e2c..61a8cb2127 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -6,8 +6,9 @@ namespace ImageSharp.Formats { using System; + using System.Collections.Generic; using System.IO; - + using System.Text; using ImageSharp.PixelFormats; /// @@ -30,17 +31,17 @@ namespace ImageSharp.Formats /// /// /// - public class PngDecoder : IImageDecoder + public sealed class PngDecoder : IImageDecoder, IPngDecoderOptions { - /// - public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options) - - where TPixel : struct, IPixel - { - IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options); + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + public bool IgnoreMetadata { get; set; } - return this.Decode(configuration, stream, pngOptions); - } + /// + /// Gets or sets the encoding that should be used when reading text chunks. + /// + public Encoding TextEncoding { get; set; } = PngConstants.DefaultEncoding; /// /// Decodes the image from the specified stream to the . @@ -48,12 +49,12 @@ namespace ImageSharp.Formats /// The pixel format. /// The configuration for the image. /// The containing image data. - /// The options for the decoder. /// The decoded image. - public Image Decode(Configuration configuration, Stream stream, IPngDecoderOptions options) + public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { - return new PngDecoderCore(options, configuration).Decode(stream); + var decoder = new PngDecoderCore(configuration, this); + return decoder.Decode(stream); } } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index e0bd153e63..e6f19b9157 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Formats using System.IO; using System.Linq; using System.Runtime.CompilerServices; - + using System.Text; using ImageSharp.Memory; using ImageSharp.PixelFormats; @@ -20,7 +20,7 @@ namespace ImageSharp.Formats /// /// Performs the png decoding operation. /// - internal class PngDecoderCore + internal sealed class PngDecoderCore { /// /// The dictionary of available color types. @@ -28,10 +28,10 @@ namespace ImageSharp.Formats private static readonly Dictionary ColorTypes = new Dictionary() { [PngColorType.Grayscale] = new byte[] { 1, 2, 4, 8 }, - [PngColorType.Rgb] = new byte[] { 8 }, + [PngColorType.Rgb] = new byte[] { 8, 16 }, [PngColorType.Palette] = new byte[] { 1, 2, 4, 8 }, [PngColorType.GrayscaleWithAlpha] = new byte[] { 8 }, - [PngColorType.RgbWithAlpha] = new byte[] { 8 }, + [PngColorType.RgbWithAlpha] = new byte[] { 8, 16 } }; /// @@ -74,11 +74,6 @@ namespace ImageSharp.Formats /// private readonly char[] chars = new char[4]; - /// - /// The decoder options. - /// - private readonly IPngDecoderOptions options; - /// /// Reusable crc for validating chunks. /// @@ -147,29 +142,40 @@ namespace ImageSharp.Formats /// /// The current pass for an interlaced PNG /// - private int pass = 0; + private int pass; /// /// The current number of bytes read in the current scanline /// - private int currentRowBytesRead = 0; + private int currentRowBytesRead; + + /// + /// Gets or sets the png color type + /// + private PngColorType pngColorType; + + /// + /// Gets the encoding to use + /// + private Encoding textEncoding; + + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// + private bool ignoreMetadata; /// /// Initializes a new instance of the class. /// - /// The decoder options. /// The configuration. - public PngDecoderCore(IPngDecoderOptions options, Configuration configuration) + /// The decoder options. + public PngDecoderCore(Configuration configuration, IPngDecoderOptions options) { this.configuration = configuration ?? Configuration.Default; - this.options = options ?? new PngDecoderOptions(); + this.textEncoding = options.TextEncoding ?? PngConstants.DefaultEncoding; + this.ignoreMetadata = options.IgnoreMetadata; } - /// - /// Gets or sets the png color type - /// - public PngColorType PngColorType { get; set; } - /// /// Decodes the stream to the image. /// @@ -221,7 +227,6 @@ namespace ImageSharp.Formats byte[] pal = new byte[currentChunk.Length]; Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length); this.palette = pal; - metadata.Quality = pal.Length / 3; break; case PngChunkTypes.PaletteAlpha: byte[] alpha = new byte[currentChunk.Length]; @@ -325,11 +330,6 @@ namespace ImageSharp.Formats private void InitializeImage(ImageMetaData metadata, out Image image) where TPixel : struct, IPixel { - if (this.header.Width > Image.MaxWidth || this.header.Height > Image.MaxHeight) - { - throw new ArgumentOutOfRangeException($"The input png '{this.header.Width}x{this.header.Height}' is bigger than the max allowed size '{Image.MaxWidth}x{Image.MaxHeight}'"); - } - image = new Image(this.configuration, this.header.Width, this.header.Height, metadata); this.bytesPerPixel = this.CalculateBytesPerPixel(); this.bytesPerScanline = this.CalculateScanlineLength(this.header.Width) + 1; @@ -349,7 +349,7 @@ namespace ImageSharp.Formats /// The private int CalculateBytesPerPixel() { - switch (this.PngColorType) + switch (this.pngColorType) { case PngColorType.Grayscale: return 1; @@ -361,10 +361,20 @@ namespace ImageSharp.Formats return 1; case PngColorType.Rgb: + if (this.header.BitDepth == 16) + { + return 6; + } + return 3; - // PngColorType.RgbWithAlpha: + case PngColorType.RgbWithAlpha: default: + if (this.header.BitDepth == 16) + { + return 8; + } + return 4; } } @@ -378,15 +388,16 @@ namespace ImageSharp.Formats /// private int CalculateScanlineLength(int width) { + int mod = this.header.BitDepth == 16 ? 16 : 8; int scanlineLength = width * this.header.BitDepth * this.bytesPerPixel; - int amount = scanlineLength % 8; + int amount = scanlineLength % mod; if (amount != 0) { - scanlineLength += 8 - amount; + scanlineLength += mod - amount; } - return scanlineLength / 8; + return scanlineLength / mod; } /// @@ -566,7 +577,7 @@ namespace ImageSharp.Formats Span rowSpan = pixels.GetRowSpan(this.currentRow); var scanlineBuffer = new Span(defilteredScanline, 1); - switch (this.PngColorType) + switch (this.pngColorType) { case PngColorType.Grayscale: int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); @@ -589,7 +600,7 @@ namespace ImageSharp.Formats byte intensity = defilteredScanline[offset]; byte alpha = defilteredScanline[offset + this.bytesPerSample]; - color.PackFromRgba32(new Rgba32(intensity, intensity, intensity)); + color.PackFromRgba32(new Rgba32(intensity, intensity, intensity, alpha)); rowSpan[x] = color; } @@ -603,18 +614,59 @@ namespace ImageSharp.Formats case PngColorType.Rgb: - PixelOperations.Instance.PackFromRgb24Bytes(scanlineBuffer, rowSpan, this.header.Width); + if (this.header.BitDepth == 16) + { + int length = this.header.Width * 3; + using (var compressed = new Buffer(length)) + { + // TODO: Should we use pack from vector here instead? + this.From16BitTo8Bit(scanlineBuffer, compressed, length); + PixelOperations.Instance.PackFromRgb24Bytes(compressed, rowSpan, this.header.Width); + } + } + else + { + PixelOperations.Instance.PackFromRgb24Bytes(scanlineBuffer, rowSpan, this.header.Width); + } break; case PngColorType.RgbWithAlpha: - PixelOperations.Instance.PackFromRgba32Bytes(scanlineBuffer, rowSpan, this.header.Width); + if (this.header.BitDepth == 16) + { + int length = this.header.Width * 4; + using (var compressed = new Buffer(length)) + { + // TODO: Should we use pack from vector here instead? + this.From16BitTo8Bit(scanlineBuffer, compressed, length); + PixelOperations.Instance.PackFromRgba32Bytes(compressed, rowSpan, this.header.Width); + } + } + else + { + PixelOperations.Instance.PackFromRgba32Bytes(scanlineBuffer, rowSpan, this.header.Width); + } break; } } + /// + /// Compresses the given span from 16bpp to 8bpp + /// + /// The source buffer + /// The target buffer + /// The target length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void From16BitTo8Bit(Span source, Span target, int length) + { + for (int i = 0, j = 0; i < length; i++, j += 2) + { + target[i] = (byte)((source[j + 1] << 8) + source[j]); + } + } + /// /// Processes a scanline that uses a palette /// @@ -625,10 +677,10 @@ namespace ImageSharp.Formats where TPixel : struct, IPixel { byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); - byte[] palette = this.palette; + byte[] pal = this.palette; var color = default(TPixel); - Rgba32 rgba = default(Rgba32); + var rgba = default(Rgba32); if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) { @@ -643,7 +695,7 @@ namespace ImageSharp.Formats if (rgba.A > 0) { - rgba.Rgb = palette.GetRgb24(pixelOffset); + rgba.Rgb = pal.GetRgb24(pixelOffset); } else { @@ -663,7 +715,7 @@ namespace ImageSharp.Formats int index = newScanline[x + 1]; int pixelOffset = index * 3; - rgba.Rgb = palette.GetRgb24(pixelOffset); + rgba.Rgb = pal.GetRgb24(pixelOffset); color.PackFromRgba32(rgba); row[x] = color; @@ -684,11 +736,14 @@ namespace ImageSharp.Formats { var color = default(TPixel); - switch (this.PngColorType) + switch (this.pngColorType) { case PngColorType.Grayscale: int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); - byte[] newScanline1 = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); + byte[] newScanline1 = ToArrayByBitsLength( + defilteredScanline, + this.bytesPerScanline, + this.header.BitDepth); for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o++) { byte intensity = (byte)(newScanline1[o] * factor); @@ -712,8 +767,11 @@ namespace ImageSharp.Formats case PngColorType.Palette: - byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); - Rgba32 rgba = default(Rgba32); + byte[] newScanline = ToArrayByBitsLength( + defilteredScanline, + this.bytesPerScanline, + this.header.BitDepth); + var rgba = default(Rgba32); if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) { @@ -760,29 +818,75 @@ namespace ImageSharp.Formats case PngColorType.Rgb: rgba.A = 255; - for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) + + if (this.header.BitDepth == 16) { - rgba.R = defilteredScanline[o]; - rgba.G = defilteredScanline[o + this.bytesPerSample]; - rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)]; + int length = this.header.Width * 3; + using (var compressed = new Buffer(length)) + { + // TODO: Should we use pack from vector here instead? + this.From16BitTo8Bit(new Span(defilteredScanline), compressed, length); + for (int x = pixelOffset, o = 1; + x < this.header.Width; + x += increment, o += this.bytesPerPixel) + { + rgba.R = compressed[o]; + rgba.G = compressed[o + this.bytesPerSample]; + rgba.B = compressed[o + (2 * this.bytesPerSample)]; - color.PackFromRgba32(rgba); - rowSpan[x] = color; + color.PackFromRgba32(rgba); + rowSpan[x] = color; + } + } + } + else + { + for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) + { + rgba.R = defilteredScanline[o]; + rgba.G = defilteredScanline[o + this.bytesPerSample]; + rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)]; + + color.PackFromRgba32(rgba); + rowSpan[x] = color; + } } break; case PngColorType.RgbWithAlpha: - for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) + if (this.header.BitDepth == 16) { - rgba.R = defilteredScanline[o]; - rgba.G = defilteredScanline[o + this.bytesPerSample]; - rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)]; - rgba.A = defilteredScanline[o + (3 * this.bytesPerSample)]; + int length = this.header.Width * 4; + using (var compressed = new Buffer(length)) + { + // TODO: Should we use pack from vector here instead? + this.From16BitTo8Bit(new Span(defilteredScanline), compressed, length); + for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) + { + rgba.R = compressed[o]; + rgba.G = compressed[o + this.bytesPerSample]; + rgba.B = compressed[o + (2 * this.bytesPerSample)]; + rgba.A = compressed[o + (3 * this.bytesPerSample)]; - color.PackFromRgba32(rgba); - rowSpan[x] = color; + color.PackFromRgba32(rgba); + rowSpan[x] = color; + } + } + } + else + { + for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel) + { + rgba.R = defilteredScanline[o]; + rgba.G = defilteredScanline[o + this.bytesPerSample]; + rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)]; + rgba.A = defilteredScanline[o + (3 * this.bytesPerSample)]; + + color.PackFromRgba32(rgba); + rowSpan[x] = color; + } } break; @@ -797,7 +901,7 @@ namespace ImageSharp.Formats /// The maximum length to read. private void ReadTextChunk(ImageMetaData metadata, byte[] data, int length) { - if (this.options.IgnoreMetadata) + if (this.ignoreMetadata) { return; } @@ -813,8 +917,8 @@ namespace ImageSharp.Formats } } - string name = this.options.TextEncoding.GetString(data, 0, zeroIndex); - string value = this.options.TextEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); + string name = this.textEncoding.GetString(data, 0, zeroIndex); + string value = this.textEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); metadata.Properties.Add(new ImageProperty(name, value)); } @@ -868,7 +972,7 @@ namespace ImageSharp.Formats throw new NotSupportedException("The png specification only defines 'None' and 'Adam7' as interlaced methods."); } - this.PngColorType = (PngColorType)this.header.ColorType; + this.pngColorType = this.header.ColorType; } /// @@ -985,13 +1089,13 @@ namespace ImageSharp.Formats /// /// Returns the correct number of columns for each interlaced pass. /// - /// Th current pass index + /// Th current pass index /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int ComputeColumnsAdam7(int pass) + private int ComputeColumnsAdam7(int passIndex) { int width = this.header.Width; - switch (pass) + switch (passIndex) { case 0: return (width + 7) / 8; case 1: return (width + 3) / 8; @@ -1000,7 +1104,7 @@ namespace ImageSharp.Formats case 4: return (width + 1) / 2; case 5: return width / 2; case 6: return width; - default: throw new ArgumentException($"Not a valid pass index: {pass}"); + default: throw new ArgumentException($"Not a valid pass index: {passIndex}"); } } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs deleted file mode 100644 index e8990ec456..0000000000 --- a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using System.Text; - - /// - /// Encapsulates the options for the . - /// - public sealed class PngDecoderOptions : DecoderOptions, IPngDecoderOptions - { - private static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); - - /// - /// Initializes a new instance of the class. - /// - public PngDecoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the decoder. - private PngDecoderOptions(IDecoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the encoding that should be used when reading text chunks. - /// - public Encoding TextEncoding { get; set; } = DefaultEncoding; - - /// - /// Converts the options to a instance with a cast - /// or by creating a new instance with the specfied options. - /// - /// The options for the decoder. - /// The options for the . - internal static IPngDecoderOptions Create(IDecoderOptions options) - { - return options as IPngDecoderOptions ?? new PngDecoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index f89b624f78..bfd82a0748 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -5,23 +5,61 @@ namespace ImageSharp.Formats { + using System.Collections.Generic; using System.IO; using ImageSharp.PixelFormats; + using ImageSharp.Quantizers; /// /// Image encoder for writing image data to a stream in png format. /// - public class PngEncoder : IImageEncoder + public sealed class PngEncoder : IImageEncoder, IPngEncoderOptions { - /// - public void Encode(Image image, Stream stream, IEncoderOptions options) - where TPixel : struct, IPixel - { - IPngEncoderOptions pngOptions = PngEncoderOptions.Create(options); + /// + /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. + /// + public bool IgnoreMetadata { get; set; } - this.Encode(image, stream, pngOptions); - } + /// + /// Gets or sets the size of the color palette to use. Set to zero to leav png encoding to use pixel data. + /// + public int PaletteSize { get; set; } = 0; + + /// + /// Gets or sets the png color type + /// + public PngColorType PngColorType { get; set; } = PngColorType.RgbWithAlpha; + + /// + /// Gets or sets the compression level 1-9. + /// Defaults to 6. + /// + public int CompressionLevel { get; set; } = 6; + + /// + /// Gets or sets the gamma value, that will be written + /// the the stream, when the property + /// is set to true. The default value is 2.2F. + /// + /// The gamma value of the image. + public float Gamma { get; set; } = 2.2F; + + /// + /// Gets or sets quantizer for reducing the color count. + /// + public IQuantizer Quantizer { get; set; } + + /// + /// Gets or sets the transparency threshold. + /// + public byte Threshold { get; set; } = 255; + + /// + /// Gets or sets a value indicating whether this instance should write + /// gamma information to the stream. The default value is false. + /// + public bool WriteGamma { get; set; } /// /// Encodes the image to the specified stream from the . @@ -29,13 +67,12 @@ namespace ImageSharp.Formats /// The pixel format. /// The to encode from. /// The to encode the image data to. - /// The options for the encoder. - public void Encode(Image image, Stream stream, IPngEncoderOptions options) + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - using (var encode = new PngEncoderCore(options)) + using (var encoder = new PngEncoderCore(this)) { - encode.Encode(image, stream); + encoder.Encode(image, stream); } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 645df05481..cfbd0c4493 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -43,11 +43,6 @@ namespace ImageSharp.Formats /// private readonly Crc32 crc = new Crc32(); - /// - /// The options for the encoder. - /// - private readonly IPngEncoderOptions options; - /// /// Contains the raw pixel data from an indexed image. /// @@ -113,11 +108,6 @@ namespace ImageSharp.Formats /// private Buffer paeth; - /// - /// The quality of output for images. - /// - private int quality; - /// /// The png color type. /// @@ -128,13 +118,50 @@ namespace ImageSharp.Formats /// private IQuantizer quantizer; + /// + /// Gets or sets a value indicating whether to ignore metadata + /// + private bool ignoreMetadata; + + /// + /// Gets or sets the Quality value + /// + private int paletteSize; + + /// + /// Gets or sets the CompressionLevel value + /// + private int compressionLevel; + + /// + /// Gets or sets the Gamma value + /// + private float gamma; + + /// + /// Gets or sets the Threshold value + /// + private byte threshold; + + /// + /// Gets or sets a value indicating whether to Write Gamma + /// + private bool writeGamma; + /// /// Initializes a new instance of the class. /// - /// The options for the encoder. + /// The options for influancing the encoder public PngEncoderCore(IPngEncoderOptions options) { - this.options = options ?? new PngEncoderOptions(); + this.ignoreMetadata = options.IgnoreMetadata; + this.paletteSize = options.PaletteSize > 0 ? options.PaletteSize.Clamp(1, int.MaxValue) : int.MaxValue; + this.pngColorType = options.PngColorType; + this.compressionLevel = options.CompressionLevel; + this.gamma = options.Gamma; + this.quantizer = options.Quantizer; + this.threshold = options.Threshold; + this.writeGamma = options.WriteGamma; } /// @@ -164,27 +191,20 @@ namespace ImageSharp.Formats stream.Write(this.chunkDataBuffer, 0, 8); - // Ensure that quality can be set but has a fallback. - this.quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; - this.quality = this.quality > 0 ? this.quality.Clamp(1, int.MaxValue) : int.MaxValue; - - this.pngColorType = this.options.PngColorType; - this.quantizer = this.options.Quantizer; - // Set correct color type if the color count is 256 or less. - if (this.quality <= 256) + if (this.paletteSize <= 256) { this.pngColorType = PngColorType.Palette; } - if (this.pngColorType == PngColorType.Palette && this.quality > 256) + if (this.pngColorType == PngColorType.Palette && this.paletteSize > 256) { - this.quality = 256; + this.paletteSize = 256; } // Set correct bit depth. - this.bitDepth = this.quality <= 256 - ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.quality).Clamp(1, 8) + this.bitDepth = this.paletteSize <= 256 + ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.paletteSize).Clamp(1, 8) : (byte)8; // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk @@ -514,7 +534,7 @@ namespace ImageSharp.Formats private QuantizedImage WritePaletteChunk(Stream stream, PngHeader header, ImageBase image) where TPixel : struct, IPixel { - if (this.quality > 256) + if (this.paletteSize > 256) { return null; } @@ -525,7 +545,7 @@ namespace ImageSharp.Formats } // Quantize the image returning a palette. This boxing is icky. - QuantizedImage quantized = ((IQuantizer)this.quantizer).Quantize(image, this.quality); + QuantizedImage quantized = ((IQuantizer)this.quantizer).Quantize(image, this.paletteSize); // Grab the palette and write it to the stream. TPixel[] palette = quantized.Palette; @@ -552,7 +572,7 @@ namespace ImageSharp.Formats colorTable[offset + 1] = bytes[1]; colorTable[offset + 2] = bytes[2]; - if (alpha > this.options.Threshold) + if (alpha > this.threshold) { alpha = 255; } @@ -610,9 +630,9 @@ namespace ImageSharp.Formats /// The containing image data. private void WriteGammaChunk(Stream stream) { - if (this.options.WriteGamma) + if (this.writeGamma) { - int gammaValue = (int)(this.options.Gamma * 100000F); + int gammaValue = (int)(this.gamma * 100000F); byte[] size = BitConverter.GetBytes(gammaValue); @@ -655,7 +675,7 @@ namespace ImageSharp.Formats try { memoryStream = new MemoryStream(); - using (var deflateStream = new ZlibDeflateStream(memoryStream, this.options.CompressionLevel)) + using (var deflateStream = new ZlibDeflateStream(memoryStream, this.compressionLevel)) { for (int y = 0; y < this.height; y++) { diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs deleted file mode 100644 index 90175c6d65..0000000000 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ /dev/null @@ -1,82 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Formats -{ - using Quantizers; - - /// - /// Encapsulates the options for the . - /// - public sealed class PngEncoderOptions : EncoderOptions, IPngEncoderOptions - { - /// - /// Initializes a new instance of the class. - /// - public PngEncoderOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The options for the encoder. - private PngEncoderOptions(IEncoderOptions options) - : base(options) - { - } - - /// - /// Gets or sets the quality of output for images. - /// - public int Quality { get; set; } - - /// - /// Gets or sets the png color type - /// - public PngColorType PngColorType { get; set; } = PngColorType.RgbWithAlpha; - - /// - /// Gets or sets the compression level 1-9. - /// Defaults to 6. - /// - public int CompressionLevel { get; set; } = 6; - - /// - /// Gets or sets the gamma value, that will be written - /// the the stream, when the property - /// is set to true. The default value is 2.2F. - /// - /// The gamma value of the image. - public float Gamma { get; set; } = 2.2F; - - /// - /// Gets or sets quantizer for reducing the color count. - /// - public IQuantizer Quantizer { get; set; } - - /// - /// Gets or sets the transparency threshold. - /// - public byte Threshold { get; set; } = 255; - - /// - /// Gets or sets a value indicating whether this instance should write - /// gamma information to the stream. The default value is false. - /// - public bool WriteGamma { get; set; } - - /// - /// Converts the options to a instance with a - /// cast or by creating a new instance with the specfied options. - /// - /// The options for the encoder. - /// The options for the . - internal static IPngEncoderOptions Create(IEncoderOptions options) - { - return options as IPngEncoderOptions ?? new PngEncoderOptions(options); - } - } -} diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs index 0f5a74da04..551b4a8c78 100644 --- a/src/ImageSharp/Formats/Png/PngFormat.cs +++ b/src/ImageSharp/Formats/Png/PngFormat.cs @@ -8,40 +8,20 @@ namespace ImageSharp.Formats using System.Collections.Generic; /// - /// Encapsulates the means to encode and decode png images. + /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// - public class PngFormat : IImageFormat + internal sealed class PngFormat : IImageFormat { /// - public string MimeType => "image/png"; + public string Name => "PNG"; /// - public string Extension => "png"; + public string DefaultMimeType => "image/png"; /// - public IEnumerable SupportedExtensions => new string[] { "png" }; + public IEnumerable MimeTypes => PngConstants.MimeTypes; /// - public IImageDecoder Decoder => new PngDecoder(); - - /// - public IImageEncoder Encoder => new PngEncoder(); - - /// - public int HeaderSize => 8; - - /// - public bool IsSupportedFileFormat(byte[] header) - { - return header.Length >= this.HeaderSize && - header[0] == 0x89 && - header[1] == 0x50 && // P - header[2] == 0x4E && // N - header[3] == 0x47 && // G - header[4] == 0x0D && // CR - header[5] == 0x0A && // LF - header[6] == 0x1A && // EOF - header[7] == 0x0A; // LF - } + public IEnumerable FileExtensions => PngConstants.FileExtensions; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs index 50d6cc9eca..9cf823fa19 100644 --- a/src/ImageSharp/Formats/Png/PngHeader.cs +++ b/src/ImageSharp/Formats/Png/PngHeader.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats /// /// Represents the png header chunk. /// - public sealed class PngHeader + internal sealed class PngHeader { /// /// Gets or sets the dimension in x-direction of the image in pixels. diff --git a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs new file mode 100644 index 0000000000..fdea3eb8ae --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -0,0 +1,43 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System; + + /// + /// Detects png file headers + /// + public sealed class PngImageFormatDetector : IImageFormatDetector + { + /// + public int HeaderSize => 8; + + /// + public IImageFormat DetectFormat(ReadOnlySpan header) + { + if (this.IsSupportedFileFormat(header)) + { + return ImageFormats.Png; + } + + return null; + } + + private bool IsSupportedFileFormat(ReadOnlySpan header) + { + // TODO: This should be in constants + return header.Length >= this.HeaderSize && + header[0] == 0x89 && + header[1] == 0x50 && // P + header[2] == 0x4E && // N + header[3] == 0x47 && // G + header[4] == 0x0D && // CR + header[5] == 0x0A && // LF + header[6] == 0x1A && // EOF + header[7] == 0x0A; // LF + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs index ec3b8ebe73..b43aff0b78 100644 --- a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs +++ b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Formats /// /// Provides enumeration of available PNG interlace modes. /// - public enum PngInterlaceMode : byte + internal enum PngInterlaceMode : byte { /// /// Non interlaced diff --git a/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs b/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs index 935cdf9532..cbd292dc4c 100644 --- a/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs +++ b/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Formats /// Value. The complete checksum object can also be reset /// so it can be used again with new data. /// - public interface IChecksum + internal interface IChecksum { /// /// Gets the data checksum computed so far. diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs index 0743d8ded3..136f919da7 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs @@ -9,7 +9,7 @@ /// /// Provides methods and properties for deframing streams from PNGs. /// - internal class ZlibInflateStream : Stream + internal sealed class ZlibInflateStream : Stream { /// /// The inner raw memory stream diff --git a/src/ImageSharp/IConfigurationModule.cs b/src/ImageSharp/IConfigurationModule.cs new file mode 100644 index 0000000000..95b92ed056 --- /dev/null +++ b/src/ImageSharp/IConfigurationModule.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + /// + /// Represents an interface that can register image encoders, decoders and image format detectors. + /// + public interface IConfigurationModule + { + /// + /// Called when loaded into a configuration object so the module can register items into the configuration. + /// + /// The configuration that will retain the encoders, decodes and mime type detectors. + void Configure(Configuration configuration); + } +} diff --git a/src/ImageSharp/Image/IImage.cs b/src/ImageSharp/Image/IImage.cs index 55abdb244f..b9e8e392a3 100644 --- a/src/ImageSharp/Image/IImage.cs +++ b/src/ImageSharp/Image/IImage.cs @@ -12,11 +12,6 @@ namespace ImageSharp /// internal interface IImage : IImageBase { - /// - /// Gets the currently loaded image format. - /// - IImageFormat CurrentImageFormat { get; } - /// /// Gets the meta data of the image. /// diff --git a/src/ImageSharp/Image/IImageBase.cs b/src/ImageSharp/Image/IImageBase.cs index 393d83077a..0e087aa4a3 100644 --- a/src/ImageSharp/Image/IImageBase.cs +++ b/src/ImageSharp/Image/IImageBase.cs @@ -5,6 +5,8 @@ namespace ImageSharp { + using SixLabors.Primitives; + /// /// Encapsulates the basic properties and methods required to manipulate images. /// diff --git a/src/ImageSharp/Image/IImageProcessor.cs b/src/ImageSharp/Image/IImageProcessor.cs index c4fa9afa29..8687766d5e 100644 --- a/src/ImageSharp/Image/IImageProcessor.cs +++ b/src/ImageSharp/Image/IImageProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing using System.Threading.Tasks; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Encapsulates methods to alter the pixels of an image. diff --git a/src/ImageSharp/Image/Image.Decode.cs b/src/ImageSharp/Image/Image.Decode.cs index c162f17726..1013107062 100644 --- a/src/ImageSharp/Image/Image.Decode.cs +++ b/src/ImageSharp/Image/Image.Decode.cs @@ -5,11 +5,10 @@ namespace ImageSharp { - using System.Buffers; using System.IO; using System.Linq; using Formats; - + using ImageSharp.Memory; using ImageSharp.PixelFormats; /// @@ -22,8 +21,8 @@ namespace ImageSharp /// /// The image stream to read the header from. /// The configuration. - /// The image format or null if none found. - private static IImageFormat DiscoverFormat(Stream stream, Configuration config) + /// The mime type or null if none found. + private static IImageFormat InternalDetectFormat(Stream stream, Configuration config) { // This is probably a candidate for making into a public API in the future! int maxHeaderSize = config.MaxHeaderSize; @@ -32,45 +31,55 @@ namespace ImageSharp return null; } - IImageFormat format; - byte[] header = ArrayPool.Shared.Rent(maxHeaderSize); - try + using (var buffer = new Buffer(maxHeaderSize)) { long startPosition = stream.Position; - stream.Read(header, 0, maxHeaderSize); + stream.Read(buffer.Array, 0, maxHeaderSize); stream.Position = startPosition; - format = config.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header)); + return config.FormatDetectors.Select(x => x.DetectFormat(buffer)).LastOrDefault(x => x != null); } - finally + } + + /// + /// By reading the header on the provided stream this calculates the images format. + /// + /// The image stream to read the header from. + /// The configuration. + /// The IImageFormat. + /// The image format or null if none found. + private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config, out IImageFormat format) + { + format = InternalDetectFormat(stream, config); + if (format != null) { - ArrayPool.Shared.Return(header); + return config.FindDecoder(format); } - return format; + return null; } +#pragma warning disable SA1008 // Opening parenthesis must be spaced correctly /// /// Decodes the image stream to the current image. /// /// The stream. - /// The options for the decoder. /// the configuration. /// The pixel format. /// /// A new . /// - private static Image Decode(Stream stream, IDecoderOptions options, Configuration config) + private static (Image img, IImageFormat format) Decode(Stream stream, Configuration config) +#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly where TPixel : struct, IPixel { - IImageFormat format = DiscoverFormat(stream, config); - if (format == null) + IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format); + if (decoder == null) { - return null; + return (null, null); } - Image img = format.Decoder.Decode(config, stream, options); - img.CurrentImageFormat = format; - return img; + Image img = decoder.Decode(config, stream); + return (img, format); } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/Image.FromBytes.cs b/src/ImageSharp/Image/Image.FromBytes.cs index c7309c4b14..c7023b860b 100644 --- a/src/ImageSharp/Image/Image.FromBytes.cs +++ b/src/ImageSharp/Image/Image.FromBytes.cs @@ -15,54 +15,78 @@ namespace ImageSharp /// public static partial class Image { + /// + /// By reading the header on the provided byte array this calculates the images format. + /// + /// The byte array containing image data to read the header from. + /// The format or null if none found. + public static IImageFormat DetectFormat(byte[] data) + { + return DetectFormat(null, data); + } + + /// + /// By reading the header on the provided byte array this calculates the images format. + /// + /// The configuration. + /// The byte array containing image data to read the header from. + /// The mime type or null if none found. + public static IImageFormat DetectFormat(Configuration config, byte[] data) + { + using (Stream stream = new MemoryStream(data)) + { + return DetectFormat(config, stream); + } + } + /// /// Create a new instance of the class from the given byte array. /// /// The byte array containing image data. /// A new . - public static Image Load(byte[] data) => Load(null, data, null); + public static Image Load(byte[] data) => Load(null, data); /// /// Create a new instance of the class from the given byte array. /// /// The byte array containing image data. - /// The options for the decoder. + /// The mime type of the decoded image. /// A new . - public static Image Load(byte[] data, IDecoderOptions options) => Load(null, data, options); + public static Image Load(byte[] data, out IImageFormat format) => Load(null, data, out format); /// - /// Create a new instance of the class from the given byte array. + /// Create a new instance of the class from the given byte array. /// /// The config for the decoder. /// The byte array containing image data. /// A new . - public static Image Load(Configuration config, byte[] data) => Load(config, data, null); + public static Image Load(Configuration config, byte[] data) => Load(config, data); /// /// Create a new instance of the class from the given byte array. /// + /// The config for the decoder. /// The byte array containing image data. - /// The decoder. + /// The mime type of the decoded image. /// A new . - public static Image Load(byte[] data, IImageDecoder decoder) => Load(data, decoder, null); + public static Image Load(Configuration config, byte[] data, out IImageFormat format) => Load(config, data, out format); /// - /// Create a new instance of the class from the given byte array. + /// Create a new instance of the class from the given byte array. /// - /// The configuration options. /// The byte array containing image data. - /// The options for the decoder. + /// The decoder. /// A new . - public static Image Load(Configuration config, byte[] data, IDecoderOptions options) => Load(config, data, options); + public static Image Load(byte[] data, IImageDecoder decoder) => Load(data, decoder); /// - /// Create a new instance of the class from the given byte array. + /// Create a new instance of the class from the given byte array. /// + /// The config for the decoder. /// The byte array containing image data. /// The decoder. - /// The options for the decoder. /// A new . - public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options) => Load(data, decoder, options); + public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) => Load(config, data, decoder); /// /// Create a new instance of the class from the given byte array. @@ -73,79 +97,85 @@ namespace ImageSharp public static Image Load(byte[] data) where TPixel : struct, IPixel { - return Load(null, data, null); + return Load(null, data); } /// /// Create a new instance of the class from the given byte array. /// /// The byte array containing image data. - /// The options for the decoder. + /// The mime type of the decoded image. /// The pixel format. /// A new . - public static Image Load(byte[] data, IDecoderOptions options) + public static Image Load(byte[] data, out IImageFormat format) where TPixel : struct, IPixel { - return Load(null, data, options); + return Load(null, data, out format); } /// /// Create a new instance of the class from the given byte array. /// - /// The config for the decoder. + /// The configuration options. /// The byte array containing image data. /// The pixel format. /// A new . public static Image Load(Configuration config, byte[] data) where TPixel : struct, IPixel { - return Load(config, data, null); + using (var memoryStream = new MemoryStream(data)) + { + return Load(config, memoryStream); + } } /// /// Create a new instance of the class from the given byte array. /// + /// The configuration options. /// The byte array containing image data. - /// The decoder. + /// The mime type of the decoded image. /// The pixel format. /// A new . - public static Image Load(byte[] data, IImageDecoder decoder) + public static Image Load(Configuration config, byte[] data, out IImageFormat format) where TPixel : struct, IPixel { - return Load(data, decoder, null); + using (var memoryStream = new MemoryStream(data)) + { + return Load(config, memoryStream, out format); + } } /// /// Create a new instance of the class from the given byte array. /// - /// The configuration options. /// The byte array containing image data. - /// The options for the decoder. + /// The decoder. /// The pixel format. /// A new . - public static Image Load(Configuration config, byte[] data, IDecoderOptions options) + public static Image Load(byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { - using (MemoryStream ms = new MemoryStream(data)) + using (var memoryStream = new MemoryStream(data)) { - return Load(config, ms, options); + return Load(memoryStream, decoder); } } /// /// Create a new instance of the class from the given byte array. /// + /// The Configuration. /// The byte array containing image data. /// The decoder. - /// The options for the decoder. /// The pixel format. /// A new . - public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options) + public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { - using (MemoryStream ms = new MemoryStream(data)) + using (var memoryStream = new MemoryStream(data)) { - return Load(ms, decoder, options); + return Load(config, memoryStream, decoder); } } } diff --git a/src/ImageSharp/Image/Image.FromFile.cs b/src/ImageSharp/Image/Image.FromFile.cs index a135c43f5e..ca395ce088 100644 --- a/src/ImageSharp/Image/Image.FromFile.cs +++ b/src/ImageSharp/Image/Image.FromFile.cs @@ -16,6 +16,31 @@ namespace ImageSharp /// public static partial class Image { + /// + /// By reading the header on the provided file this calculates the images mime type. + /// + /// The image file to open and to read the header from. + /// The mime type or null if none found. + public static IImageFormat DetectFormat(string filePath) + { + return DetectFormat(null, filePath); + } + + /// + /// By reading the header on the provided file this calculates the images mime type. + /// + /// The configuration. + /// The image file to open and to read the header from. + /// The mime type or null if none found. + public static IImageFormat DetectFormat(Configuration config, string filePath) + { + config = config ?? Configuration.Default; + using (Stream file = config.FileSystem.OpenRead(filePath)) + { + return DetectFormat(config, file); + } + } + /// /// Create a new instance of the class from the given file. /// @@ -30,12 +55,12 @@ namespace ImageSharp /// Create a new instance of the class from the given file. /// /// The file path to the image. - /// The options for the decoder. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// - /// A new . - public static Image Load(string path, IDecoderOptions options) => Load(path, options); + /// A new . + public static Image Load(string path, out IImageFormat format) => Load(path, out format); /// /// Create a new instance of the class from the given file. @@ -51,37 +76,37 @@ namespace ImageSharp /// /// Create a new instance of the class from the given file. /// + /// The config for the decoder. /// The file path to the image. - /// The decoder. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(string path, IImageDecoder decoder) => Load(path, decoder); + public static Image Load(Configuration config, string path, out IImageFormat format) => Load(config, path, out format); /// /// Create a new instance of the class from the given file. /// - /// The configuration options. + /// The Configuration. /// The file path to the image. - /// The options for the decoder. + /// The decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(Configuration config, string path, IDecoderOptions options) => Load(config, path, options); + public static Image Load(Configuration config, string path, IImageDecoder decoder) => Load(config, path, decoder); /// /// Create a new instance of the class from the given file. /// /// The file path to the image. /// The decoder. - /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options) => Load(path, decoder, options); + public static Image Load(string path, IImageDecoder decoder) => Load(path, decoder); /// /// Create a new instance of the class from the given file. @@ -95,29 +120,29 @@ namespace ImageSharp public static Image Load(string path) where TPixel : struct, IPixel { - return Load(null, path, null); + return Load(null, path); } /// /// Create a new instance of the class from the given file. /// /// The file path to the image. - /// The options for the decoder. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(string path, IDecoderOptions options) + public static Image Load(string path, out IImageFormat format) where TPixel : struct, IPixel { - return Load(null, path, options); + return Load(null, path, out format); } /// /// Create a new instance of the class from the given file. /// - /// The config for the decoder. + /// The configuration options. /// The file path to the image. /// /// Thrown if the stream is not readable nor seekable. @@ -127,64 +152,68 @@ namespace ImageSharp public static Image Load(Configuration config, string path) where TPixel : struct, IPixel { - return Load(config, path, null); + config = config ?? Configuration.Default; + using (Stream stream = config.FileSystem.OpenRead(path)) + { + return Load(config, stream); + } } /// /// Create a new instance of the class from the given file. /// + /// The configuration options. /// The file path to the image. - /// The decoder. + /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(string path, IImageDecoder decoder) + public static Image Load(Configuration config, string path, out IImageFormat format) where TPixel : struct, IPixel { - return Load(path, decoder, null); + config = config ?? Configuration.Default; + using (Stream stream = config.FileSystem.OpenRead(path)) + { + return Load(config, stream, out format); + } } /// /// Create a new instance of the class from the given file. /// - /// The configuration options. /// The file path to the image. - /// The options for the decoder. + /// The decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(Configuration config, string path, IDecoderOptions options) + public static Image Load(string path, IImageDecoder decoder) where TPixel : struct, IPixel { - config = config ?? Configuration.Default; - using (Stream s = config.FileSystem.OpenRead(path)) - { - return Load(config, s, options); - } + return Load(null, path, decoder); } /// /// Create a new instance of the class from the given file. /// + /// The Configuration. /// The file path to the image. /// The decoder. - /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options) + public static Image Load(Configuration config, string path, IImageDecoder decoder) where TPixel : struct, IPixel { - Configuration config = Configuration.Default; - using (Stream s = config.FileSystem.OpenRead(path)) + config = config ?? Configuration.Default; + using (Stream stream = config.FileSystem.OpenRead(path)) { - return Load(s, decoder, options); + return Load(config, stream, decoder); } } } diff --git a/src/ImageSharp/Image/Image.FromStream.cs b/src/ImageSharp/Image/Image.FromStream.cs index 1bcb5adc9a..29d93ae859 100644 --- a/src/ImageSharp/Image/Image.FromStream.cs +++ b/src/ImageSharp/Image/Image.FromStream.cs @@ -6,6 +6,7 @@ namespace ImageSharp { using System; + using System.Collections.Generic; using System.IO; using System.Text; using Formats; @@ -17,26 +18,47 @@ namespace ImageSharp /// public static partial class Image { + /// + /// By reading the header on the provided stream this calculates the images mime type. + /// + /// The image stream to read the header from. + /// The mime type or null if none found. + public static IImageFormat DetectFormat(Stream stream) + { + return DetectFormat(null, stream); + } + + /// + /// By reading the header on the provided stream this calculates the images mime type. + /// + /// The configuration. + /// The image stream to read the header from. + /// The mime type or null if none found. + public static IImageFormat DetectFormat(Configuration config, Stream stream) + { + return WithSeekableStream(stream, s => InternalDetectFormat(s, config ?? Configuration.Default)); + } + /// /// Create a new instance of the class from the given stream. /// /// The stream containing image information. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// A new .> - public static Image Load(Stream stream) => Load(stream); + public static Image Load(Stream stream, out IImageFormat format) => Load(stream, out format); /// /// Create a new instance of the class from the given stream. /// /// The stream containing image information. - /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// A new .> - public static Image Load(Stream stream, IDecoderOptions options) => Load(stream, options); + public static Image Load(Stream stream) => Load(stream); /// /// Create a new instance of the class from the given stream. @@ -63,14 +85,14 @@ namespace ImageSharp /// /// Create a new instance of the class from the given stream. /// + /// The config for the decoder. /// The stream containing image information. - /// The decoder. - /// The options for the decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// - /// A new .> - public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) => Load(stream, decoder, options); + /// A new .> + public static Image Load(Configuration config, Stream stream, out IImageFormat format) => Load(config, stream, out format); /// /// Create a new instance of the class from the given stream. @@ -84,44 +106,45 @@ namespace ImageSharp public static Image Load(Stream stream) where TPixel : struct, IPixel { - return Load(null, stream, null); + return Load(null, stream); } /// /// Create a new instance of the class from the given stream. /// /// The stream containing image information. - /// The options for the decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Stream stream, IDecoderOptions options) + public static Image Load(Stream stream, out IImageFormat format) where TPixel : struct, IPixel { - return Load(null, stream, options); + return Load(null, stream, out format); } /// /// Create a new instance of the class from the given stream. /// - /// The config for the decoder. /// The stream containing image information. + /// The decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Configuration config, Stream stream) + public static Image Load(Stream stream, IImageDecoder decoder) where TPixel : struct, IPixel { - return Load(config, stream, null); + return WithSeekableStream(stream, s => decoder.Decode(Configuration.Default, s)); } /// /// Create a new instance of the class from the given stream. /// + /// The Configuration. /// The stream containing image information. /// The decoder. /// @@ -129,27 +152,26 @@ namespace ImageSharp /// /// The pixel format. /// A new .> - public static Image Load(Stream stream, IImageDecoder decoder) + public static Image Load(Configuration config, Stream stream, IImageDecoder decoder) where TPixel : struct, IPixel { - return Load(stream, decoder, null); + return WithSeekableStream(stream, s => decoder.Decode(config, s)); } /// /// Create a new instance of the class from the given stream. /// + /// The configuration options. /// The stream containing image information. - /// The decoder. - /// The options for the decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) + public static Image Load(Configuration config, Stream stream) where TPixel : struct, IPixel { - return WithSeekableStream(stream, s => decoder.Decode(Configuration.Default, s, options)); + return Load(config, stream, out var _); } /// @@ -157,29 +179,31 @@ namespace ImageSharp /// /// The configuration options. /// The stream containing image information. - /// The options for the decoder. + /// the mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new .> - public static Image Load(Configuration config, Stream stream, IDecoderOptions options) - where TPixel : struct, IPixel + public static Image Load(Configuration config, Stream stream, out IImageFormat format) + where TPixel : struct, IPixel { config = config ?? Configuration.Default; - Image img = WithSeekableStream(stream, s => Decode(s, options, config)); + (Image img, IImageFormat format) data = WithSeekableStream(stream, s => Decode(s, config)); + + format = data.format; - if (img != null) + if (data.img != null) { - return img; + return data.img; } - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.AppendLine("Image cannot be loaded. Available formats:"); + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("Image cannot be loaded. Available decoders:"); - foreach (IImageFormat format in config.ImageFormats) + foreach (KeyValuePair val in config.ImageDecoders) { - stringBuilder.AppendLine("-" + format); + stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); } throw new NotSupportedException(stringBuilder.ToString()); @@ -198,12 +222,12 @@ namespace ImageSharp } // We want to be able to load images from things like HttpContext.Request.Body - using (MemoryStream ms = new MemoryStream()) + using (var memoryStream = new MemoryStream()) { - stream.CopyTo(ms); - ms.Position = 0; + stream.CopyTo(memoryStream); + memoryStream.Position = 0; - return action(ms); + return action(memoryStream); } } } diff --git a/src/ImageSharp/Image/ImageBase{TPixel}.cs b/src/ImageSharp/Image/ImageBase{TPixel}.cs index 647d60075d..20b891f2dd 100644 --- a/src/ImageSharp/Image/ImageBase{TPixel}.cs +++ b/src/ImageSharp/Image/ImageBase{TPixel}.cs @@ -12,6 +12,7 @@ namespace ImageSharp using ImageSharp.Memory; using ImageSharp.PixelFormats; using ImageSharp.Processing; + using SixLabors.Primitives; /// /// The base class of all images. Encapsulates the basic properties and methods required to manipulate diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 059ccb9a07..5e8bcab31b 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -9,13 +9,14 @@ namespace ImageSharp using System.Collections.Generic; using System.Diagnostics; using System.IO; - using System.Linq; using System.Numerics; + using System.Text; using System.Threading.Tasks; using Formats; using ImageSharp.PixelFormats; using ImageSharp.Processing; + using SixLabors.Primitives; /// /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes. @@ -94,13 +95,7 @@ namespace ImageSharp internal Image(Configuration configuration, int width, int height, ImageMetaData metadata) : base(configuration, width, height) { - if (!this.Configuration.ImageFormats.Any()) - { - throw new InvalidOperationException("No image formats have been configured."); - } - this.MetaData = metadata ?? new ImageMetaData(); - this.CurrentImageFormat = this.Configuration.ImageFormats.First(); } /// @@ -138,11 +133,6 @@ namespace ImageSharp /// The list of frame images. public IList> Frames { get; } = new List>(); - /// - /// Gets the currently loaded image format. - /// - public IImageFormat CurrentImageFormat { get; internal set; } - /// /// Applies the processor to the image. /// @@ -162,48 +152,28 @@ namespace ImageSharp /// Saves the image to the given stream using the currently loaded image format. /// /// The stream to save the image to. + /// The format to save the image to. /// Thrown if the stream is null. /// The - public Image Save(Stream stream) + public Image Save(Stream stream, IImageFormat format) { - return this.Save(stream, (IEncoderOptions)null); - } + Guard.NotNull(format, nameof(format)); + IImageEncoder encoder = this.Configuration.FindEncoder(format); - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The stream to save the image to. - /// The options for the encoder. - /// Thrown if the stream is null. - /// The - public Image Save(Stream stream, IEncoderOptions options) - { - return this.Save(stream, this.CurrentImageFormat?.Encoder, options); - } + if (encoder == null) + { + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:"); - /// - /// Saves the image to the given stream using the given image format. - /// - /// The stream to save the image to. - /// The format to save the image as. - /// The - public Image Save(Stream stream, IImageFormat format) - { - return this.Save(stream, format, null); - } + foreach (KeyValuePair val in this.Configuration.ImageEncoders) + { + stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); + } - /// - /// Saves the image to the given stream using the given image format. - /// - /// The stream to save the image to. - /// The format to save the image as. - /// The options for the encoder. - /// The - public Image Save(Stream stream, IImageFormat format, IEncoderOptions options) - { - Guard.NotNull(format, nameof(format)); + throw new NotSupportedException(stringBuilder.ToString()); + } - return this.Save(stream, format.Encoder, options); + return this.Save(stream, encoder); } /// @@ -216,26 +186,11 @@ namespace ImageSharp /// The . /// public Image Save(Stream stream, IImageEncoder encoder) - { - return this.Save(stream, encoder, null); - } - - /// - /// Saves the image to the given stream using the given image encoder. - /// - /// The stream to save the image to. - /// The encoder to save the image with. - /// The options for the encoder. - /// Thrown if the stream or encoder is null. - /// - /// The . - /// - public Image Save(Stream stream, IImageEncoder encoder, IEncoderOptions options) { Guard.NotNull(stream, nameof(stream)); Guard.NotNull(encoder, nameof(encoder)); - encoder.Encode(this, stream, options); + encoder.Encode(this, stream); return this; } @@ -249,64 +204,37 @@ namespace ImageSharp /// The public Image Save(string filePath) { - return this.Save(filePath, (IEncoderOptions)null); - } + Guard.NotNullOrEmpty(filePath, nameof(filePath)); - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The file path to save the image to. - /// The options for the encoder. - /// Thrown if the stream is null. - /// The - public Image Save(string filePath, IEncoderOptions options) - { string ext = Path.GetExtension(filePath).Trim('.'); - IImageFormat format = this.Configuration.ImageFormats.SingleOrDefault(f => f.SupportedExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase)); + var format = this.Configuration.FindFormatByFileExtensions(ext); if (format == null) { - throw new InvalidOperationException($"No image formats have been registered for the file extension '{ext}'."); + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); + foreach (IImageFormat fmt in this.Configuration.ImageFormats) + { + stringBuilder.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); + } + + throw new NotSupportedException(stringBuilder.ToString()); } - return this.Save(filePath, format, options); - } + IImageEncoder encoder = this.Configuration.FindEncoder(format); - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The file path to save the image to. - /// The format to save the image as. - /// Thrown if the format is null. - /// The - public Image Save(string filePath, IImageFormat format) - { - return this.Save(filePath, format, null); - } + if (encoder == null) + { + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); + foreach (KeyValuePair enc in this.Configuration.ImageEncoders) + { + stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); + } - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The file path to save the image to. - /// The format to save the image as. - /// The options for the encoder. - /// Thrown if the format is null. - /// The - public Image Save(string filePath, IImageFormat format, IEncoderOptions options) - { - Guard.NotNull(format, nameof(format)); - return this.Save(filePath, format.Encoder, options); - } + throw new NotSupportedException(stringBuilder.ToString()); + } - /// - /// Saves the image to the given stream using the currently loaded image format. - /// - /// The file path to save the image to. - /// The encoder to save the image with. - /// Thrown if the encoder is null. - /// The - public Image Save(string filePath, IImageEncoder encoder) - { - return this.Save(filePath, encoder, null); + return this.Save(filePath, encoder); } /// @@ -314,15 +242,14 @@ namespace ImageSharp /// /// The file path to save the image to. /// The encoder to save the image with. - /// The options for the encoder. /// Thrown if the encoder is null. /// The - public Image Save(string filePath, IImageEncoder encoder, IEncoderOptions options) + public Image Save(string filePath, IImageEncoder encoder) { Guard.NotNull(encoder, nameof(encoder)); using (Stream fs = this.Configuration.FileSystem.Create(filePath)) { - return this.Save(fs, encoder, options); + return this.Save(fs, encoder); } } #endif @@ -330,21 +257,22 @@ namespace ImageSharp /// public override string ToString() { - return $"Image: {this.Width}x{this.Height}"; + return $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; } /// /// Returns a Base64 encoded string from the given image. /// /// + /// The format. /// The - public string ToBase64String() + public string ToBase64String(IImageFormat format) { - using (MemoryStream stream = new MemoryStream()) + using (var stream = new MemoryStream()) { - this.Save(stream); + this.Save(stream, format); stream.Flush(); - return $"data:{this.CurrentImageFormat.MimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; + return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; } } @@ -359,7 +287,7 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - Image target = new Image(this.Configuration, this.Width, this.Height); + var target = new Image(this.Configuration, this.Width, this.Height); target.CopyProperties(this); using (PixelAccessor pixels = this.Lock()) @@ -373,7 +301,7 @@ namespace ImageSharp { for (int x = 0; x < target.Width; x++) { - TPixel2 color = default(TPixel2); + var color = default(TPixel2); color.PackFromVector4(scaleFunc(pixels[x, y].ToVector4())); targetPixels[x, y] = color; } @@ -417,7 +345,6 @@ namespace ImageSharp /// private void CopyProperties(IImage other) { - this.CurrentImageFormat = other.CurrentImageFormat; this.MetaData = new ImageMetaData(other.MetaData); } } diff --git a/src/ImageSharp/ImageFormats.cs b/src/ImageSharp/ImageFormats.cs new file mode 100644 index 0000000000..f79191eae6 --- /dev/null +++ b/src/ImageSharp/ImageFormats.cs @@ -0,0 +1,35 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using ImageSharp.Formats; + + /// + /// The static collection of all the default image formats + /// + public static class ImageFormats + { + /// + /// The format details for the jpegs. + /// + public static readonly IImageFormat Jpeg = new JpegFormat(); + + /// + /// The format details for the pngs. + /// + public static readonly IImageFormat Png = new PngFormat(); + + /// + /// The format details for the gifs. + /// + public static readonly IImageFormat Gif = new GifFormat(); + + /// + /// The format details for the bitmaps. + /// + public static readonly IImageFormat Bitmap = new BmpFormat(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 17f7bf58f3..8733131a74 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -34,6 +34,7 @@ + All @@ -43,6 +44,7 @@ + ..\..\ImageSharp.ruleset @@ -63,6 +65,14 @@ TextTemplatingFileGenerator Rgba32.PixelOperations.Generated.cs + + PorterDuffFunctions.Generated.cs + TextTemplatingFileGenerator + + + DefaultPixelBlenders.Generated.cs + TextTemplatingFileGenerator + @@ -83,5 +93,15 @@ True Rgba32.PixelOperations.Generated.tt + + True + True + DefaultPixelBlenders.Generated.tt + + + True + True + PorterDuffFunctions.Generated.tt + \ No newline at end of file diff --git a/src/ImageSharp/Memory/Buffer.cs b/src/ImageSharp/Memory/Buffer.cs index a894ea53a4..4b3681c744 100644 --- a/src/ImageSharp/Memory/Buffer.cs +++ b/src/ImageSharp/Memory/Buffer.cs @@ -115,6 +115,16 @@ namespace ImageSharp.Memory } } + /// + /// Converts to an . + /// + /// The to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(Buffer buffer) + { + return new ReadOnlySpan(buffer.Array, 0, buffer.Length); + } + /// /// Converts to an . /// diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 91ea9ac4bf..5361b486d4 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -50,7 +50,6 @@ namespace ImageSharp this.HorizontalResolution = other.HorizontalResolution; this.VerticalResolution = other.VerticalResolution; - this.Quality = other.Quality; this.FrameDelay = other.FrameDelay; this.DisposalMethod = other.DisposalMethod; this.RepeatCount = other.RepeatCount; @@ -127,11 +126,6 @@ namespace ImageSharp /// A list of image properties. public IList Properties { get; } = new List(); - /// - /// Gets or sets the quality of the image. This affects the output quality of lossy image formats. - /// - public int Quality { get; set; } - /// /// Gets or sets the number of times any animation is repeated. /// 0 means to repeat indefinitely. diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs index 1c130b54d0..711de818b3 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs @@ -464,17 +464,31 @@ namespace ImageSharp int start = this.currentIndex - 8; // 8 is the tag header size uint recordCount = this.ReadUInt32(); - // TODO: Why are we storing variable - uint recordSize = this.ReadUInt32(); + this.ReadUInt32(); // Record size (always 12) IccLocalizedString[] text = new IccLocalizedString[recordCount]; - string[] culture = new string[recordCount]; + CultureInfo[] culture = new CultureInfo[recordCount]; uint[] length = new uint[recordCount]; uint[] offset = new uint[recordCount]; for (int i = 0; i < recordCount; i++) { - culture[i] = $"{this.ReadAsciiString(2)}-{this.ReadAsciiString(2)}"; + string languageCode = this.ReadAsciiString(2); + string countryCode = this.ReadAsciiString(2); + + if (string.IsNullOrWhiteSpace(languageCode)) + { + culture[i] = CultureInfo.InvariantCulture; + } + else if (string.IsNullOrWhiteSpace(countryCode)) + { + culture[i] = new CultureInfo(languageCode); + } + else + { + culture[i] = new CultureInfo($"{languageCode}-{countryCode}"); + } + length[i] = this.ReadUInt32(); offset[i] = this.ReadUInt32(); } @@ -482,7 +496,7 @@ namespace ImageSharp for (int i = 0; i < recordCount; i++) { this.currentIndex = (int)(start + offset[i]); - text[i] = new IccLocalizedString(new CultureInfo(culture[i]), this.ReadUnicodeString((int)length[i])); + text[i] = new IccLocalizedString(culture[i], this.ReadUnicodeString((int)length[i])); } return new IccMultiLocalizedUnicodeTagDataEntry(text); diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs index 8e8065cee8..b74f22054e 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs @@ -5,6 +5,8 @@ namespace ImageSharp { + using System.Linq; + /// /// Provides methods to write ICC data types /// @@ -560,27 +562,45 @@ namespace ImageSharp long tpos = this.dataStream.Position; this.dataStream.Position += cultureCount * 12; - uint[] offset = new uint[cultureCount]; - int[] lengths = new int[cultureCount]; + IGrouping[] texts = value.Texts.GroupBy(t => t.Text).ToArray(); + + uint[] offset = new uint[texts.Length]; + int[] lengths = new int[texts.Length]; - for (int i = 0; i < cultureCount; i++) + for (int i = 0; i < texts.Length; i++) { offset[i] = (uint)(this.dataStream.Position - start); - count += lengths[i] = this.WriteUnicodeString(value.Texts[i].Text); + count += lengths[i] = this.WriteUnicodeString(texts[i].Key); } // Write position table long lpos = this.dataStream.Position; this.dataStream.Position = tpos; - for (int i = 0; i < cultureCount; i++) + for (int i = 0; i < texts.Length; i++) { - string[] code = value.Texts[i].Culture.Name.Split('-'); - - count += this.WriteAsciiString(code[0].ToLower(), 2, false); - count += this.WriteAsciiString(code[1].ToUpper(), 2, false); - - count += this.WriteUInt32((uint)lengths[i]); - count += this.WriteUInt32(offset[i]); + foreach (IccLocalizedString localizedString in texts[i]) + { + string cultureName = localizedString.Culture.Name; + if (string.IsNullOrEmpty(cultureName)) + { + count += this.WriteAsciiString("xx", 2, false); + count += this.WriteAsciiString("\0\0", 2, false); + } + else if (cultureName.Contains("-")) + { + string[] code = cultureName.Split('-'); + count += this.WriteAsciiString(code[0].ToLower(), 2, false); + count += this.WriteAsciiString(code[1].ToUpper(), 2, false); + } + else + { + count += this.WriteAsciiString(cultureName, 2, false); + count += this.WriteAsciiString("\0\0", 2, false); + } + + count += this.WriteUInt32((uint)lengths[i]); + count += this.WriteUInt32(offset[i]); + } } this.dataStream.Position = lpos; diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs index d7f556a814..b24c96f023 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs @@ -5,6 +5,8 @@ namespace ImageSharp { + using System.Collections.Generic; + /// /// Reads and parses ICC data from a byte array /// @@ -85,9 +87,21 @@ namespace ImageSharp { IccTagTableEntry[] tagTable = this.ReadTagTable(reader); IccTagDataEntry[] entries = new IccTagDataEntry[tagTable.Length]; + var store = new Dictionary(); for (int i = 0; i < tagTable.Length; i++) { - IccTagDataEntry entry = reader.ReadTagDataEntry(tagTable[i]); + IccTagDataEntry entry; + uint offset = tagTable[i].Offset; + if (store.ContainsKey(offset)) + { + entry = store[offset]; + } + else + { + entry = reader.ReadTagDataEntry(tagTable[i]); + store.Add(offset, entry); + } + entry.TagSignature = tagTable[i].Signature; entries[i] = entry; } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs index b4e5f28689..19c00e8f55 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs @@ -5,6 +5,7 @@ namespace ImageSharp { + using System; using System.Collections.Generic; using System.Linq; @@ -76,30 +77,18 @@ namespace ImageSharp private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List entries) { - var inData = new List(entries); - var dupData = new List(); - - while (inData.Count > 0) - { - IccTagDataEntry[] items = inData.Where(t => inData[0].Equals(t)).ToArray(); - dupData.Add(items); - foreach (IccTagDataEntry item in items) - { - inData.Remove(item); - } - } - - var table = new List(); + IEnumerable> grouped = entries.GroupBy(t => t); // (Header size) + (entry count) + (nr of entries) * (size of table entry) writer.SetIndex(128 + 4 + (entries.Count * 12)); - foreach (IccTagDataEntry[] entry in dupData) + var table = new List(); + foreach (IGrouping group in grouped) { - writer.WriteTagDataEntry(entry[0], out IccTagTableEntry tentry); - foreach (IccTagDataEntry item in entry) + writer.WriteTagDataEntry(group.Key, out IccTagTableEntry tableEntry); + foreach (IccTagDataEntry item in group) { - table.Add(new IccTagTableEntry(item.TagSignature, tentry.Offset, tentry.DataSize)); + table.Add(new IccTagTableEntry(item.TagSignature, tableEntry.Offset, tableEntry.DataSize)); } } diff --git a/src/ImageSharp/Numerics/Ellipse.cs b/src/ImageSharp/Numerics/Ellipse.cs deleted file mode 100644 index 9aba745e46..0000000000 --- a/src/ImageSharp/Numerics/Ellipse.cs +++ /dev/null @@ -1,183 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.ComponentModel; - using System.Numerics; - - /// - /// Represents an ellipse. - /// - public struct Ellipse : IEquatable - { - /// - /// Represents a that has X and Y values set to zero. - /// - public static readonly Ellipse Empty = default(Ellipse); - - /// - /// The center point. - /// - private Point center; - - /// - /// Initializes a new instance of the struct. - /// - /// The center point. - /// The x-radius. - /// The y-radius. - public Ellipse(Point center, float radiusX, float radiusY) - { - this.center = center; - this.RadiusX = radiusX; - this.RadiusY = radiusY; - } - - /// - /// Gets the x-radius of this . - /// - public float RadiusX { get; } - - /// - /// Gets the y-radius of this . - /// - public float RadiusY { get; } - - /// - /// Gets a value indicating whether this is empty. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public bool IsEmpty => this.Equals(Empty); - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - public static bool operator ==(Ellipse left, Ellipse right) - { - return left.Equals(right); - } - - /// - /// Compares two objects for inequality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - public static bool operator !=(Ellipse left, Ellipse right) - { - return !left.Equals(right); - } - - /// - /// Returns the center point of the given - /// - /// The ellipse - /// - public static Vector2 Center(Ellipse ellipse) - { - return new Vector2(ellipse.center.X, ellipse.center.Y); - } - - /// - /// Determines if the specfied point is contained within the rectangular region defined by - /// this . - /// - /// The x-coordinate of the given point. - /// The y-coordinate of the given point. - /// The - public bool Contains(int x, int y) - { - if (this.RadiusX <= 0 || this.RadiusY <= 0) - { - return false; - } - - // TODO: SIMD? - // This is a more general form of the circle equation - // X^2/a^2 + Y^2/b^2 <= 1 - Point normalized = new Point(x - this.center.X, y - this.center.Y); - int nX = normalized.X; - int nY = normalized.Y; - - return ((double)(nX * nX) / (this.RadiusX * this.RadiusX)) - + ((double)(nY * nY) / (this.RadiusY * this.RadiusY)) - <= 1.0; - } - - /// - public override int GetHashCode() - { - return this.GetHashCode(this); - } - - /// - public override string ToString() - { - if (this.IsEmpty) - { - return "Ellipse [ Empty ]"; - } - - return - $"Ellipse [ RadiusX={this.RadiusX}, RadiusY={this.RadiusX}, Centre={this.center.X},{this.center.Y} ]"; - } - - /// - public override bool Equals(object obj) - { - if (obj is Ellipse) - { - return this.Equals((Ellipse)obj); - } - - return false; - } - - /// - public bool Equals(Ellipse other) - { - return this.center.Equals(other.center) - && this.RadiusX.Equals(other.RadiusX) - && this.RadiusY.Equals(other.RadiusY); - } - - /// - /// Returns the hash code for this instance. - /// - /// - /// The instance of to return the hash code for. - /// - /// - /// A 32-bit signed integer that is the hash code for this instance. - /// - private int GetHashCode(Ellipse ellipse) - { - unchecked - { - int hashCode = ellipse.center.GetHashCode(); - hashCode = (hashCode * 397) ^ ellipse.RadiusX.GetHashCode(); - hashCode = (hashCode * 397) ^ ellipse.RadiusY.GetHashCode(); - return hashCode; - } - } - } -} diff --git a/src/ImageSharp/Numerics/Matrix3x2Extensions.cs b/src/ImageSharp/Numerics/Matrix3x2Extensions.cs deleted file mode 100644 index f424624020..0000000000 --- a/src/ImageSharp/Numerics/Matrix3x2Extensions.cs +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System.Numerics; - using System.Runtime.CompilerServices; - - /// - /// Extension methods for the struct - /// - public static class Matrix3x2Extensions - { - /// - /// Creates a rotation matrix for the given rotation in degrees and a center point. - /// - /// The angle in degrees - /// The center point - /// The rotation - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Matrix3x2 CreateRotation(float degree, Point centerPoint) - { - float radian = MathF.DegreeToRadian(degree); - return Matrix3x2.CreateRotation(radian, new Vector2(centerPoint.X, centerPoint.Y)); - } - - /// - /// Creates a rotation matrix for the given rotation in degrees and a center point. - /// - /// The angle in degrees - /// The center point - /// The rotation - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Matrix3x2 CreateRotation(float degree, PointF centerPoint) - { - float radian = MathF.DegreeToRadian(degree); - return Matrix3x2.CreateRotation(radian, centerPoint); - } - - /// - /// Creates a skew matrix for the given angle in degrees and a center point. - /// - /// The x-angle in degrees - /// The y-angle in degrees - /// The center point - /// The rotation - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Matrix3x2 CreateSkew(float degreesX, float degreesY, Point centerPoint) - { - float radiansX = MathF.DegreeToRadian(degreesX); - float radiansY = MathF.DegreeToRadian(degreesY); - return Matrix3x2.CreateSkew(radiansX, radiansY, new Vector2(centerPoint.X, centerPoint.Y)); - } - - /// - /// Creates a skew matrix for the given angle in degrees and a center point. - /// - /// The x-angle in degrees - /// The y-angle in degrees - /// The rotation - /// The center point - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Matrix3x2 CreateSkew(float degreesX, float degreesY, PointF centerPoint) - { - float radiansX = MathF.DegreeToRadian(degreesX); - float radiansY = MathF.DegreeToRadian(degreesY); - return Matrix3x2.CreateSkew(radiansX, radiansY, new Vector2(centerPoint.X, centerPoint.Y)); - } - } -} diff --git a/src/ImageSharp/Numerics/Point.cs b/src/ImageSharp/Numerics/Point.cs deleted file mode 100644 index 9bff27d2ac..0000000000 --- a/src/ImageSharp/Numerics/Point.cs +++ /dev/null @@ -1,257 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.ComponentModel; - using System.Numerics; - using System.Runtime.CompilerServices; - - /// - /// Represents an ordered pair of integer x- and y-coordinates that defines a point in - /// a two-dimensional plane. - /// - /// - /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, - /// as it avoids the need to create new values for modification operations. - /// - public struct Point : IEquatable - { - /// - /// Represents a that has X and Y values set to zero. - /// - public static readonly Point Empty = default(Point); - - /// - /// Initializes a new instance of the struct. - /// - /// The horizontal and vertical position of the point. - public Point(int value) - : this() - { - this.X = LowInt16(value); - this.Y = HighInt16(value); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The horizontal position of the point. - /// The vertical position of the point. - public Point(int x, int y) - : this() - { - this.X = x; - this.Y = y; - } - - /// - /// Initializes a new instance of the struct from the given . - /// - /// The size - public Point(Size size) - { - this.X = size.Width; - this.Y = size.Height; - } - - /// - /// Gets or sets the x-coordinate of this . - /// - public int X { get; set; } - - /// - /// Gets or sets the y-coordinate of this . - /// - public int Y { get; set; } - - /// - /// Gets a value indicating whether this is empty. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public bool IsEmpty => this.Equals(Empty); - - /// - /// Creates a with the coordinates of the specified . - /// - /// The point - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PointF(Point point) => new PointF(point.X, point.Y); - - /// - /// Creates a with the coordinates of the specified . - /// - /// The point - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Vector2(Point point) => new Vector2(point.X, point.Y); - - /// - /// Creates a with the coordinates of the specified . - /// - /// The point - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator Size(Point point) => new Size(point.X, point.Y); - - /// - /// Translates a by a given . - /// - /// The point on the left hand of the operand. - /// The size on the right hand of the operand. - /// - /// The - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point operator +(Point point, Size size) => Add(point, size); - - /// - /// Translates a by the negative of a given . - /// - /// The point on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point operator -(Point point, Size size) => Subtract(point, size); - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Point left, Point right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Point left, Point right) => !left.Equals(right); - - /// - /// Translates a by the negative of a given . - /// - /// The point on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point Add(Point point, Size size) => new Point(unchecked(point.X + size.Width), unchecked(point.Y + size.Height)); - - /// - /// Translates a by the negative of a given . - /// - /// The point on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point Subtract(Point point, Size size) => new Point(unchecked(point.X - size.Width), unchecked(point.Y - size.Height)); - - /// - /// Converts a to a by performing a ceiling operation on all the coordinates. - /// - /// The point - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point Ceiling(PointF point) => new Point(unchecked((int)MathF.Ceiling(point.X)), unchecked((int)MathF.Ceiling(point.Y))); - - /// - /// Converts a to a by performing a round operation on all the coordinates. - /// - /// The point - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point Round(PointF point) => new Point(unchecked((int)MathF.Round(point.X)), unchecked((int)MathF.Round(point.Y))); - - /// - /// Converts a to a by performing a truncate operation on all the coordinates. - /// - /// The point - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point Truncate(PointF point) => new Point(unchecked((int)point.X), unchecked((int)point.Y)); - - /// - /// Converts a to a by performing a round operation on all the coordinates. - /// - /// The vector - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point Round(Vector2 vector) => new Point(unchecked((int)MathF.Round(vector.X)), unchecked((int)MathF.Round(vector.Y))); - - /// - /// Rotates a point around the given rotation matrix. - /// - /// The point to rotate - /// Rotation matrix used - /// The rotated - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point Rotate(Point point, Matrix3x2 rotation) => Round(Vector2.Transform(new Vector2(point.X, point.Y), rotation)); - - /// - /// Skews a point using the given skew matrix. - /// - /// The point to rotate - /// Rotation matrix used - /// The rotated - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point Skew(Point point, Matrix3x2 skew) => Round(Vector2.Transform(new Vector2(point.X, point.Y), skew)); - - /// - /// Translates this by the specified amount. - /// - /// The amount to offset the x-coordinate. - /// The amount to offset the y-coordinate. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Offset(int dx, int dy) - { - unchecked - { - this.X += dx; - this.Y += dy; - } - } - - /// - /// Translates this by the specified amount. - /// - /// The used offset this . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Offset(Point point) => this.Offset(point.X, point.Y); - - /// - public override int GetHashCode() => this.GetHashCode(this); - - /// - public override string ToString() - { - if (this.IsEmpty) - { - return "Point [ Empty ]"; - } - - return $"Point [ X={this.X}, Y={this.Y} ]"; - } - - /// - public override bool Equals(object obj) => obj is Point && this.Equals((Point)obj); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Point other) => this.X == other.X && this.Y == other.Y; - - private static short HighInt16(int n) => unchecked((short)((n >> 16) & 0xffff)); - - private static short LowInt16(int n) => unchecked((short)(n & 0xffff)); - - private int GetHashCode(Point point) => point.X ^ point.Y; - } -} \ No newline at end of file diff --git a/src/ImageSharp/Numerics/PointF.cs b/src/ImageSharp/Numerics/PointF.cs deleted file mode 100644 index cbe5c7f48b..0000000000 --- a/src/ImageSharp/Numerics/PointF.cs +++ /dev/null @@ -1,233 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.ComponentModel; - using System.Numerics; - using System.Runtime.CompilerServices; - - /// - /// Represents an ordered pair of single precision floating point x- and y-coordinates that defines a point in - /// a two-dimensional plane. - /// - /// - /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, - /// as it avoids the need to create new values for modification operations. - /// - public struct PointF : IEquatable - { - /// - /// Represents a that has X and Y values set to zero. - /// - public static readonly PointF Empty = default(PointF); - - /// - /// Initializes a new instance of the struct. - /// - /// The horizontal position of the point. - /// The vertical position of the point. - public PointF(float x, float y) - : this() - { - this.X = x; - this.Y = y; - } - - /// - /// Initializes a new instance of the struct from the given . - /// - /// The size - public PointF(SizeF size) - { - this.X = size.Width; - this.Y = size.Height; - } - - /// - /// Gets or sets the x-coordinate of this . - /// - public float X { get; set; } - - /// - /// Gets or sets the y-coordinate of this . - /// - public float Y { get; set; } - - /// - /// Gets a value indicating whether this is empty. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public bool IsEmpty => this.Equals(Empty); - - /// - /// Creates a with the coordinates of the specified . - /// - /// The vector. - /// - /// The . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PointF(Vector2 vector) => new PointF(vector.X, vector.Y); - - /// - /// Creates a with the coordinates of the specified . - /// - /// The point. - /// - /// The . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Vector2(PointF point) => new Vector2(point.X, point.Y); - - /// - /// Creates a with the coordinates of the specified by truncating each of the coordinates. - /// - /// The point. - /// - /// The . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator Point(PointF point) => Point.Truncate(point); - - /// - /// Translates a by a given . - /// - /// The point on the left hand of the operand. - /// The size on the right hand of the operand. - /// - /// The - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PointF operator +(PointF point, SizeF size) => Add(point, size); - - /// - /// Translates a by the negative of a given . - /// - /// The point on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PointF operator -(PointF point, SizeF size) => Subtract(point, size); - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(PointF left, PointF right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(PointF left, PointF right) => !left.Equals(right); - - /// - /// Translates a by the negative of a given . - /// - /// The point on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PointF Add(PointF point, SizeF size) => new PointF(point.X + size.Width, point.Y + size.Height); - - /// - /// Translates a by the negative of a given . - /// - /// The point on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PointF Subtract(PointF point, SizeF size) => new PointF(point.X - size.Width, point.Y - size.Height); - - /// - /// Rotates a point around the given rotation matrix. - /// - /// The point to rotate - /// Rotation matrix used - /// The rotated - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PointF Rotate(PointF point, Matrix3x2 rotation) => Vector2.Transform(new Vector2(point.X, point.Y), rotation); - - /// - /// Skews a point using the given skew matrix. - /// - /// The point to rotate - /// Rotation matrix used - /// The rotated - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PointF Skew(PointF point, Matrix3x2 skew) => Vector2.Transform(new Vector2(point.X, point.Y), skew); - - /// - /// Translates this by the specified amount. - /// - /// The amount to offset the x-coordinate. - /// The amount to offset the y-coordinate. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Offset(float dx, float dy) - { - this.X += dx; - this.Y += dy; - } - - /// - /// Translates this by the specified amount. - /// - /// The used offset this . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Offset(PointF point) => this.Offset(point.X, point.Y); - - /// - public override int GetHashCode() => this.GetHashCode(this); - - /// - public override string ToString() - { - if (this.IsEmpty) - { - return "PointF [ Empty ]"; - } - - return $"PointF [ X={this.X}, Y={this.Y} ]"; - } - - /// - public override bool Equals(object obj) => obj is PointF && this.Equals((PointF)obj); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(PointF other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); - - /// - /// Returns the hash code for this instance. - /// - /// - /// The instance of to return the hash code for. - /// - /// - /// A 32-bit signed integer that is the hash code for this instance. - /// - private int GetHashCode(PointF point) => point.X.GetHashCode() ^ point.Y.GetHashCode(); - } -} \ No newline at end of file diff --git a/src/ImageSharp/Numerics/Rectangle.cs b/src/ImageSharp/Numerics/Rectangle.cs deleted file mode 100644 index d16b22920a..0000000000 --- a/src/ImageSharp/Numerics/Rectangle.cs +++ /dev/null @@ -1,467 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.ComponentModel; - using System.Numerics; - using System.Runtime.CompilerServices; - - /// - /// Stores a set of four integers that represent the location and size of a rectangle. - /// - /// - /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, - /// as it avoids the need to create new values for modification operations. - /// - public struct Rectangle : IEquatable - { - /// - /// Represents a that has X, Y, Width, and Height values set to zero. - /// - public static readonly Rectangle Empty = default(Rectangle); - - /// - /// Initializes a new instance of the struct. - /// - /// The horizontal position of the rectangle. - /// The vertical position of the rectangle. - /// The width of the rectangle. - /// The height of the rectangle. - public Rectangle(int x, int y, int width, int height) - { - this.X = x; - this.Y = y; - this.Width = width; - this.Height = height; - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The which specifies the rectangles point in a two-dimensional plane. - /// - /// - /// The which specifies the rectangles height and width. - /// - public Rectangle(Point point, Size size) - { - this.X = point.X; - this.Y = point.Y; - this.Width = size.Width; - this.Height = size.Height; - } - - /// - /// Gets or sets the x-coordinate of this . - /// - public int X { get; set; } - - /// - /// Gets or sets the y-coordinate of this . - /// - public int Y { get; set; } - - /// - /// Gets or sets the width of this . - /// - public int Width { get; set; } - - /// - /// Gets or sets the height of this . - /// - public int Height { get; set; } - - /// - /// Gets or sets the coordinates of the upper-left corner of the rectangular region represented by this . - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public Point Location - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new Point(this.X, this.Y); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.X = value.X; - this.Y = value.Y; - } - } - - /// - /// Gets or sets the size of this . - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public Size Size - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new Size(this.Width, this.Height); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.Width = value.Width; - this.Height = value.Height; - } - } - - /// - /// Gets a value indicating whether this is empty. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public bool IsEmpty => this.Equals(Empty); - - /// - /// Gets the y-coordinate of the top edge of this . - /// - public int Top - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.Y; - } - } - - /// - /// Gets the x-coordinate of the right edge of this . - /// - public int Right - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return unchecked(this.X + this.Width); - } - } - - /// - /// Gets the y-coordinate of the bottom edge of this . - /// - public int Bottom - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return unchecked(this.Y + this.Height); - } - } - - /// - /// Gets the x-coordinate of the left edge of this . - /// - public int Left - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.X; - } - } - - /// - /// Creates a with the coordinates of the specified . - /// - /// The rectangle - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator RectangleF(Rectangle rectangle) => new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); - - /// - /// Creates a with the coordinates of the specified . - /// - /// The rectangle - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Vector4(Rectangle rectangle) => new Vector4(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rectangle left, Rectangle right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rectangle left, Rectangle right) => !left.Equals(right); - - /// - /// Creates a new with the specified location and size. - /// The left coordinate of the rectangle - /// The top coordinate of the rectangle - /// The right coordinate of the rectangle - /// The bottom coordinate of the rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - - // ReSharper disable once InconsistentNaming - public static Rectangle FromLTRB(int left, int top, int right, int bottom) => new Rectangle(left, top, unchecked(right - left), unchecked(bottom - top)); - - /// - /// Returns the center point of the given - /// - /// The rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point Center(Rectangle rectangle) => new Point(rectangle.Left + (rectangle.Width / 2), rectangle.Top + (rectangle.Height / 2)); - - /// - /// Creates a rectangle that represents the intersection between and - /// . If there is no intersection, an empty rectangle is returned. - /// - /// The first rectangle - /// The second rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rectangle Intersect(Rectangle a, Rectangle b) - { - int x1 = Math.Max(a.X, b.X); - int x2 = Math.Min(a.Right, b.Right); - int y1 = Math.Max(a.Y, b.Y); - int y2 = Math.Min(a.Bottom, b.Bottom); - - if (x2 >= x1 && y2 >= y1) - { - return new Rectangle(x1, y1, x2 - x1, y2 - y1); - } - - return Empty; - } - - /// - /// Creates a that is inflated by the specified amount. - /// - /// The rectangle - /// The amount to inflate the width by - /// The amount to inflate the height by - /// A new - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rectangle Inflate(Rectangle rectangle, int x, int y) - { - Rectangle r = rectangle; - r.Inflate(x, y); - return r; - } - - /// - /// Converts a to a by performing a ceiling operation on all the coordinates. - /// - /// The rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rectangle Ceiling(RectangleF rectangle) - { - unchecked - { - return new Rectangle( - (int)MathF.Ceiling(rectangle.X), - (int)MathF.Ceiling(rectangle.Y), - (int)MathF.Ceiling(rectangle.Width), - (int)MathF.Ceiling(rectangle.Height)); - } - } - - /// - /// Converts a to a by performing a truncate operation on all the coordinates. - /// - /// The rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rectangle Truncate(RectangleF rectangle) - { - unchecked - { - return new Rectangle( - (int)rectangle.X, - (int)rectangle.Y, - (int)rectangle.Width, - (int)rectangle.Height); - } - } - - /// - /// Converts a to a by performing a round operation on all the coordinates. - /// - /// The rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rectangle Round(RectangleF rectangle) - { - unchecked - { - return new Rectangle( - (int)MathF.Round(rectangle.X), - (int)MathF.Round(rectangle.Y), - (int)MathF.Round(rectangle.Width), - (int)MathF.Round(rectangle.Height)); - } - } - - /// - /// Creates a rectangle that represents the union between and . - /// - /// The first rectangle - /// The second rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rectangle Union(Rectangle a, Rectangle b) - { - int x1 = Math.Min(a.X, b.X); - int x2 = Math.Max(a.Right, b.Right); - int y1 = Math.Min(a.Y, b.Y); - int y2 = Math.Max(a.Bottom, b.Bottom); - - return new Rectangle(x1, y1, x2 - x1, y2 - y1); - } - - /// - /// Creates a Rectangle that represents the intersection between this Rectangle and the . - /// - /// The rectangle - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Intersect(Rectangle rectangle) - { - Rectangle result = Intersect(rectangle, this); - - this.X = result.X; - this.Y = result.Y; - this.Width = result.Width; - this.Height = result.Height; - } - - /// - /// Inflates this by the specified amount. - /// - /// The width - /// The height - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Inflate(int width, int height) - { - unchecked - { - this.X -= width; - this.Y -= height; - - this.Width += 2 * width; - this.Height += 2 * height; - } - } - - /// - /// Inflates this by the specified amount. - /// - /// The size - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Inflate(Size size) => this.Inflate(size.Width, size.Height); - - /// - /// Determines if the specfied point is contained within the rectangular region defined by - /// this . - /// - /// The x-coordinate of the given point. - /// The y-coordinate of the given point. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(int x, int y) => this.X <= x && x < this.Right && this.Y <= y && y < this.Bottom; - - /// - /// Determines if the specified point is contained within the rectangular region defined by this . - /// - /// The point - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(Point point) => this.Contains(point.X, point.Y); - - /// - /// Determines if the rectangular region represented by is entirely contained - /// within the rectangular region represented by this . - /// - /// The rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(Rectangle rectangle) => - (this.X <= rectangle.X) && (rectangle.Right <= this.Right) && - (this.Y <= rectangle.Y) && (rectangle.Bottom <= this.Bottom); - - /// - /// Determines if the specfied intersects the rectangular region defined by - /// this . - /// - /// The other Rectange - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IntersectsWith(Rectangle rectangle) => - (rectangle.X < this.Right) && (this.X < rectangle.Right) && - (rectangle.Y < this.Bottom) && (this.Y < rectangle.Bottom); - - /// - /// Adjusts the location of this rectangle by the specified amount. - /// - /// The point - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Offset(Point point) => this.Offset(point.X, point.Y); - - /// - /// Adjusts the location of this rectangle by the specified amount. - /// - /// The amount to offset the x-coordinate. - /// The amount to offset the y-coordinate. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Offset(int dx, int dy) - { - unchecked - { - this.X += dx; - this.Y += dy; - } - } - - /// - public override int GetHashCode() => this.GetHashCode(this); - - /// - public override string ToString() - { - if (this.IsEmpty) - { - return "Rectangle [ Empty ]"; - } - - return $"Rectangle [ X={this.X}, Y={this.Y}, Width={this.Width}, Height={this.Height} ]"; - } - - /// - public override bool Equals(object obj) => obj is Rectangle && this.Equals((Rectangle)obj); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rectangle other) => this.X == other.X && this.Y == other.Y && this.Width == other.Width && this.Height == other.Height; - - private int GetHashCode(Rectangle rectangle) - { - unchecked - { - int hashCode = rectangle.X; - hashCode = (hashCode * 397) ^ rectangle.Y; - hashCode = (hashCode * 397) ^ rectangle.Width; - hashCode = (hashCode * 397) ^ rectangle.Height; - return hashCode; - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Numerics/RectangleF.cs b/src/ImageSharp/Numerics/RectangleF.cs deleted file mode 100644 index 7611c96029..0000000000 --- a/src/ImageSharp/Numerics/RectangleF.cs +++ /dev/null @@ -1,400 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.ComponentModel; - using System.Numerics; - using System.Runtime.CompilerServices; - - /// - /// Stores a set of four single precision floating points that represent the location and size of a rectangle. - /// - /// - /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, - /// as it avoids the need to create new values for modification operations. - /// - public struct RectangleF : IEquatable - { - /// - /// Represents a that has X, Y, Width, and Height values set to zero. - /// - public static readonly RectangleF Empty = default(RectangleF); - - /// - /// Initializes a new instance of the struct. - /// - /// The horizontal position of the rectangle. - /// The vertical position of the rectangle. - /// The width of the rectangle. - /// The height of the rectangle. - public RectangleF(float x, float y, float width, float height) - { - this.X = x; - this.Y = y; - this.Width = width; - this.Height = height; - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The which specifies the rectangles point in a two-dimensional plane. - /// - /// - /// The which specifies the rectangles height and width. - /// - public RectangleF(PointF point, SizeF size) - { - this.X = point.X; - this.Y = point.Y; - this.Width = size.Width; - this.Height = size.Height; - } - - /// - /// Gets or sets the x-coordinate of this . - /// - public float X { get; set; } - - /// - /// Gets or sets the y-coordinate of this . - /// - public float Y { get; set; } - - /// - /// Gets or sets the width of this . - /// - public float Width { get; set; } - - /// - /// Gets or sets the height of this . - /// - public float Height { get; set; } - - /// - /// Gets or sets the coordinates of the upper-left corner of the rectangular region represented by this . - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public PointF Location - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new PointF(this.X, this.Y); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.X = value.X; - this.Y = value.Y; - } - } - - /// - /// Gets or sets the size of this . - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public SizeF Size - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new SizeF(this.Width, this.Height); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.Width = value.Width; - this.Height = value.Height; - } - } - - /// - /// Gets a value indicating whether this is empty. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public bool IsEmpty => (this.Width <= 0) || (this.Height <= 0); - - /// - /// Gets the y-coordinate of the top edge of this . - /// - public float Top - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.Y; - } - } - - /// - /// Gets the x-coordinate of the right edge of this . - /// - public float Right - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.X + this.Width; - } - } - - /// - /// Gets the y-coordinate of the bottom edge of this . - /// - public float Bottom - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.Y + this.Height; - } - } - - /// - /// Gets the x-coordinate of the left edge of this . - /// - public float Left - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.X; - } - } - - /// - /// Creates a with the coordinates of the specified by truncating each coordinate. - /// - /// The rectangle - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator Rectangle(RectangleF rectangle) => Rectangle.Truncate(rectangle); - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(RectangleF left, RectangleF right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(RectangleF left, RectangleF right) => !left.Equals(right); - - /// - /// Creates a new with the specified location and size. - /// The left coordinate of the rectangle - /// The top coordinate of the rectangle - /// The right coordinate of the rectangle - /// The bottom coordinate of the rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - - // ReSharper disable once InconsistentNaming - public static RectangleF FromLTRB(float left, float top, float right, float bottom) => new RectangleF(left, top, right - left, bottom - top); - - /// - /// Returns the center point of the given - /// - /// The rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PointF Center(RectangleF rectangle) => new PointF(rectangle.Left + (rectangle.Width / 2), rectangle.Top + (rectangle.Height / 2)); - - /// - /// Creates a rectangle that represents the intersection between and - /// . If there is no intersection, an empty rectangle is returned. - /// - /// The first rectangle - /// The second rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static RectangleF Intersect(RectangleF a, RectangleF b) - { - float x1 = MathF.Max(a.X, b.X); - float x2 = MathF.Min(a.Right, b.Right); - float y1 = MathF.Max(a.Y, b.Y); - float y2 = MathF.Min(a.Bottom, b.Bottom); - - if (x2 >= x1 && y2 >= y1) - { - return new RectangleF(x1, y1, x2 - x1, y2 - y1); - } - - return Empty; - } - - /// - /// Creates a that is inflated by the specified amount. - /// - /// The rectangle - /// The amount to inflate the width by - /// The amount to inflate the height by - /// A new - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static RectangleF Inflate(RectangleF rectangle, float x, float y) - { - RectangleF r = rectangle; - r.Inflate(x, y); - return r; - } - - /// - /// Creates a rectangle that represents the union between and . - /// - /// The first rectangle - /// The second rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static RectangleF Union(RectangleF a, RectangleF b) - { - float x1 = MathF.Min(a.X, b.X); - float x2 = MathF.Max(a.Right, b.Right); - float y1 = MathF.Min(a.Y, b.Y); - float y2 = MathF.Max(a.Bottom, b.Bottom); - - return new RectangleF(x1, y1, x2 - x1, y2 - y1); - } - - /// - /// Creates a RectangleF that represents the intersection between this RectangleF and the . - /// - /// The rectangle - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Intersect(RectangleF rectangle) - { - RectangleF result = Intersect(rectangle, this); - - this.X = result.X; - this.Y = result.Y; - this.Width = result.Width; - this.Height = result.Height; - } - - /// - /// Inflates this by the specified amount. - /// - /// The width - /// The height - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Inflate(float width, float height) - { - this.X -= width; - this.Y -= height; - - this.Width += 2 * width; - this.Height += 2 * height; - } - - /// - /// Inflates this by the specified amount. - /// - /// The size - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Inflate(SizeF size) => this.Inflate(size.Width, size.Height); - - /// - /// Determines if the specfied point is contained within the rectangular region defined by - /// this . - /// - /// The x-coordinate of the given point. - /// The y-coordinate of the given point. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(float x, float y) => this.X <= x && x < this.Right && this.Y <= y && y < this.Bottom; - - /// - /// Determines if the specified point is contained within the rectangular region defined by this . - /// - /// The point - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(PointF point) => this.Contains(point.X, point.Y); - - /// - /// Determines if the rectangular region represented by is entirely contained - /// within the rectangular region represented by this . - /// - /// The rectangle - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Contains(RectangleF rectangle) => - (this.X <= rectangle.X) && (rectangle.Right <= this.Right) && - (this.Y <= rectangle.Y) && (rectangle.Bottom <= this.Bottom); - - /// - /// Determines if the specfied intersects the rectangular region defined by - /// this . - /// - /// The other Rectange - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IntersectsWith(RectangleF rectangle) => - (rectangle.X < this.Right) && (this.X < rectangle.Right) && - (rectangle.Y < this.Bottom) && (this.Y < rectangle.Bottom); - - /// - /// Adjusts the location of this rectangle by the specified amount. - /// - /// The point - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Offset(PointF point) => this.Offset(point.X, point.Y); - - /// - /// Adjusts the location of this rectangle by the specified amount. - /// - /// The amount to offset the x-coordinate. - /// The amount to offset the y-coordinate. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Offset(float dx, float dy) - { - this.X += dx; - this.Y += dy; - } - - /// - public override int GetHashCode() => this.GetHashCode(this); - - /// - public override string ToString() - { - if (this.IsEmpty) - { - return "RectangleF [ Empty ]"; - } - - return $"RectangleF [ X={this.X}, Y={this.Y}, Width={this.Width}, Height={this.Height} ]"; - } - - /// - public override bool Equals(object obj) => obj is RectangleF && this.Equals((RectangleF)obj); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(RectangleF other) => this.X.Equals(other.X) && this.Y.Equals(other.Y) && this.Width.Equals(other.Width) && this.Height.Equals(other.Height); - - private int GetHashCode(RectangleF rectangle) - { - unchecked - { - int hashCode = rectangle.X.GetHashCode(); - hashCode = (hashCode * 397) ^ rectangle.Y.GetHashCode(); - hashCode = (hashCode * 397) ^ rectangle.Width.GetHashCode(); - hashCode = (hashCode * 397) ^ rectangle.Height.GetHashCode(); - return hashCode; - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Numerics/Size.cs b/src/ImageSharp/Numerics/Size.cs deleted file mode 100644 index 79ee1ddead..0000000000 --- a/src/ImageSharp/Numerics/Size.cs +++ /dev/null @@ -1,225 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.ComponentModel; - using System.Runtime.CompilerServices; - - /// - /// Stores an ordered pair of integers, which specify a height and width. - /// - /// - /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, - /// as it avoids the need to create new values for modification operations. - /// - public struct Size : IEquatable - { - /// - /// Represents a that has Width and Height values set to zero. - /// - public static readonly Size Empty = default(Size); - - /// - /// Initializes a new instance of the struct. - /// - /// The width and height of the size - public Size(int value) - : this() - { - this.Width = value; - this.Height = value; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The width of the size. - /// The height of the size. - public Size(int width, int height) - { - this.Width = width; - this.Height = height; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The size - public Size(Size size) - : this() - { - this.Width = size.Width; - this.Height = size.Height; - } - - /// - /// Initializes a new instance of the struct from the given . - /// - /// The point - public Size(Point point) - { - this.Width = point.X; - this.Height = point.Y; - } - - /// - /// Gets or sets the width of this . - /// - public int Width { get; set; } - - /// - /// Gets or sets the height of this . - /// - public int Height { get; set; } - - /// - /// Gets a value indicating whether this is empty. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public bool IsEmpty => this.Equals(Empty); - - /// - /// Creates a with the dimensions of the specified . - /// - /// The point - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator SizeF(Size size) => new SizeF(size.Width, size.Height); - - /// - /// Converts the given into a . - /// - /// The size - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator Point(Size size) => new Point(size.Width, size.Height); - - /// - /// Computes the sum of adding two sizes. - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// - /// The - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Size operator +(Size left, Size right) => Add(left, right); - - /// - /// Computes the difference left by subtracting one size from another. - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// - /// The - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Size operator -(Size left, Size right) => Subtract(left, right); - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Size left, Size right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Size left, Size right) => !left.Equals(right); - - /// - /// Performs vector addition of two objects. - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Size Add(Size left, Size right) => new Size(unchecked(left.Width + right.Width), unchecked(left.Height + right.Height)); - - /// - /// Contracts a by another - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Size Subtract(Size left, Size right) => new Size(unchecked(left.Width - right.Width), unchecked(left.Height - right.Height)); - - /// - /// Converts a to a by performing a ceiling operation on all the dimensions. - /// - /// The size - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Size Ceiling(SizeF size) => new Size(unchecked((int)MathF.Ceiling(size.Width)), unchecked((int)MathF.Ceiling(size.Height))); - - /// - /// Converts a to a by performing a round operation on all the dimensions. - /// - /// The size - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Size Round(SizeF size) => new Size(unchecked((int)MathF.Round(size.Width)), unchecked((int)MathF.Round(size.Height))); - - /// - /// Converts a to a by performing a round operation on all the dimensions. - /// - /// The size - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Size Truncate(SizeF size) => new Size(unchecked((int)size.Width), unchecked((int)size.Height)); - - /// - public override int GetHashCode() => this.GetHashCode(this); - - /// - public override string ToString() - { - if (this.IsEmpty) - { - return "Size [ Empty ]"; - } - - return $"Size [ Width={this.Width}, Height={this.Height} ]"; - } - - /// - public override bool Equals(object obj) => obj is Size && this.Equals((Size)obj); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Size other) => this.Width == other.Width && this.Height == other.Height; - - /// - /// Returns the hash code for this instance. - /// - /// - /// The instance of to return the hash code for. - /// - /// - /// A 32-bit signed integer that is the hash code for this instance. - /// - private int GetHashCode(Size size) => size.Width ^ size.Height; - } -} \ No newline at end of file diff --git a/src/ImageSharp/Numerics/SizeF.cs b/src/ImageSharp/Numerics/SizeF.cs deleted file mode 100644 index 78078fd01f..0000000000 --- a/src/ImageSharp/Numerics/SizeF.cs +++ /dev/null @@ -1,179 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.ComponentModel; - using System.Runtime.CompilerServices; - - /// - /// Stores an ordered pair of single precision floating points, which specify a height and width. - /// - /// - /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, - /// as it avoids the need to create new values for modification operations. - /// - public struct SizeF : IEquatable - { - /// - /// Represents a that has Width and Height values set to zero. - /// - public static readonly SizeF Empty = default(SizeF); - - /// - /// Initializes a new instance of the struct. - /// - /// The width of the size. - /// The height of the size. - public SizeF(float width, float height) - { - this.Width = width; - this.Height = height; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The size - public SizeF(SizeF size) - : this() - { - this.Width = size.Width; - this.Height = size.Height; - } - - /// - /// Initializes a new instance of the struct from the given . - /// - /// The point - public SizeF(PointF point) - { - this.Width = point.X; - this.Height = point.Y; - } - - /// - /// Gets or sets the width of this . - /// - public float Width { get; set; } - - /// - /// Gets or sets the height of this . - /// - public float Height { get; set; } - - /// - /// Gets a value indicating whether this is empty. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public bool IsEmpty => this.Equals(Empty); - - /// - /// Creates a with the dimensions of the specified by truncating each of the dimensions. - /// - /// The size. - /// - /// The . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator Size(SizeF size) => new Size(unchecked((int)size.Width), unchecked((int)size.Height)); - - /// - /// Converts the given into a . - /// - /// The size - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator PointF(SizeF size) => new PointF(size.Width, size.Height); - - /// - /// Computes the sum of adding two sizes. - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// - /// The - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static SizeF operator +(SizeF left, SizeF right) => Add(left, right); - - /// - /// Computes the difference left by subtracting one size from another. - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// - /// The - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static SizeF operator -(SizeF left, SizeF right) => Subtract(left, right); - - /// - /// Compares two objects for equality. - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(SizeF left, SizeF right) => left.Equals(right); - - /// - /// Compares two objects for inequality. - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(SizeF left, SizeF right) => !left.Equals(right); - - /// - /// Performs vector addition of two objects. - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static SizeF Add(SizeF left, SizeF right) => new SizeF(left.Width + right.Width, left.Height + right.Height); - - /// - /// Contracts a by another - /// - /// The size on the left hand of the operand. - /// The size on the right hand of the operand. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static SizeF Subtract(SizeF left, SizeF right) => new SizeF(left.Width - right.Width, left.Height - right.Height); - - /// - public override int GetHashCode() - { - return this.GetHashCode(this); - } - - /// - public override string ToString() - { - if (this.IsEmpty) - { - return "SizeF [ Empty ]"; - } - - return $"SizeF [ Width={this.Width}, Height={this.Height} ]"; - } - - /// - public override bool Equals(object obj) => obj is SizeF && this.Equals((SizeF)obj); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(SizeF other) => this.Width.Equals(other.Width) && this.Height.Equals(other.Height); - - private int GetHashCode(SizeF size) => size.Width.GetHashCode() ^ size.Height.GetHashCode(); - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenderMode.cs b/src/ImageSharp/PixelFormats/PixelBlenderMode.cs index d8031fe6e5..1e48f71814 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenderMode.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenderMode.cs @@ -57,6 +57,66 @@ namespace ImageSharp.PixelFormats /// /// Multiplies or screens the colors, depending on the source value. /// - HardLight + HardLight, + + /// + /// returns the source colors + /// + Src, + + /// + /// returns the source over the destination + /// + Atop, + + /// + /// returns the detination over the source + /// + Over, + + /// + /// the source where the desitnation and source overlap + /// + In, + + /// + /// the destination where the desitnation and source overlap + /// + Out, + + /// + /// the destination where the source does not overlap it + /// + Dest, + + /// + /// the source where they dont overlap othersie dest in overlapping parts + /// + DestAtop, + + /// + /// the destnation over the source + /// + DestOver, + + /// + /// the destination where the desitnation and source overlap + /// + DestIn, + + /// + /// the source where the desitnation and source overlap + /// + DestOut, + + /// + /// the clear. + /// + Clear, + + /// + /// clear where they overlap + /// + Xor } } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs deleted file mode 100644 index 261a986742..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System; - using System.Numerics; - - using ImageSharp.Memory; - using ImageSharp.PixelFormats; - - /// - /// Applies an "Add" blending to pixels. - /// - /// The type of the pixel - internal class DefaultAddPixelBlender : PixelBlender - where TPixel : struct, IPixel - { - /// - /// Gets the static instance of this blender. - /// - public static DefaultAddPixelBlender Instance { get; } = new DefaultAddPixelBlender(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - return PorterDuffFunctions.AddFunction(background, source, amount); - } - - /// - public override void Blend(Span destination, Span background, Span source, Span amount) - { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (Buffer buffer = new Buffer(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddFunction(backgroundSpan[i], sourceSpan[i], amount[i]); - } - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs deleted file mode 100644 index bca99e2f0d..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System; - using System.Numerics; - - using ImageSharp.Memory; - using ImageSharp.PixelFormats; - - /// - /// Applies an "Darken" blending to pixels. - /// - /// The type of the pixel - internal class DefaultDarkenPixelBlender : PixelBlender - where TPixel : struct, IPixel - { - /// - /// Gets the static instance of this blender. - /// - public static DefaultDarkenPixelBlender Instance { get; } = new DefaultDarkenPixelBlender(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - return PorterDuffFunctions.DarkenFunction(background, source, amount); - } - - /// - public override void Blend(Span destination, Span background, Span source, Span amount) - { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (Buffer buffer = new Buffer(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenFunction(backgroundSpan[i], sourceSpan[i], amount[i]); - } - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs deleted file mode 100644 index 646423cffb..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System; - using System.Numerics; - - using ImageSharp.Memory; - using ImageSharp.PixelFormats; - - /// - /// Applies an "Hard Light" blending to pixels. - /// - /// The type of the pixel - internal class DefaultHardLightPixelBlender : PixelBlender - where TPixel : struct, IPixel - { - /// - /// Gets the static instance of this blender. - /// - public static DefaultHardLightPixelBlender Instance { get; } = new DefaultHardLightPixelBlender(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - return PorterDuffFunctions.HardLightFunction(background, source, amount); - } - - /// - public override void Blend(Span destination, Span background, Span source, Span amount) - { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (Buffer buffer = new Buffer(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightFunction(backgroundSpan[i], sourceSpan[i], amount[i]); - } - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs deleted file mode 100644 index 55ad81e7a9..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System; - using System.Numerics; - - using ImageSharp.Memory; - using ImageSharp.PixelFormats; - - /// - /// Applies an "Lighten" blending to pixels. - /// - /// The type of the pixel - internal class DefaultLightenPixelBlender : PixelBlender - where TPixel : struct, IPixel - { - /// - /// Gets the static instance of this blender. - /// - public static DefaultLightenPixelBlender Instance { get; } = new DefaultLightenPixelBlender(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - return PorterDuffFunctions.LightenFunction(background, source, amount); - } - - /// - public override void Blend(Span destination, Span background, Span source, Span amount) - { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (Buffer buffer = new Buffer(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenFunction(backgroundSpan[i], sourceSpan[i], amount[i]); - } - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs deleted file mode 100644 index e21efaed07..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System; - using System.Numerics; - - using ImageSharp.Memory; - using ImageSharp.PixelFormats; - - /// - /// Applies an "Multiply" blending to pixels. - /// - /// The type of the pixel - internal class DefaultMultiplyPixelBlender : PixelBlender - where TPixel : struct, IPixel - { - /// - /// Gets the static instance of this blender. - /// - public static DefaultMultiplyPixelBlender Instance { get; } = new DefaultMultiplyPixelBlender(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - return PorterDuffFunctions.MultiplyFunction(background, source, amount); - } - - /// - public override void Blend(Span destination, Span background, Span source, Span amount) - { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (Buffer buffer = new Buffer(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplyFunction(backgroundSpan[i], sourceSpan[i], amount[i]); - } - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs deleted file mode 100644 index 9d63d11e0b..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultNormalPixelBlender{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System; - using System.Numerics; - - using ImageSharp.Memory; - using ImageSharp.PixelFormats; - - /// - /// Applies a "Normal" otherwise nown as "Alpha Blending" blending to pixels. - /// - /// The type of the pixel - internal class DefaultNormalPixelBlender : PixelBlender - where TPixel : struct, IPixel - { - /// - /// Gets the static instance of this blender. - /// - public static DefaultNormalPixelBlender Instance { get; } = new DefaultNormalPixelBlender(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - return PorterDuffFunctions.NormalBlendFunction(background, source, amount); - } - - /// - public override void Blend(Span destination, Span background, Span source, Span amount) - { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (Buffer buffer = new Buffer(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalBlendFunction(backgroundSpan[i], sourceSpan[i], amount[i]); - } - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs deleted file mode 100644 index 8172909ecd..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultOverlayPixelBlender{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System; - using System.Numerics; - - using ImageSharp.Memory; - using ImageSharp.PixelFormats; - - /// - /// Applies an "Overlay" blending to pixels. - /// - /// The type of the pixel - internal class DefaultOverlayPixelBlender : PixelBlender - where TPixel : struct, IPixel - { - /// - /// Gets the static instance of this blender. - /// - public static DefaultOverlayPixelBlender Instance { get; } = new DefaultOverlayPixelBlender(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - return PorterDuffFunctions.OverlayFunction(background, source, amount); - } - - /// - public override void Blend(Span destination, Span background, Span source, Span amount) - { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (Buffer buffer = new Buffer(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlayFunction(backgroundSpan[i], sourceSpan[i], amount[i]); - } - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs new file mode 100644 index 0000000000..915d9a9244 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -0,0 +1,849 @@ +// +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.PixelFormats.PixelBlenders +{ + using System; + using System.Numerics; + using ImageSharp.Memory; + + + /// + /// Collection of Porter Duff alpha blending functions applying different composition models. + /// + /// + /// These functions are designed to be a general solution for all color cases, + /// that is, they take in account the alpha value of both the backdrop + /// and source, and there's no need to alpha-premultiply neither the backdrop + /// nor the source. + /// Note there are faster functions for when the backdrop color is known + /// to be opaque + /// + internal static class DefaultPixelBlenders + where TPixel : struct, IPixel + { + + internal class Normal : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Normal Instance { get; } = new Normal(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Normal(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Normal(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Multiply : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Multiply Instance { get; } = new Multiply(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Multiply(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Multiply(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Add : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Add Instance { get; } = new Add(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Add(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Add(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Substract : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Substract Instance { get; } = new Substract(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Substract(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Substract(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Screen : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Screen Instance { get; } = new Screen(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Screen(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Screen(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Darken : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Darken Instance { get; } = new Darken(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Darken(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Darken(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Lighten : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Lighten Instance { get; } = new Lighten(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Lighten(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Lighten(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Overlay : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Overlay Instance { get; } = new Overlay(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Overlay(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Overlay(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class HardLight : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static HardLight Instance { get; } = new HardLight(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.HardLight(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.HardLight(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Src : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Src Instance { get; } = new Src(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Src(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Src(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Atop : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Atop Instance { get; } = new Atop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Atop(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Atop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Over : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Over Instance { get; } = new Over(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Over(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Over(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class In : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static In Instance { get; } = new In(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.In(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.In(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Out : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Out Instance { get; } = new Out(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Out(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Out(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Dest : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Dest Instance { get; } = new Dest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Dest(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Dest(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class DestAtop : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static DestAtop Instance { get; } = new DestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DestAtop(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class DestOver : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static DestOver Instance { get; } = new DestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DestOver(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DestOver(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class DestIn : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static DestIn Instance { get; } = new DestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DestIn(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DestIn(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class DestOut : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static DestOut Instance { get; } = new DestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.DestOut(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.DestOut(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Clear : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Clear Instance { get; } = new Clear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Clear(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Clear(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + internal class Xor : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static Xor Instance { get; } = new Xor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.Xor(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.Xor(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt new file mode 100644 index 0000000000..230b05499f --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -0,0 +1,118 @@ +<# +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +// +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.PixelFormats.PixelBlenders +{ + using System; + using System.Numerics; + using ImageSharp.Memory; + + + /// + /// Collection of Porter Duff alpha blending functions applying different composition models. + /// + /// + /// These functions are designed to be a general solution for all color cases, + /// that is, they take in account the alpha value of both the backdrop + /// and source, and there's no need to alpha-premultiply neither the backdrop + /// nor the source. + /// Note there are faster functions for when the backdrop color is known + /// to be opaque + /// + internal static class DefaultPixelBlenders + where TPixel : struct, IPixel + { + +<# + + + + string[] blenders = new []{ + "Normal", + "Multiply", + "Add", + "Substract", + "Screen", + "Darken", + "Lighten", + "Overlay", + "HardLight", + "Src" , + "Atop" , + "Over" , + "In" , + "Out" , + "Dest" , + "DestAtop" , + "DestOver" , + "DestIn" , + "DestOut" , + "Clear" , + "Xor" , + }; + + + + foreach(var blender in blenders) { +#> + internal class <#=blender#> : PixelBlender + { + + /// + /// Gets the static instance of this blender. + /// + public static <#=blender#> Instance { get; } = new <#=blender#>(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + return PorterDuffFunctions.<#=blender#>(background, source, amount); + } + + /// + public override void Blend(Span destination, Span background, Span source, Span amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (Buffer buffer = new Buffer(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + for (int i = 0; i < destination.Length; i++) + { + destinationSpan[i] = PorterDuffFunctions.<#=blender#>(backgroundSpan[i], sourceSpan[i], amount[i]); + } + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + } +<# + + } + +#> + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultScreenPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultScreenPixelBlender{TPixel}.cs deleted file mode 100644 index 8405c3946b..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultScreenPixelBlender{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System; - using System.Numerics; - - using ImageSharp.Memory; - using ImageSharp.PixelFormats; - - /// - /// Applies an "Screen" blending to pixels. - /// - /// The type of the pixel - internal class DefaultScreenPixelBlender : PixelBlender - where TPixel : struct, IPixel - { - /// - /// Gets the static instance of this blender. - /// - public static DefaultScreenPixelBlender Instance { get; } = new DefaultScreenPixelBlender(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - return PorterDuffFunctions.ScreenFunction(background, source, amount); - } - - /// - public override void Blend(Span destination, Span background, Span source, Span amount) - { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (Buffer buffer = new Buffer(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenFunction(backgroundSpan[i], sourceSpan[i], amount[i]); - } - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultSubstractPixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultSubstractPixelBlender{TPixel}.cs deleted file mode 100644 index ab44cb7609..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultSubstractPixelBlender{TPixel}.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System; - using System.Numerics; - - using ImageSharp.Memory; - using ImageSharp.PixelFormats; - - /// - /// Applies an "Subtract" blending to pixels. - /// - /// The type of the pixel - internal class DefaultSubstractPixelBlender : PixelBlender - where TPixel : struct, IPixel - { - /// - /// Gets the static instance of this blender. - /// - public static DefaultSubstractPixelBlender Instance { get; } = new DefaultSubstractPixelBlender(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - return PorterDuffFunctions.SubstractFunction(background, source, amount); - } - - /// - public override void Blend(Span destination, Span background, Span source, Span amount) - { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (Buffer buffer = new Buffer(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubstractFunction(backgroundSpan[i], sourceSpan[i], amount[i]); - } - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs new file mode 100644 index 0000000000..4213be0bae --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -0,0 +1,451 @@ +// +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.PixelFormats.PixelBlenders +{ + using System.Numerics; + using System.Runtime.CompilerServices; + + + internal static partial class PorterDuffFunctions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Src(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + Vector4 xform = source; + + // calculate weights + float xw = Vector4.Zero.W * source.W; + float bw = Vector4.Zero.W - xw; + float sw = source.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Atop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + Vector4 xform = source; + + // calculate weights + float xw = backdrop.W * Vector4.Zero.W; + float bw = backdrop.W - xw; + float sw = Vector4.Zero.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Over(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + Vector4 xform = source; + + // calculate weights + float xw = backdrop.W * source.W; + float bw = backdrop.W - xw; + float sw = source.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 In(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + Vector4 xform = source; + + // calculate weights + float xw = Vector4.Zero.W * Vector4.Zero.W; + float bw = Vector4.Zero.W - xw; + float sw = Vector4.Zero.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Out(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + Vector4 xform = Vector4.Zero; + + // calculate weights + float xw = Vector4.Zero.W * source.W; + float bw = Vector4.Zero.W - xw; + float sw = source.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Dest(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + Vector4 xform = backdrop; + + // calculate weights + float xw = backdrop.W * Vector4.Zero.W; + float bw = backdrop.W - xw; + float sw = Vector4.Zero.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DestAtop(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + Vector4 xform = backdrop; + + // calculate weights + float xw = Vector4.Zero.W * source.W; + float bw = Vector4.Zero.W - xw; + float sw = source.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (Vector4.Zero * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DestOver(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + Vector4 xform = backdrop; + + // calculate weights + float xw = backdrop.W * source.W; + float bw = backdrop.W - xw; + float sw = source.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DestIn(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + Vector4 xform = backdrop; + + // calculate weights + float xw = Vector4.Zero.W * Vector4.Zero.W; + float bw = Vector4.Zero.W - xw; + float sw = Vector4.Zero.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DestOut(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + Vector4 xform = Vector4.Zero; + + // calculate weights + float xw = backdrop.W * Vector4.Zero.W; + float bw = backdrop.W - xw; + float sw = Vector4.Zero.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (backdrop * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Clear(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + Vector4 xform = Vector4.Zero; + + // calculate weights + float xw = Vector4.Zero.W * Vector4.Zero.W; + float bw = Vector4.Zero.W - xw; + float sw = Vector4.Zero.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (Vector4.Zero * bw) + (Vector4.Zero * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Xor(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); + source.W *= opacity; + Vector4 xform = Vector4.Zero; + + // calculate weights + float xw = backdrop.W * source.W; + float bw = backdrop.W - xw; + float sw = source.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Normal(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Normal(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Multiply(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Multiply(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Add(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Add(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Substract(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Substract(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Screen(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Screen(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Darken(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Darken(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Lighten(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Lighten(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Overlay(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Overlay(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel HardLight(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(HardLight(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Src(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Src(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Atop(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Atop(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Over(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Over(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel In(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(In(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Out(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Out(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Dest(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Dest(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DestAtop(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(DestAtop(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DestOver(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(DestOver(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DestIn(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(DestIn(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel DestOut(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(DestOut(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Clear(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Clear(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel Xor(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(Xor(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt new file mode 100644 index 0000000000..53d22d8f38 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -0,0 +1,112 @@ +<# +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +// +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.PixelFormats.PixelBlenders +{ + using System.Numerics; + using System.Runtime.CompilerServices; + + + internal static partial class PorterDuffFunctions + { +<# + + void GeneratePixelBlender (string blender) + { +#> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel <#=blender#>(TPixel backdrop, TPixel source, float amount) + where TPixel : struct, IPixel + { + TPixel dest = default(TPixel); + dest.PackFromVector4(<#=blender#>(backdrop.ToVector4(), source.ToVector4(), amount)); + return dest; + } + +<# + } + + void GenerateVectorCompositor(string name, string sourceVar, string destVar, string blendVar) + { +#> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 <#=name#>(Vector4 backdrop, Vector4 source, float opacity) + { + opacity = opacity.Clamp(0, 1); +<# if(sourceVar != "Vector4.Zero" ) { #> + source.W *= opacity; +<# } #> + Vector4 xform = <#=blendVar#>; + + // calculate weights + float xw = <#=destVar#>.W * <#=sourceVar#>.W; + float bw = <#=destVar#>.W - xw; + float sw = <#=sourceVar#>.W - xw; + + // calculate final alpha + float a = xw + bw + sw; + + // calculate final value + xform = ((xform * xw) + (<#=destVar#> * bw) + (<#=sourceVar#> * sw)) / MathF.Max(a, Constants.Epsilon); + + return Vector4.Lerp(backdrop, xform, opacity); + } + +<# + } + GenerateVectorCompositor("Src", "source", "Vector4.Zero", "source"); + GenerateVectorCompositor("Atop", "Vector4.Zero", "backdrop", "source"); + GenerateVectorCompositor("Over", "source", "backdrop", "source"); + GenerateVectorCompositor("In", "Vector4.Zero", "Vector4.Zero", "source"); + GenerateVectorCompositor("Out", "source", "Vector4.Zero", "Vector4.Zero"); + GenerateVectorCompositor("Dest", "Vector4.Zero", "backdrop", "backdrop"); + GenerateVectorCompositor("DestAtop", "source", "Vector4.Zero", "backdrop"); + GenerateVectorCompositor("DestOver", "source", "backdrop", "backdrop"); + GenerateVectorCompositor("DestIn", "Vector4.Zero", "Vector4.Zero", "backdrop"); + GenerateVectorCompositor("DestOut", "Vector4.Zero", "backdrop", "Vector4.Zero"); + GenerateVectorCompositor("Clear", "Vector4.Zero", "Vector4.Zero", "Vector4.Zero"); + GenerateVectorCompositor("Xor", "source", "backdrop", "Vector4.Zero"); + + + GeneratePixelBlender("Normal"); + GeneratePixelBlender("Multiply"); + GeneratePixelBlender("Add"); + GeneratePixelBlender("Substract"); + GeneratePixelBlender("Screen"); + GeneratePixelBlender("Darken"); + GeneratePixelBlender("Lighten"); + GeneratePixelBlender("Overlay"); + GeneratePixelBlender("HardLight"); + + GeneratePixelBlender("Src"); + GeneratePixelBlender("Atop"); + GeneratePixelBlender("Over"); + GeneratePixelBlender("In"); + GeneratePixelBlender("Out"); + GeneratePixelBlender("Dest"); + GeneratePixelBlender("DestAtop"); + GeneratePixelBlender("DestOver"); + GeneratePixelBlender("DestIn"); + GeneratePixelBlender("DestOut"); + GeneratePixelBlender("Clear"); + GeneratePixelBlender("Xor"); + + +#> + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs index 25eb6a5c87..b1fca9520c 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs @@ -29,14 +29,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders /// Opacity applied to Source Alpha /// Output color [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 NormalBlendFunction(Vector4 backdrop, Vector4 source, float opacity) + public static Vector4 Normal(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; - if (source.W == 0) - { - return backdrop; - } - return Compose(backdrop, source, source); } @@ -48,14 +43,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders /// Opacity applied to Source Alpha /// Output color [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 MultiplyFunction(Vector4 backdrop, Vector4 source, float opacity) + public static Vector4 Multiply(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; - if (source.W == 0) - { - return backdrop; - } - return Compose(backdrop, source, backdrop * source); } @@ -67,14 +57,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders /// Opacity applied to Source Alpha /// Output color [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 AddFunction(Vector4 backdrop, Vector4 source, float opacity) + public static Vector4 Add(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; - if (source.W == 0) - { - return backdrop; - } - return Compose(backdrop, source, Vector4.Min(Vector4.One, backdrop + source)); } @@ -86,14 +71,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders /// Opacity applied to Source Alpha /// Output color [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 SubstractFunction(Vector4 backdrop, Vector4 source, float opacity) + public static Vector4 Substract(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; - if (source.W == 0) - { - return backdrop; - } - return Compose(backdrop, source, Vector4.Max(Vector4.Zero, backdrop - source)); } @@ -105,14 +85,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders /// Opacity applied to Source Alpha /// Output color [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 ScreenFunction(Vector4 backdrop, Vector4 source, float opacity) + public static Vector4 Screen(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; - if (source.W == 0) - { - return backdrop; - } - return Compose(backdrop, source, Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source))); } @@ -124,14 +99,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders /// Opacity applied to Source Alpha /// Output color [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 DarkenFunction(Vector4 backdrop, Vector4 source, float opacity) + public static Vector4 Darken(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; - if (source.W == 0) - { - return backdrop; - } - return Compose(backdrop, source, Vector4.Min(backdrop, source)); } @@ -143,14 +113,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders /// Opacity applied to Source Alpha /// Output color [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 LightenFunction(Vector4 backdrop, Vector4 source, float opacity) + public static Vector4 Lighten(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; - if (source.W == 0) - { - return backdrop; - } - return Compose(backdrop, source, Vector4.Max(backdrop, source)); } @@ -162,14 +127,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders /// Opacity applied to Source Alpha /// Output color [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 OverlayFunction(Vector4 backdrop, Vector4 source, float opacity) + public static Vector4 Overlay(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; - if (source.W == 0) - { - return backdrop; - } - float cr = OverlayValueFunction(backdrop.X, source.X); float cg = OverlayValueFunction(backdrop.Y, source.Y); float cb = OverlayValueFunction(backdrop.Z, source.Z); @@ -185,14 +145,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders /// Opacity applied to Source Alpha /// Output color [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 HardLightFunction(Vector4 backdrop, Vector4 source, float opacity) + public static Vector4 HardLight(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; - if (source.W == 0) - { - return backdrop; - } - float cr = OverlayValueFunction(source.X, backdrop.X); float cg = OverlayValueFunction(source.Y, backdrop.Y); float cb = OverlayValueFunction(source.Z, backdrop.Z); @@ -222,8 +177,6 @@ namespace ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector4 Compose(Vector4 backdrop, Vector4 source, Vector4 xform) { - DebugGuard.MustBeGreaterThan(source.W, 0, nameof(source.W)); - // calculate weights float xw = backdrop.W * source.W; float bw = backdrop.W - xw; @@ -233,7 +186,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders float a = xw + bw + sw; // calculate final value - xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / a; + xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); xform.W = a; return xform; diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions{TPixel}.cs deleted file mode 100644 index 4e829212e8..0000000000 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions{TPixel}.cs +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.PixelFormats.PixelBlenders -{ - using System.Numerics; - using System.Runtime.CompilerServices; - - /// - /// Collection of Porter Duff alpha blending functions - /// - /// Pixel Format - /// - /// These functions are designed to be a general solution for all color cases, - /// that is, they take in account the alpha value of both the backdrop - /// and source, and there's no need to alpha-premultiply neither the backdrop - /// nor the source. - /// Note there are faster functions for when the backdrop color is known - /// to be opaque - /// - internal static class PorterDuffFunctions - where TPixel : IPixel - { - /// - /// Source over backdrop - /// - /// Backgrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel NormalBlendFunction(TPixel backdrop, TPixel source, float opacity) - { - return ToPixel(PorterDuffFunctions.NormalBlendFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); - } - - /// - /// Source multiplied by backdrop - /// - /// Backgrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel MultiplyFunction(TPixel backdrop, TPixel source, float opacity) - { - return ToPixel(PorterDuffFunctions.MultiplyFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); - } - - /// - /// Source added to backdrop - /// - /// Backgrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel AddFunction(TPixel backdrop, TPixel source, float opacity) - { - return ToPixel(PorterDuffFunctions.AddFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); - } - - /// - /// Source substracted from backdrop - /// - /// Backgrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel SubstractFunction(TPixel backdrop, TPixel source, float opacity) - { - return ToPixel(PorterDuffFunctions.SubstractFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); - } - - /// - /// Complement of source multiplied by the complement of backdrop - /// - /// Backgrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ScreenFunction(TPixel backdrop, TPixel source, float opacity) - { - return ToPixel(PorterDuffFunctions.ScreenFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); - } - - /// - /// Per element, chooses the smallest value of source and backdrop - /// - /// Backgrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel DarkenFunction(TPixel backdrop, TPixel source, float opacity) - { - return ToPixel(PorterDuffFunctions.DarkenFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); - } - - /// - /// Per element, chooses the largest value of source and backdrop - /// - /// Backgrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel LightenFunction(TPixel backdrop, TPixel source, float opacity) - { - return ToPixel(PorterDuffFunctions.LightenFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); - } - - /// - /// Overlays source over backdrop - /// - /// Backgrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel OverlayFunction(TPixel backdrop, TPixel source, float opacity) - { - return ToPixel(PorterDuffFunctions.OverlayFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); - } - - /// - /// Hard light effect - /// - /// Backgrop color - /// Source color - /// Opacity applied to Source Alpha - /// Output color - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel HardLightFunction(TPixel backdrop, TPixel source, float opacity) - { - return ToPixel(PorterDuffFunctions.HardLightFunction(backdrop.ToVector4(), source.ToVector4(), opacity)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static TPixel ToPixel(Vector4 vector) - { - TPixel p = default(TPixel); - p.PackFromVector4(vector); - return p; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs index cab357c412..5a3737dc66 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs @@ -22,25 +22,30 @@ namespace ImageSharp.PixelFormats { switch (mode) { - case PixelBlenderMode.Multiply: - return DefaultMultiplyPixelBlender.Instance; - case PixelBlenderMode.Add: - return DefaultAddPixelBlender.Instance; - case PixelBlenderMode.Substract: - return DefaultSubstractPixelBlender.Instance; - case PixelBlenderMode.Screen: - return DefaultScreenPixelBlender.Instance; - case PixelBlenderMode.Darken: - return DefaultDarkenPixelBlender.Instance; - case PixelBlenderMode.Lighten: - return DefaultLightenPixelBlender.Instance; - case PixelBlenderMode.Overlay: - return DefaultOverlayPixelBlender.Instance; - case PixelBlenderMode.HardLight: - return DefaultHardLightPixelBlender.Instance; + case PixelBlenderMode.Multiply: return DefaultPixelBlenders.Multiply.Instance; + case PixelBlenderMode.Add: return DefaultPixelBlenders.Add.Instance; + case PixelBlenderMode.Substract: return DefaultPixelBlenders.Substract.Instance; + case PixelBlenderMode.Screen: return DefaultPixelBlenders.Screen.Instance; + case PixelBlenderMode.Darken: return DefaultPixelBlenders.Darken.Instance; + case PixelBlenderMode.Lighten: return DefaultPixelBlenders.Lighten.Instance; + case PixelBlenderMode.Overlay: return DefaultPixelBlenders.Overlay.Instance; + case PixelBlenderMode.HardLight: return DefaultPixelBlenders.HardLight.Instance; + case PixelBlenderMode.Src: return DefaultPixelBlenders.Src.Instance; + case PixelBlenderMode.Atop: return DefaultPixelBlenders.Atop.Instance; + case PixelBlenderMode.Over: return DefaultPixelBlenders.Over.Instance; + case PixelBlenderMode.In: return DefaultPixelBlenders.In.Instance; + case PixelBlenderMode.Out: return DefaultPixelBlenders.Out.Instance; + case PixelBlenderMode.Dest: return DefaultPixelBlenders.Dest.Instance; + case PixelBlenderMode.DestAtop: return DefaultPixelBlenders.DestAtop.Instance; + case PixelBlenderMode.DestOver: return DefaultPixelBlenders.DestOver.Instance; + case PixelBlenderMode.DestIn: return DefaultPixelBlenders.DestIn.Instance; + case PixelBlenderMode.DestOut: return DefaultPixelBlenders.DestOut.Instance; + case PixelBlenderMode.Clear: return DefaultPixelBlenders.Clear.Instance; + case PixelBlenderMode.Xor: return DefaultPixelBlenders.Xor.Instance; + case PixelBlenderMode.Normal: default: - return DefaultNormalPixelBlender.Instance; + return DefaultPixelBlenders.Normal.Instance; } } } diff --git a/src/ImageSharp/Processing/Binarization/BinaryThreshold.cs b/src/ImageSharp/Processing/Binarization/BinaryThreshold.cs index f50616aa30..e37f80c25a 100644 --- a/src/ImageSharp/Processing/Binarization/BinaryThreshold.cs +++ b/src/ImageSharp/Processing/Binarization/BinaryThreshold.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Binarization/Dither.cs b/src/ImageSharp/Processing/Binarization/Dither.cs index 2a359c0898..efaf63b06c 100644 --- a/src/ImageSharp/Processing/Binarization/Dither.cs +++ b/src/ImageSharp/Processing/Binarization/Dither.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.Dithering; using ImageSharp.PixelFormats; using ImageSharp.Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ColorMatrix/BlackWhite.cs b/src/ImageSharp/Processing/ColorMatrix/BlackWhite.cs index de543f2cd9..6a4e3807ba 100644 --- a/src/ImageSharp/Processing/ColorMatrix/BlackWhite.cs +++ b/src/ImageSharp/Processing/ColorMatrix/BlackWhite.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ColorMatrix/ColorBlindness.cs b/src/ImageSharp/Processing/ColorMatrix/ColorBlindness.cs index c48a862930..14641afba1 100644 --- a/src/ImageSharp/Processing/ColorMatrix/ColorBlindness.cs +++ b/src/ImageSharp/Processing/ColorMatrix/ColorBlindness.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ColorMatrix/Grayscale.cs b/src/ImageSharp/Processing/ColorMatrix/Grayscale.cs index daddf106c3..635b6747a6 100644 --- a/src/ImageSharp/Processing/ColorMatrix/Grayscale.cs +++ b/src/ImageSharp/Processing/ColorMatrix/Grayscale.cs @@ -9,6 +9,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ColorMatrix/Hue.cs b/src/ImageSharp/Processing/ColorMatrix/Hue.cs index bcaf68d9a9..d218b3a104 100644 --- a/src/ImageSharp/Processing/ColorMatrix/Hue.cs +++ b/src/ImageSharp/Processing/ColorMatrix/Hue.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ColorMatrix/Kodachrome.cs b/src/ImageSharp/Processing/ColorMatrix/Kodachrome.cs index a302bb2e90..09eb131907 100644 --- a/src/ImageSharp/Processing/ColorMatrix/Kodachrome.cs +++ b/src/ImageSharp/Processing/ColorMatrix/Kodachrome.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ColorMatrix/Lomograph.cs b/src/ImageSharp/Processing/ColorMatrix/Lomograph.cs index cbfeb7d055..bca4577e48 100644 --- a/src/ImageSharp/Processing/ColorMatrix/Lomograph.cs +++ b/src/ImageSharp/Processing/ColorMatrix/Lomograph.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ColorMatrix/Polaroid.cs b/src/ImageSharp/Processing/ColorMatrix/Polaroid.cs index ac9f7391f1..b2d8515d6c 100644 --- a/src/ImageSharp/Processing/ColorMatrix/Polaroid.cs +++ b/src/ImageSharp/Processing/ColorMatrix/Polaroid.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ColorMatrix/Saturation.cs b/src/ImageSharp/Processing/ColorMatrix/Saturation.cs index ffe336c62d..88f3b15296 100644 --- a/src/ImageSharp/Processing/ColorMatrix/Saturation.cs +++ b/src/ImageSharp/Processing/ColorMatrix/Saturation.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ColorMatrix/Sepia.cs b/src/ImageSharp/Processing/ColorMatrix/Sepia.cs index 8488dcfe5a..000c0ffba8 100644 --- a/src/ImageSharp/Processing/ColorMatrix/Sepia.cs +++ b/src/ImageSharp/Processing/ColorMatrix/Sepia.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Convolution/BoxBlur.cs b/src/ImageSharp/Processing/Convolution/BoxBlur.cs index 46c134ee20..ad5e477dc9 100644 --- a/src/ImageSharp/Processing/Convolution/BoxBlur.cs +++ b/src/ImageSharp/Processing/Convolution/BoxBlur.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Convolution/DetectEdges.cs b/src/ImageSharp/Processing/Convolution/DetectEdges.cs index 368688f624..1cc8b693ff 100644 --- a/src/ImageSharp/Processing/Convolution/DetectEdges.cs +++ b/src/ImageSharp/Processing/Convolution/DetectEdges.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Convolution/GaussianBlur.cs b/src/ImageSharp/Processing/Convolution/GaussianBlur.cs index 0b8c5383c8..f9658fcb5d 100644 --- a/src/ImageSharp/Processing/Convolution/GaussianBlur.cs +++ b/src/ImageSharp/Processing/Convolution/GaussianBlur.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Convolution/GaussianSharpen.cs b/src/ImageSharp/Processing/Convolution/GaussianSharpen.cs index 1a5d3c2df5..bb616cc67e 100644 --- a/src/ImageSharp/Processing/Convolution/GaussianSharpen.cs +++ b/src/ImageSharp/Processing/Convolution/GaussianSharpen.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Effects/Alpha.cs b/src/ImageSharp/Processing/Effects/Alpha.cs index 73b682b93b..a0d218651a 100644 --- a/src/ImageSharp/Processing/Effects/Alpha.cs +++ b/src/ImageSharp/Processing/Effects/Alpha.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Effects/BackgroundColor.cs b/src/ImageSharp/Processing/Effects/BackgroundColor.cs index 975d2c24b2..a1e04c8a3d 100644 --- a/src/ImageSharp/Processing/Effects/BackgroundColor.cs +++ b/src/ImageSharp/Processing/Effects/BackgroundColor.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Effects/Brightness.cs b/src/ImageSharp/Processing/Effects/Brightness.cs index a28df82c09..165f897b80 100644 --- a/src/ImageSharp/Processing/Effects/Brightness.cs +++ b/src/ImageSharp/Processing/Effects/Brightness.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Effects/Contrast.cs b/src/ImageSharp/Processing/Effects/Contrast.cs index 8f226d08e2..0a55fd067b 100644 --- a/src/ImageSharp/Processing/Effects/Contrast.cs +++ b/src/ImageSharp/Processing/Effects/Contrast.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Effects/Invert.cs b/src/ImageSharp/Processing/Effects/Invert.cs index fe3bb7dc98..d9a0695566 100644 --- a/src/ImageSharp/Processing/Effects/Invert.cs +++ b/src/ImageSharp/Processing/Effects/Invert.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Effects/OilPainting.cs b/src/ImageSharp/Processing/Effects/OilPainting.cs index fd65542e04..3b300e9197 100644 --- a/src/ImageSharp/Processing/Effects/OilPainting.cs +++ b/src/ImageSharp/Processing/Effects/OilPainting.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Effects/Pixelate.cs b/src/ImageSharp/Processing/Effects/Pixelate.cs index eeffff0925..07fdd50a35 100644 --- a/src/ImageSharp/Processing/Effects/Pixelate.cs +++ b/src/ImageSharp/Processing/Effects/Pixelate.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/ImageProcessor.cs b/src/ImageSharp/Processing/ImageProcessor.cs index d42650e56f..dd2a93bc52 100644 --- a/src/ImageSharp/Processing/ImageProcessor.cs +++ b/src/ImageSharp/Processing/ImageProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing using System.Threading.Tasks; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Allows the application of processors to images. diff --git a/src/ImageSharp/Processing/Overlays/Glow.cs b/src/ImageSharp/Processing/Overlays/Glow.cs index 04c85e00c7..84f6bf10ae 100644 --- a/src/ImageSharp/Processing/Overlays/Glow.cs +++ b/src/ImageSharp/Processing/Overlays/Glow.cs @@ -8,6 +8,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Overlays/Vignette.cs b/src/ImageSharp/Processing/Overlays/Vignette.cs index c04e887182..75c4611a1e 100644 --- a/src/ImageSharp/Processing/Overlays/Vignette.cs +++ b/src/ImageSharp/Processing/Overlays/Vignette.cs @@ -8,6 +8,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index a2fa1ddf39..ea1b759ab5 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An to perform binary threshold filtering against an diff --git a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs index 47811f0ec2..85522e2886 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Dithering; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An that dithers an image using error diffusion. diff --git a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs index 8983897778..a190bcd61b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Dithering; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An that dithers an image using error diffusion. diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs index 49af2667d4..1bac145bc9 100644 --- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// The color matrix filter. Inherit from this class to perform operation involving color matrices. diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs index f6480c1837..bb33e51513 100644 --- a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using System.Numerics; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Converts the colors of the image recreating an old Lomograph effect. diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs index 5df034add2..9e54574df9 100644 --- a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using System.Numerics; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Converts the colors of the image recreating an old Polaroid effect. diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index b97e070791..0a2162fb05 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Applies a Box blur sampler to the image. diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index b6b56adb3a..708b6c6fd8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Defines a sampler that uses two one-dimensional matrices to perform convolution against an image. diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index efc00b08fd..ceb985b0b7 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Defines a sampler that uses two one-dimensional matrices to perform two-pass convolution against an image. diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index 06607c87a2..cd2eb27004 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Defines a sampler that uses a 2 dimensional matrix to perform convolution against an image. diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs index 6f1057e007..ab0b459076 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Defines a sampler that detects edges within an image using two one-dimensional matrices. diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs index a03d126775..367c288fca 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Defines a sampler that detects edges within an image using a eight two dimensional matrices. diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs index 415b574b8a..1400b6317a 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Defines a sampler that detects edges within an image using a single two dimensional matrix. diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs index 4cd49e149e..ef6ddaa6a7 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Applies a Gaussian blur sampler to the image. diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs index 5bb29a67e2..594dda8cab 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Applies a Gaussian sharpening sampler to the image. diff --git a/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs index a3894f8d34..0efca43b26 100644 --- a/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An to change the alpha component of an . diff --git a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs index 153719191e..96fcf4d630 100644 --- a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Sets the background color of the image. diff --git a/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs index 121d25d1e0..3fbe1742ed 100644 --- a/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An to change the brightness of an . diff --git a/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs index 1daead6e50..e40f8d5de5 100644 --- a/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An to change the contrast of an . diff --git a/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs index dc0b134421..07a57db54a 100644 --- a/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An to invert the colors of an . diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index 37cc8a9d9c..f484c8eec8 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An to apply an oil painting effect to an . diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs index ba6bb5c9d8..ff83117c5f 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An to pixelate the colors of an . diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 4e4a36a380..8a13eabca8 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An that applies a radial glow effect an . diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 23ba5afe0f..8cb58739b0 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// An that applies a radial vignette effect to an . diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index ade5fa8308..37f8867755 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides methods to allow the cropping of an image. diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs index 571c40939e..16f74f218b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs @@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors using System; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides methods to allow the cropping of an image to preserve areas of highest diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs index d4303c455e..cba60f928e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides methods that allow the flipping of an image around its center point. diff --git a/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs b/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs index 4cc03d864b..d1a35659b3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs @@ -8,6 +8,7 @@ namespace ImageSharp.Processing.Processors using System.Numerics; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides methods to transform an image using a . diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs index 7245b961f8..0186a8fa8e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs @@ -9,6 +9,7 @@ namespace ImageSharp.Processing.Processors using System.Runtime.CompilerServices; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides methods that allow the resizing of images using various algorithms. diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 68ff1397df..be1680cf1c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Processing.Processors using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides methods that allow the resizing of images using various algorithms. diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 15d7ca641a..e6b1d180f1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides methods that allow the rotating of images. diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs index 264cf4a531..9766caa696 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Processing.Processors using System.Threading.Tasks; using ImageSharp.Memory; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides methods that allow the skewing of images. diff --git a/src/ImageSharp/Processing/Transforms/Crop.cs b/src/ImageSharp/Processing/Transforms/Crop.cs index 1cdef56c48..94e9ba1f49 100644 --- a/src/ImageSharp/Processing/Transforms/Crop.cs +++ b/src/ImageSharp/Processing/Transforms/Crop.cs @@ -10,6 +10,7 @@ namespace ImageSharp using ImageSharp.PixelFormats; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs b/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs index 712efec121..7eae89eac0 100644 --- a/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs +++ b/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs @@ -8,6 +8,7 @@ namespace ImageSharp.Processing using System.Linq; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Provides methods to help calculate the target rectangle when resizing using the diff --git a/src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs b/src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs index 3c67cb9501..2ca2b1c39d 100644 --- a/src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs +++ b/src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs @@ -7,6 +7,7 @@ namespace ImageSharp.Processing { using System.Collections.Generic; using System.Linq; + using SixLabors.Primitives; /// /// The resize options for resizing images against certain modes. diff --git a/src/ImageSharp/Processing/Transforms/Pad.cs b/src/ImageSharp/Processing/Transforms/Pad.cs index 4bded07724..8138fd7654 100644 --- a/src/ImageSharp/Processing/Transforms/Pad.cs +++ b/src/ImageSharp/Processing/Transforms/Pad.cs @@ -11,6 +11,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/src/ImageSharp/Processing/Transforms/Resize.cs b/src/ImageSharp/Processing/Transforms/Resize.cs index 3399ff0e37..e00faf10ea 100644 --- a/src/ImageSharp/Processing/Transforms/Resize.cs +++ b/src/ImageSharp/Processing/Transforms/Resize.cs @@ -9,6 +9,7 @@ namespace ImageSharp using ImageSharp.Processing; using Processing.Processors; + using SixLabors.Primitives; /// /// Extension methods for the type. diff --git a/tests/ImageSharp.Benchmarks/BenchmarkBase.cs b/tests/ImageSharp.Benchmarks/BenchmarkBase.cs index b1aadac0ab..41574d109f 100644 --- a/tests/ImageSharp.Benchmarks/BenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/BenchmarkBase.cs @@ -13,11 +13,6 @@ protected BenchmarkBase() { // Add Image Formats - Configuration.Default.AddImageFormat(new JpegFormat()); - Configuration.Default.AddImageFormat(new PngFormat()); - Configuration.Default.AddImageFormat(new BmpFormat()); - Configuration.Default.AddImageFormat(new GifFormat()); - Configuration.Default.AddImageFormat(new TiffFormat()); } } } diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs index 183782d915..66104944ea 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs @@ -50,7 +50,7 @@ namespace ImageSharp.Benchmarks image.DrawBeziers( Rgba32.HotPink, 10, - new[] { + new SixLabors.Primitives.PointF[] { new Vector2(10, 500), new Vector2(30, 10), new Vector2(240, 30), diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs index 5ecdec2c29..a6af5a9769 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs @@ -48,7 +48,7 @@ namespace ImageSharp.Benchmarks image.DrawLines( Rgba32.HotPink, 10, - new[] { + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(550, 50), new Vector2(200, 400) diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs index d3ff33956e..3abd3b889d 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs @@ -50,7 +50,7 @@ namespace ImageSharp.Benchmarks image.DrawPolygon( Rgba32.HotPink, 10, - new[] { + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(550, 50), new Vector2(200, 400) diff --git a/tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs b/tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs index deba595545..b7d1b96b74 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs @@ -57,7 +57,7 @@ namespace ImageSharp.Benchmarks { image.FillPolygon( Rgba32.HotPink, - new[] { + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(550, 50), new Vector2(200, 400) diff --git a/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs b/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs index a90a7a4c01..0738812a1c 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs @@ -9,8 +9,8 @@ namespace ImageSharp.Benchmarks using System.Drawing.Drawing2D; using BenchmarkDotNet.Attributes; - using CoreRectangle = ImageSharp.Rectangle; - using CoreSize = ImageSharp.Size; + using CoreRectangle = SixLabors.Primitives.Rectangle; + using CoreSize = SixLabors.Primitives.Size; using System.Numerics; @@ -52,7 +52,7 @@ namespace ImageSharp.Benchmarks { image.FillPolygon( Rgba32.HotPink, - new[] { + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 10), new Vector2(200, 150), diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs b/tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs index 3c327bd562..6f3a38b7fd 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs +++ b/tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Benchmarks.Image using CoreImage = ImageSharp.Image; - using CoreSize = ImageSharp.Size; + using CoreSize = SixLabors.Primitives.Size; public class DecodeBmp : BenchmarkBase { diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs b/tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs index 8f79386a67..ae1add172d 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs +++ b/tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs @@ -10,6 +10,7 @@ namespace ImageSharp.Benchmarks.Image using BenchmarkDotNet.Attributes; using ImageSharp; + using SixLabors.Primitives; using CoreImage = ImageSharp.Image; public class DecodeFilteredPng : BenchmarkBase @@ -30,11 +31,11 @@ namespace ImageSharp.Benchmarks.Image this.filter4 = new MemoryStream(File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Png/filter4.png")); } - private Size LoadPng(MemoryStream stream) + private SixLabors.Primitives.Size LoadPng(MemoryStream stream) { using (Image image = CoreImage.Load(stream)) { - return new Size(image.Width, image.Height); + return new SixLabors.Primitives.Size(image.Width, image.Height); } } diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeGif.cs b/tests/ImageSharp.Benchmarks/Image/DecodeGif.cs index b1e56c6bd2..3f908d3622 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Image/DecodeGif.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Benchmarks.Image using CoreImage = ImageSharp.Image; - using CoreSize = ImageSharp.Size; + using CoreSize = SixLabors.Primitives.Size; public class DecodeGif : BenchmarkBase { diff --git a/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs index 455af48ad2..ece93f912e 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Image/DecodeJpeg.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Benchmarks.Image using CoreImage = ImageSharp.Image; - using CoreSize = ImageSharp.Size; + using CoreSize = SixLabors.Primitives.Size; public class DecodeJpeg : BenchmarkBase { diff --git a/tests/ImageSharp.Benchmarks/Image/DecodePng.cs b/tests/ImageSharp.Benchmarks/Image/DecodePng.cs index dd26a2cf73..be1633c044 100644 --- a/tests/ImageSharp.Benchmarks/Image/DecodePng.cs +++ b/tests/ImageSharp.Benchmarks/Image/DecodePng.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Benchmarks.Image using CoreImage = ImageSharp.Image; - using CoreSize = ImageSharp.Size; + using CoreSize = SixLabors.Primitives.Size; public class DecodePng : BenchmarkBase { diff --git a/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs index 88e82f0796..02e3211a76 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs +++ b/tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs @@ -53,9 +53,9 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions() { Quantizer = new OctreeQuantizer(), Quality = 256 }; + PngEncoder encoder = new PngEncoder() { Quantizer = new OctreeQuantizer(), PaletteSize = 256 }; - this.bmpCore.SaveAsPng(memoryStream, options); + this.bmpCore.SaveAsPng(memoryStream, encoder); } } @@ -64,7 +64,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions { Quantizer = new OctreeQuantizer { Dither = false }, Quality = 256 }; + PngEncoder options = new PngEncoder { Quantizer = new OctreeQuantizer { Dither = false }, PaletteSize = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } @@ -75,7 +75,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions { Quantizer = new PaletteQuantizer(), Quality = 256 }; + PngEncoder options = new PngEncoder { Quantizer = new PaletteQuantizer(), PaletteSize = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } @@ -86,7 +86,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions { Quantizer = new PaletteQuantizer { Dither = false }, Quality = 256 }; + PngEncoder options = new PngEncoder { Quantizer = new PaletteQuantizer { Dither = false }, PaletteSize = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } @@ -97,7 +97,7 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - PngEncoderOptions options = new PngEncoderOptions() { Quantizer = new WuQuantizer(), Quality = 256 }; + PngEncoder options = new PngEncoder() { Quantizer = new WuQuantizer(), PaletteSize = 256 }; this.bmpCore.SaveAsPng(memoryStream, options); } diff --git a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs b/tests/ImageSharp.Benchmarks/Image/EncodePng.cs index 3ec83aa7cf..81bb235eea 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs +++ b/tests/ImageSharp.Benchmarks/Image/EncodePng.cs @@ -71,7 +71,7 @@ namespace ImageSharp.Benchmarks.Image new OctreeQuantizer() : new PaletteQuantizer(); - PngEncoderOptions options = new PngEncoderOptions() { Quantizer = quantizer }; + PngEncoder options = new PngEncoder() { Quantizer = quantizer }; this.bmpCore.SaveAsPng(memoryStream, options); } } diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 1da69f1a8f..19904a5ad2 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -9,7 +9,7 @@ namespace ImageSharp.Benchmarks using BenchmarkDotNet.Attributes; using ImageSharp.PixelFormats; - using CoreSize = ImageSharp.Size; + using CoreSize = SixLabors.Primitives.Size; using System.Numerics; using ImageSharp.Memory; @@ -35,7 +35,7 @@ namespace ImageSharp.Benchmarks for (int i = 0; i < destination.Length; i++) { - destinationSpan[i] = PorterDuffFunctions.NormalBlendFunction(backgroundSpan[i], sourceSpan[i], amount[i]); + destinationSpan[i] = PorterDuffFunctions.Normal(backgroundSpan[i], sourceSpan[i], amount[i]); } PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); @@ -50,7 +50,7 @@ namespace ImageSharp.Benchmarks for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalBlendFunction(destination[i], source[i], amount[i]); + destination[i] = PorterDuffFunctions.Normal(destination[i], source[i], amount[i]); } } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Crop.cs b/tests/ImageSharp.Benchmarks/Samplers/Crop.cs index 9fa9794637..cb13378a13 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Crop.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Crop.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Benchmarks using ImageSharp.PixelFormats; - using CoreSize = ImageSharp.Size; + using CoreSize = SixLabors.Primitives.Size; public class Crop : BenchmarkBase { diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index 049a00c1ca..2aa8df96ca 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -9,13 +9,14 @@ namespace ImageSharp.Benchmarks using BenchmarkDotNet.Attributes; using ImageSharp.PixelFormats; using ImageSharp.Processing.Processors; - using CoreSize = ImageSharp.Size; + using CoreSize = SixLabors.Primitives.Size; using ImageSharp.Processing; using System.Numerics; using System; using System.Threading.Tasks; using ImageSharp.Memory; + using SixLabors.Primitives; public class Glow : BenchmarkBase { diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index d96be70f74..3873400698 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Benchmarks using ImageSharp.PixelFormats; - using CoreSize = ImageSharp.Size; + using CoreSize = SixLabors.Primitives.Size; public class Resize : BenchmarkBase { diff --git a/tests/ImageSharp.Sandbox46/Tests/PixelFormats/PixelBlenderTests.cs b/tests/ImageSharp.Sandbox46/Tests/PixelFormats/PixelBlenderTests.cs deleted file mode 100644 index 7efd3a6fcb..0000000000 --- a/tests/ImageSharp.Sandbox46/Tests/PixelFormats/PixelBlenderTests.cs +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Tests.PixelFormats -{ - using System; - using System.Collections.Generic; - using System.Text; - using ImageSharp.PixelFormats; - using ImageSharp.PixelFormats.PixelBlenders; - using ImageSharp.Tests.TestUtilities; - using Xunit; - - public class PixelOperations - { - public static TheoryData BlenderMappings = new TheoryData() - { - { new TestPixel(), typeof(DefaultNormalPixelBlender), PixelBlenderMode.Normal }, - { new TestPixel(), typeof(DefaultScreenPixelBlender), PixelBlenderMode.Screen }, - { new TestPixel(), typeof(DefaultHardLightPixelBlender), PixelBlenderMode.HardLight }, - { new TestPixel(), typeof(DefaultOverlayPixelBlender), PixelBlenderMode.Overlay }, - { new TestPixel(), typeof(DefaultDarkenPixelBlender), PixelBlenderMode.Darken }, - { new TestPixel(), typeof(DefaultLightenPixelBlender), PixelBlenderMode.Lighten }, - { new TestPixel(), typeof(DefaultAddPixelBlender), PixelBlenderMode.Add }, - { new TestPixel(), typeof(DefaultSubstractPixelBlender), PixelBlenderMode.Substract }, - { new TestPixel(), typeof(DefaultMultiplyPixelBlender), PixelBlenderMode.Multiply }, - - { new TestPixel(), typeof(DefaultNormalPixelBlender), PixelBlenderMode.Normal }, - { new TestPixel(), typeof(DefaultScreenPixelBlender), PixelBlenderMode.Screen }, - { new TestPixel(), typeof(DefaultHardLightPixelBlender), PixelBlenderMode.HardLight }, - { new TestPixel(), typeof(DefaultOverlayPixelBlender), PixelBlenderMode.Overlay }, - { new TestPixel(), typeof(DefaultDarkenPixelBlender), PixelBlenderMode.Darken }, - { new TestPixel(), typeof(DefaultLightenPixelBlender), PixelBlenderMode.Lighten }, - { new TestPixel(), typeof(DefaultAddPixelBlender), PixelBlenderMode.Add }, - { new TestPixel(), typeof(DefaultSubstractPixelBlender), PixelBlenderMode.Substract }, - { new TestPixel(), typeof(DefaultMultiplyPixelBlender), PixelBlenderMode.Multiply }, - }; - - [Theory] - [MemberData(nameof(BlenderMappings))] - public void ReturnsCorrectBlender(TestPixel pixel, Type type, PixelBlenderMode mode) - where TPixel : struct, IPixel - { - PixelBlender blender = PixelOperations.Instance.GetPixelBlender(mode); - Assert.IsType(type, blender); - } - } -} diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index aa3c4edfc1..417588180a 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -13,7 +13,7 @@ namespace ImageSharp.Tests using ImageSharp.Formats; using ImageSharp.IO; using ImageSharp.PixelFormats; - + using Moq; using Xunit; /// @@ -21,22 +21,27 @@ namespace ImageSharp.Tests /// public class ConfigurationTests { + public Configuration ConfigurationEmpty { get; private set; } + public Configuration DefaultConfiguration { get; private set; } + + public ConfigurationTests() + { + this.DefaultConfiguration = Configuration.CreateDefaultInstance(); + this.ConfigurationEmpty = new Configuration(); + } + [Fact] public void DefaultsToLocalFileSystem() { - var configuration = Configuration.CreateDefaultInstance(); - - ImageSharp.IO.IFileSystem fs = configuration.FileSystem; - - Assert.IsType(fs); + Assert.IsType(DefaultConfiguration.FileSystem); + Assert.IsType(ConfigurationEmpty.FileSystem); } [Fact] public void IfAutoloadWellknwonFormatesIsTrueAllFormateAreLoaded() { - var configuration = Configuration.CreateDefaultInstance(); - - Assert.Equal(4, configuration.ImageFormats.Count); + Assert.Equal(4, DefaultConfiguration.ImageEncoders.Count()); + Assert.Equal(4, DefaultConfiguration.ImageDecoders.Count()); } /// @@ -67,243 +72,97 @@ namespace ImageSharp.Tests Assert.True(Configuration.Default.ParallelOptions.MaxDegreeOfParallelism == Environment.ProcessorCount); } - /// - /// Test that the default configuration parallel options is not null. - /// [Fact] - public void TestDefultConfigurationImageFormatsIsNotNull() - { - Assert.True(Configuration.Default.ImageFormats != null); - } - - /// - /// Tests the method throws an exception - /// when the format is null. - /// - [Fact] - public void TestAddImageFormatThrowsWithNullFormat() + public void AddImageFormatDetectorNullthrows() { Assert.Throws(() => { - Configuration.Default.AddImageFormat(null); + DefaultConfiguration.AddImageFormatDetector(null); }); } - /// - /// Tests the method throws an exception - /// when the encoder is null. - /// [Fact] - public void TestAddImageFormatThrowsWithNullEncoder() + public void RegisterNullMimeTypeEncoder() { - var format = new TestFormat { Encoder = null }; - Assert.Throws(() => { - Configuration.Default.AddImageFormat(format); + DefaultConfiguration.SetEncoder(null, new Mock().Object); }); - } - - /// - /// Tests the method throws an exception - /// when the decoder is null. - /// - [Fact] - public void TestAddImageFormatThrowsWithNullDecoder() - { - var format = new TestFormat { Decoder = null }; - Assert.Throws(() => { - Configuration.Default.AddImageFormat(format); + DefaultConfiguration.SetEncoder(ImageFormats.Bitmap, null); }); - } - - /// - /// Tests the method throws an exception - /// when the mime type is null or an empty string. - /// - [Fact] - public void TestAddImageFormatThrowsWithNullOrEmptyMimeType() - { - var format = new TestFormat { MimeType = null }; - Assert.Throws(() => { - Configuration.Default.AddImageFormat(format); - }); - - format = new TestFormat { MimeType = string.Empty }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); + DefaultConfiguration.SetEncoder(null, null); }); } - /// - /// Tests the method throws an exception - /// when the extension is null or an empty string. - /// [Fact] - public void TestAddImageFormatThrowsWithNullOrEmptyExtension() + public void RegisterNullSetDecoder() { - var format = new TestFormat { Extension = null }; - Assert.Throws(() => { - Configuration.Default.AddImageFormat(format); - }); - - format = new TestFormat { Extension = string.Empty }; - - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); + DefaultConfiguration.SetDecoder(null, new Mock().Object); }); - } - - /// - /// Tests the method throws an exception - /// when the supported extensions list is null or empty. - /// - [Fact] - public void TestAddImageFormatThrowsWenSupportedExtensionsIsNullOrEmpty() - { - var format = new TestFormat { SupportedExtensions = null }; - Assert.Throws(() => { - Configuration.Default.AddImageFormat(format); + DefaultConfiguration.SetDecoder(ImageFormats.Bitmap, null); }); - - format = new TestFormat { SupportedExtensions = Enumerable.Empty() }; - - Assert.Throws(() => + Assert.Throws(() => { - Configuration.Default.AddImageFormat(format); + DefaultConfiguration.SetDecoder(null, null); }); } - /// - /// Tests the method throws an exception - /// when the supported extensions list does not contain the default extension. - /// [Fact] - public void TestAddImageFormatThrowsWithoutDefaultExtension() + public void RegisterMimeTypeEncoderReplacesLast() { - var format = new TestFormat { Extension = "test" }; + var encoder1 = new Mock().Object; + ConfigurationEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder1); + var found = ConfigurationEmpty.FindEncoder(TestFormat.GlobalTestFormat); + Assert.Equal(encoder1, found); - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); + var encoder2 = new Mock().Object; + ConfigurationEmpty.SetEncoder(TestFormat.GlobalTestFormat, encoder2); + var found2 = ConfigurationEmpty.FindEncoder(TestFormat.GlobalTestFormat); + Assert.Equal(encoder2, found2); + Assert.NotEqual(found, found2); } - /// - /// Tests the method throws an exception - /// when the supported extensions list contains an empty string. - /// [Fact] - public void TestAddImageFormatThrowsWithEmptySupportedExtension() + public void RegisterMimeTypeDecoderReplacesLast() { - var format = new TestFormat - { - Extension = "test", - SupportedExtensions = new[] { "test", string.Empty } - }; + var decoder1 = new Mock().Object; + ConfigurationEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder1); + var found = ConfigurationEmpty.FindDecoder(TestFormat.GlobalTestFormat); + Assert.Equal(decoder1, found); - Assert.Throws(() => - { - Configuration.Default.AddImageFormat(format); - }); + var decoder2 = new Mock().Object; + ConfigurationEmpty.SetDecoder(TestFormat.GlobalTestFormat, decoder2); + var found2 = ConfigurationEmpty.FindDecoder(TestFormat.GlobalTestFormat); + Assert.Equal(decoder2, found2); + Assert.NotEqual(found, found2); } - /// - /// Test that the method ignores adding duplicate image formats. - /// - [Fact] - public void TestConfigurationIgnoresDuplicateImageFormats() - { - Configuration.Default.AddImageFormat(new PngFormat()); - Configuration.Default.AddImageFormat(new PngFormat()); - - Assert.True(Configuration.Default.ImageFormats.Count(i => i.GetType() == typeof(PngFormat)) == 1); - } - /// - /// Test that the default image constructors use default configuration. - /// [Fact] - public void TestImageUsesDefaultConfiguration() + public void ConstructorCallConfigureOnFormatProvider() { - Configuration.Default.AddImageFormat(new PngFormat()); + var provider = new Mock(); + var config = new Configuration(provider.Object); - var image = new Image(1, 1); - Assert.Equal(image.Configuration.ParallelOptions, Configuration.Default.ParallelOptions); - Assert.Equal(image.Configuration.ImageFormats, Configuration.Default.ImageFormats); + provider.Verify(x => x.Configure(config)); } - /// - /// Test that the default image constructor copies the configuration. - /// [Fact] - public void TestImageCopiesConfiguration() - { - Configuration.Default.AddImageFormat(new PngFormat()); - - var image = new Image(1, 1); - var image2 = new Image(image); - Assert.Equal(image2.Configuration.ParallelOptions, image.Configuration.ParallelOptions); - Assert.True(image2.Configuration.ImageFormats.SequenceEqual(image.Configuration.ImageFormats)); - } - - /// - /// A test image format for testing the configuration. - /// - private class TestFormat : IImageFormat + public void AddFormatCallsConfig() { - /// - /// Initializes a new instance of the class. - /// - public TestFormat() - { - this.Decoder = new JpegDecoder(); - this.Encoder = new JpegEncoder(); - this.Extension = "jpg"; - this.MimeType = "image/test"; - this.SupportedExtensions = new[] { "jpg" }; - } - - /// - public IImageDecoder Decoder { get; set; } - - /// - public IImageEncoder Encoder { get; set; } - - /// - public string MimeType { get; set; } + var provider = new Mock(); + var config = new Configuration(); + config.Configure(provider.Object); - /// - public string Extension { get; set; } - - /// - public IEnumerable SupportedExtensions { get; set; } - - /// - public int HeaderSize - { - get - { - throw new NotImplementedException(); - } - } - - /// - public bool IsSupportedFileFormat(byte[] header) - { - throw new NotImplementedException(); - } + provider.Verify(x => x.Configure(config)); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs index 3d49a70b81..7ddc2de5a4 100644 --- a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs +++ b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs @@ -24,18 +24,15 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "BezierLine"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image.BackgroundColor(Rgba32.Blue) - .DrawBeziers(Rgba32.HotPink, 5, - new[] { + image.BackgroundColor(Rgba32.Blue) + .DrawBeziers(Rgba32.HotPink, 5, + new SixLabors.Primitives.PointF[] { new Vector2(10, 400), new Vector2(30, 10), new Vector2(240, 30), new Vector2(300, 400) - }) - .Save(output); - } + }) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -66,19 +63,16 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image.BackgroundColor(Rgba32.Blue) - .DrawBeziers(color, - 10, - new[] { + image.BackgroundColor(Rgba32.Blue) + .DrawBeziers(color, + 10, + new SixLabors.Primitives.PointF[]{ new Vector2(10, 400), new Vector2(30, 10), new Vector2(240, 30), new Vector2(300, 400) - }) - .Save(output); - } + }) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/BlendedShapes.cs b/tests/ImageSharp.Tests/Drawing/BlendedShapes.cs index 23f0569e75..40a1cb3d3c 100644 --- a/tests/ImageSharp.Tests/Drawing/BlendedShapes.cs +++ b/tests/ImageSharp.Tests/Drawing/BlendedShapes.cs @@ -11,6 +11,7 @@ namespace ImageSharp.Tests.Drawing using System.Text; using ImageSharp.PixelFormats; using Xunit; + using SixLabors.Primitives; public class BlendedShapes { @@ -18,14 +19,16 @@ namespace ImageSharp.Tests.Drawing .Select(x=> new object[] { x }); [Theory] - [WithBlankImages(nameof(modes), 100, 100, PixelTypes.Rgba32)] + [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] public void DrawBlendedValues(TestImageProvider provider, PixelBlenderMode mode) where TPixel : struct, IPixel { using (var img = provider.GetImage()) { - img.Fill(NamedColors.DarkBlue, new Rectangle(0, 40, 100, 20)); - img.Fill(NamedColors.HotPink, new Rectangle(40, 0, 20, 100), new ImageSharp.GraphicsOptions(true) + var scaleX = (img.Width / 100); + var scaleY = (img.Height / 100); + img.Fill(NamedColors.DarkBlue, new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY)); + img.Fill(NamedColors.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY), new ImageSharp.GraphicsOptions(true) { BlenderMode = mode }); @@ -34,18 +37,72 @@ namespace ImageSharp.Tests.Drawing } [Theory] - [WithBlankImages(nameof(modes), 100, 100, PixelTypes.Rgba32)] + [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] public void DrawBlendedValues_transparent(TestImageProvider provider, PixelBlenderMode mode) where TPixel : struct, IPixel { using (var img = provider.GetImage()) { - img.Fill(NamedColors.DarkBlue, new Rectangle(0, 40, 100, 20)); - img.Fill(NamedColors.HotPink, new Rectangle(20, 0, 40, 100), new ImageSharp.GraphicsOptions(true) + var scaleX = (img.Width / 100); + var scaleY = (img.Height / 100); + img.Fill(NamedColors.DarkBlue, new Rectangle(0* scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY)); + img.Fill(NamedColors.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY), new ImageSharp.GraphicsOptions(true) { BlenderMode = mode }); - img.Fill(NamedColors.Transparent, new Rectangle(40, 0, 20, 100), new ImageSharp.GraphicsOptions(true) + img.Fill(NamedColors.Transparent, new SixLabors.Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY), new ImageSharp.GraphicsOptions(true) + { + BlenderMode = mode + }); + img.DebugSave(provider, new { mode }); + } + } + + [Theory] + [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] + public void DrawBlendedValues_transparent50Percent(TestImageProvider provider, PixelBlenderMode mode) + where TPixel : struct, IPixel + { + using (var img = provider.GetImage()) + { + var scaleX = (img.Width / 100); + var scaleY = (img.Height / 100); + img.Fill(NamedColors.DarkBlue, new Rectangle(0 * scaleX, 40, 100 * scaleX, 20* scaleY)); + img.Fill(NamedColors.HotPink, new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY), new ImageSharp.GraphicsOptions(true) + { + BlenderMode = mode + }); + var c = NamedColors.Red.ToVector4(); + c.W *= 0.5f; + TPixel pixel = default(TPixel); + pixel.PackFromVector4(c); + + img.Fill(pixel, new SixLabors.Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY), new ImageSharp.GraphicsOptions(true) + { + BlenderMode = mode + }); + img.DebugSave(provider, new { mode }); + } + } + + + + [Theory] + [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] + public void DrawBlendedValues_doldidEllips(TestImageProvider provider, PixelBlenderMode mode) + where TPixel : struct, IPixel + { + using (var img = provider.GetImage()) + { + var scaleX = (img.Width / 100); + var scaleY = (img.Height / 100); + img.Fill(NamedColors.DarkBlue, new Rectangle(0 * scaleX, 40* scaleY, 100 * scaleX, 20 * scaleY)); + //img.Fill(NamedColors.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY), new ImageSharp.GraphicsOptions(true) + //{ + // BlenderMode = mode + //}); + + img.Fill(NamedColors.Black, new SixLabors.Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY), new ImageSharp.GraphicsOptions(true) { BlenderMode = mode }); diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 42353a2aab..728ed749a2 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -8,6 +8,7 @@ namespace ImageSharp.Tests using System.IO; using System.Linq; using ImageSharp.PixelFormats; + using SixLabors.Primitives; using Xunit; public class DrawImageTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs index 4ba4a3a835..da5028f04f 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawPathTests.cs @@ -27,20 +27,17 @@ namespace ImageSharp.Tests.Drawing new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300)); - BezierLineSegment bazierSegment = new BezierLineSegment(new Vector2(50, 300), + CubicBezierLineSegment bazierSegment = new CubicBezierLineSegment(new Vector2(50, 300), new Vector2(500, 500), new Vector2(60, 10), new Vector2(10, 400)); ShapePath p = new ShapePath(linerSegemnt, bazierSegment); - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Rgba32.HotPink, 5, p) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Rgba32.HotPink, 5, p) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -68,7 +65,7 @@ namespace ImageSharp.Tests.Drawing new Vector2(50, 300) ); - BezierLineSegment bazierSegment = new BezierLineSegment(new Vector2(50, 300), + CubicBezierLineSegment bazierSegment = new CubicBezierLineSegment(new Vector2(50, 300), new Vector2(500, 500), new Vector2(60, 10), new Vector2(10, 400)); @@ -77,13 +74,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(color, 10, p) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(color, 10, p) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); @@ -112,14 +106,11 @@ namespace ImageSharp.Tests.Drawing for (int i = 0; i < 300; i += 20) { - image.DrawLines(pen, new Vector2[] { new Vector2(100, 2), new Vector2(-10, i) }); + image.DrawLines(pen, new SixLabors.Primitives.PointF[] { new Vector2(100, 2), new Vector2(-10, i) }); } - using (FileStream output = File.OpenWrite($"{path}/ClippedLines.png")) - { - image - .Save(output); - } + image + .Save($"{path}/ClippedLines.png"); using (PixelAccessor sourcePixels = image.Lock()) { Assert.Equal(Rgba32.White, sourcePixels[0, 90]); diff --git a/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs b/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs index 7bacebe42e..bbabdf0ea6 100644 --- a/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs @@ -25,10 +25,7 @@ namespace ImageSharp.Tests.Drawing .Fill(background) .Fill(brush); - using (FileStream output = File.OpenWrite($"{path}/{name}.png")) - { - image.Save(output); - } + image.Save($"{path}/{name}.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -54,10 +51,7 @@ namespace ImageSharp.Tests.Drawing } } } - using (FileStream output = File.OpenWrite($"{path}/{name}x4.png")) - { - image.Resize(80, 80).Save(output); - } + image.Resize(80, 80).Save($"{path}/{name}x4.png"); } } diff --git a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs index 58e55c1245..b04a413857 100644 --- a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs @@ -23,7 +23,7 @@ namespace ImageSharp.Tests.Drawing [InlineData(false, 16, 4)] // we always do 4 sub=pixels when antialising is off. public void MinimumAntialiasSubpixelDepth(bool antialias, int antialiasSubpixelDepth, int expectedAntialiasSubpixelDepth) { - ImageSharp.Rectangle bounds = new ImageSharp.Rectangle(0, 0, 1, 1); + SixLabors.Primitives.Rectangle bounds = new SixLabors.Primitives.Rectangle(0, 0, 1, 1); Mock> brush = new Mock>(); Mock region = new Mock(); @@ -44,7 +44,7 @@ namespace ImageSharp.Tests.Drawing public void FillOffCanvas() { - ImageSharp.Rectangle bounds = new ImageSharp.Rectangle(-100, -10, 10, 10); + SixLabors.Primitives.Rectangle bounds = new SixLabors.Primitives.Rectangle(-100, -10, 10, 10); Mock> brush = new Mock>(); Mock region = new Mock(); @@ -79,7 +79,7 @@ namespace ImageSharp.Tests.Drawing using (var img = new Image(10, 10)) { - img.DrawLines(new Pen(Rgba32.Black, 10), new Vector2[] { + img.DrawLines(new Pen(Rgba32.Black, 10), new SixLabors.Primitives.PointF[] { new Vector2(-10, 5), new Vector2(20, 5), }); diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index dc0b83615d..ce127cfe03 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -16,7 +16,7 @@ namespace ImageSharp.Tests.Drawing using Xunit; - public class FillSolidBrushTests: FileTestBase + public class FillSolidBrushTests : FileTestBase { [Fact] public void ImageShouldBeFloodFilledWithColorOnDefaultBackground() @@ -24,12 +24,9 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Fill", "SolidBrush"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/DefaultBack.png")) - { - image - .Fill(Rgba32.HotPink) - .Save(output); - } + image + .Fill(Rgba32.HotPink) + .Save($"{path}/DefaultBack.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -46,13 +43,10 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Fill", "SolidBrush"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -71,13 +65,11 @@ namespace ImageSharp.Tests.Drawing { Rgba32 color = new Rgba32(Rgba32.HotPink.R, Rgba32.HotPink.G, Rgba32.HotPink.B, 150); - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(color) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(color) + .Save($"{path}/Opacity.png"); + //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs index 1f35a37884..e058572fb3 100644 --- a/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineComplexPolygonTests.cs @@ -34,13 +34,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -84,13 +81,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/SimpleVanishHole.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) + .Save($"{path}/SimpleVanishHole.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -135,13 +129,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/SimpleOverlapping.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Rgba32.HotPink, 5, simplePath.Clip(hole1)) + .Save($"{path}/SimpleOverlapping.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -181,13 +172,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Dashed.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(Pens.Dash(Rgba32.HotPink, 5), simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(Pens.Dash(Rgba32.HotPink, 5), simplePath.Clip(hole1)) + .Save($"{path}/Dashed.png"); } } @@ -209,13 +197,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Draw(color, 5, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Draw(color, 5, simplePath.Clip(hole1)) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/LineTests.cs b/tests/ImageSharp.Tests/Drawing/LineTests.cs index e751557b6f..f47d566967 100644 --- a/tests/ImageSharp.Tests/Drawing/LineTests.cs +++ b/tests/ImageSharp.Tests/Drawing/LineTests.cs @@ -23,18 +23,15 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Rgba32.HotPink, 5, - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Rgba32.HotPink, 5, + new SixLabors.Primitives.PointF[]{ new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); - } + }) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -53,19 +50,16 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple_noantialias.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Rgba32.HotPink, 5, - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Rgba32.HotPink, 5, + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }, - new GraphicsOptions(false)) - .Save(output); - } + }, + new GraphicsOptions(false)) + .Save($"{path}/Simple_noantialias.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -84,20 +78,17 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Dashed.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.Dash(Rgba32.HotPink, 5), - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Pens.Dash(Rgba32.HotPink, 5), + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); + }) + .Save($"{path}/Dashed.png"); } } - } [Fact] public void ImageShouldBeOverlayedByPathDotted() @@ -105,20 +96,17 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Dot.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.Dot(Rgba32.HotPink, 5), - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Pens.Dot(Rgba32.HotPink, 5), + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); + }) + .Save($"{path}/Dot.png"); } } - } [Fact] public void ImageShouldBeOverlayedByPathDashDot() @@ -126,20 +114,17 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/DashDot.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.DashDot(Rgba32.HotPink, 5), - new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Pens.DashDot(Rgba32.HotPink, 5), + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); + }) + .Save($"{path}/DashDot.png"); } } - } [Fact] public void ImageShouldBeOverlayedByPathDashDotDot() @@ -147,18 +132,15 @@ namespace ImageSharp.Tests.Drawing string path = this.CreateOutputDirectory("Drawing", "Lines"); Image image = new Image(500, 500); - using (FileStream output = File.OpenWrite($"{path}/DashDotDot.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Pens.DashDotDot(Rgba32.HotPink, 5), new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Pens.DashDotDot(Rgba32.HotPink, 5), new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); + }) + .Save($"{path}/DashDotDot.png"); } - } [Fact] public void ImageShouldBeOverlayedPathWithOpacity() @@ -169,31 +151,27 @@ namespace ImageSharp.Tests.Drawing Image image = new Image(500, 500); - - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(color, 10, new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(color, 10, new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) - }) - .Save(output); - } + }) + .Save($"{path}/Opacity.png"); - //shift background color towards forground color by the opacity amount - Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f/255f)); + //shift background color towards forground color by the opacity amount + Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); - using (PixelAccessor sourcePixels = image.Lock()) - { - Assert.Equal(mergedColor, sourcePixels[11, 11]); + using (PixelAccessor sourcePixels = image.Lock()) + { + Assert.Equal(mergedColor, sourcePixels[11, 11]); - Assert.Equal(mergedColor, sourcePixels[199, 149]); + Assert.Equal(mergedColor, sourcePixels[199, 149]); - Assert.Equal(Rgba32.Blue, sourcePixels[50, 50]); + Assert.Equal(Rgba32.Blue, sourcePixels[50, 50]); + } } - } [Fact] public void ImageShouldBeOverlayedByPathOutline() @@ -202,30 +180,27 @@ namespace ImageSharp.Tests.Drawing Image image = new Image(500, 500); - using (FileStream output = File.OpenWrite($"{path}/Rectangle.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .DrawLines(Rgba32.HotPink, 10, new[] { + image + .BackgroundColor(Rgba32.Blue) + .DrawLines(Rgba32.HotPink, 10, new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 10), new Vector2(200, 150), new Vector2(10, 150) - }) - .Save(output); - } + }) + .Save($"{path}/Rectangle.png"); - using (PixelAccessor sourcePixels = image.Lock()) - { - Assert.Equal(Rgba32.HotPink, sourcePixels[11, 11]); + using (PixelAccessor sourcePixels = image.Lock()) + { + Assert.Equal(Rgba32.HotPink, sourcePixels[11, 11]); - Assert.Equal(Rgba32.HotPink, sourcePixels[198, 10]); + Assert.Equal(Rgba32.HotPink, sourcePixels[198, 10]); - Assert.Equal(Rgba32.Blue, sourcePixels[10, 50]); + Assert.Equal(Rgba32.Blue, sourcePixels[10, 50]); - Assert.Equal(Rgba32.Blue, sourcePixels[50, 50]); + Assert.Equal(Rgba32.Blue, sourcePixels[50, 50]); + } } - } + } } -} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs b/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs deleted file mode 100644 index 24f2a6bd8b..0000000000 --- a/tests/ImageSharp.Tests/Drawing/Paths/Extensions.cs +++ /dev/null @@ -1,33 +0,0 @@ - -namespace ImageSharp.Tests.Drawing.Paths -{ - using System; - using System.IO; - using ImageSharp; - using ImageSharp.Drawing.Brushes; - using ImageSharp.Processing; - using System.Collections.Generic; - using Xunit; - using ImageSharp.Drawing; - using System.Numerics; - using SixLabors.Shapes; - using ImageSharp.Drawing.Processors; - using ImageSharp.Drawing.Pens; - - public class Extensions - { - [Theory] - [InlineData(0.5, 0.5, 5, 5, 0,0,6,6)] - [InlineData(1, 1, 5, 5, 1,1,5,5)] - public void ConvertRectangle(float x, float y, float width, float height, int expectedX, int expectedY, int expectedWidth, int expectedHeight) - { - SixLabors.Shapes.Rectangle src = new SixLabors.Shapes.Rectangle(x, y, width, height); - ImageSharp.Rectangle actual = src.Convert(); - - Assert.Equal(expectedX, actual.X); - Assert.Equal(expectedY, actual.Y); - Assert.Equal(expectedWidth, actual.Width); - Assert.Equal(expectedHeight, actual.Height); - } - } -} diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs index eb0127cb10..3a2b66c3c2 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPath.cs @@ -16,7 +16,7 @@ namespace ImageSharp.Tests.Drawing.Paths GraphicsOptions noneDefault = new GraphicsOptions(); Rgba32 color = Rgba32.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); - IPath path = new SixLabors.Shapes.Path(new LinearLineSegment(new Vector2[] { + IPath path = new SixLabors.Shapes.Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { new Vector2(10,10), new Vector2(20,10), new Vector2(20,10), diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs index e60ac0c13d..24efa976e8 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPathCollection.cs @@ -16,13 +16,13 @@ namespace ImageSharp.Tests.Drawing.Paths GraphicsOptions noneDefault = new GraphicsOptions(); Rgba32 color = Rgba32.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); - IPath path1 = new SixLabors.Shapes.Path(new LinearLineSegment(new Vector2[] { + IPath path1 = new SixLabors.Shapes.Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { new Vector2(10,10), new Vector2(20,10), new Vector2(20,10), new Vector2(30,10), })); - IPath path2 = new SixLabors.Shapes.Path(new LinearLineSegment(new Vector2[] { + IPath path2 = new SixLabors.Shapes.Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { new Vector2(10,10), new Vector2(20,10), new Vector2(20,10), diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs index 3f912fe79f..b46d3d0d9c 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillPolygon.cs @@ -16,7 +16,7 @@ namespace ImageSharp.Tests.Drawing.Paths GraphicsOptions noneDefault = new GraphicsOptions(); Rgba32 color = Rgba32.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); - Vector2[] path = new Vector2[] { + SixLabors.Primitives.PointF[] path = new SixLabors.Primitives.PointF[] { new Vector2(10,10), new Vector2(20,10), new Vector2(20,10), diff --git a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs index 1f4774550e..7e6a3deee5 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Tests.Drawing.Paths GraphicsOptions noneDefault = new GraphicsOptions(); Rgba32 color = Rgba32.HotPink; SolidBrush brush = Brushes.Solid(Rgba32.HotPink); - ImageSharp.Rectangle rectangle = new ImageSharp.Rectangle(10, 10, 77, 76); + SixLabors.Primitives.Rectangle rectangle = new SixLabors.Primitives.Rectangle(10, 10, 77, 76); private ProcessorWatchingImage img; @@ -40,7 +40,7 @@ namespace ImageSharp.Tests.Drawing.Paths Assert.Equal(GraphicsOptions.Default, processor.Options); ShapeRegion region = Assert.IsType(processor.Region); - SixLabors.Shapes.Rectangle rect = Assert.IsType(region.Shape); + SixLabors.Shapes.RectangularePolygon rect = Assert.IsType(region.Shape); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); @@ -60,7 +60,7 @@ namespace ImageSharp.Tests.Drawing.Paths Assert.Equal(noneDefault, processor.Options); ShapeRegion region = Assert.IsType(processor.Region); - SixLabors.Shapes.Rectangle rect = Assert.IsType(region.Shape); + SixLabors.Shapes.RectangularePolygon rect = Assert.IsType(region.Shape); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); @@ -80,7 +80,7 @@ namespace ImageSharp.Tests.Drawing.Paths Assert.Equal(GraphicsOptions.Default, processor.Options); ShapeRegion region = Assert.IsType(processor.Region); - SixLabors.Shapes.Rectangle rect = Assert.IsType(region.Shape); + SixLabors.Shapes.RectangularePolygon rect = Assert.IsType(region.Shape); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); @@ -101,7 +101,7 @@ namespace ImageSharp.Tests.Drawing.Paths Assert.Equal(noneDefault, processor.Options); ShapeRegion region = Assert.IsType(processor.Region); - SixLabors.Shapes.Rectangle rect = Assert.IsType(region.Shape); + SixLabors.Shapes.RectangularePolygon rect = Assert.IsType(region.Shape); Assert.Equal(rect.Location.X, rectangle.X); Assert.Equal(rect.Location.Y, rectangle.Y); Assert.Equal(rect.Size.Width, rectangle.Width); diff --git a/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs b/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs index 0392160788..1670b33520 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/ProcessorWatchingImage.cs @@ -7,6 +7,7 @@ namespace ImageSharp.Tests.Drawing.Paths using ImageSharp.Processing; using System.Collections.Generic; using ImageSharp.PixelFormats; + using SixLabors.Primitives; /// /// Watches but does not actually run the processors against the image. diff --git a/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs index 7765436f72..df183a8aff 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs @@ -15,17 +15,18 @@ namespace ImageSharp.Tests.Drawing.Paths using ImageSharp.Drawing.Pens; using Moq; using System.Collections.Immutable; + using SixLabors.Primitives; public class ShapeRegionTests { private readonly Mock pathMock; - private readonly SixLabors.Shapes.Rectangle bounds; + private readonly SixLabors.Primitives.RectangleF bounds; public ShapeRegionTests() { this.pathMock = new Mock(); - this.bounds = new SixLabors.Shapes.Rectangle(10.5f, 10, 10, 10); + this.bounds = new RectangleF(10.5f, 10, 10, 10); pathMock.Setup(x => x.Bounds).Returns(this.bounds); // wire up the 2 mocks to reference eachother pathMock.Setup(x => x.AsClosedPath()).Returns(() => pathMock.Object); @@ -73,8 +74,8 @@ namespace ImageSharp.Tests.Drawing.Paths int yToScan = 10; ShapeRegion region = new ShapeRegion(pathMock.Object); - pathMock.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((s, e, b, c, o) => { + pathMock.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny>())) + .Callback>((s, e, b) => { Assert.Equal(yToScan, s.Y); Assert.Equal(yToScan, e.Y); Assert.True(s.X < bounds.Left); @@ -83,7 +84,7 @@ namespace ImageSharp.Tests.Drawing.Paths int i = region.Scan(yToScan, new float[0]); - pathMock.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + pathMock.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny>()), Times.Once); } [Fact] @@ -92,8 +93,8 @@ namespace ImageSharp.Tests.Drawing.Paths int yToScan = 10; ShapeRegion region = new ShapeRegion(pathMock.Object); - pathMock.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((s, e, b, c, o) => { + pathMock.Setup(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny>())) + .Callback>((s, e, b) => { Assert.Equal(yToScan, s.Y); Assert.Equal(yToScan, e.Y); Assert.True(s.X < bounds.Left); @@ -102,7 +103,7 @@ namespace ImageSharp.Tests.Drawing.Paths int i = region.Scan(yToScan, new float[0]); - pathMock.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + pathMock.Verify(x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny>()), Times.Once); } [Fact] diff --git a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs index 9bc918d37a..501b10e4af 100644 --- a/tests/ImageSharp.Tests/Drawing/PolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/PolygonTests.cs @@ -14,6 +14,7 @@ namespace ImageSharp.Tests.Drawing using System.Numerics; using ImageSharp.PixelFormats; + using SixLabors.Primitives; public class PolygonTests : FileTestBase { @@ -24,18 +25,15 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { image .BackgroundColor(Rgba32.Blue) .DrawPolygon(Rgba32.HotPink, 5, - new[] { + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) }) - .Save(output); - } + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -54,7 +52,7 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedPolygonOutlineWithOpacity() { string path = this.CreateOutputDirectory("Drawing", "Polygons"); - Vector2[] simplePath = new[] { + SixLabors.Primitives.PointF[] simplePath = new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) @@ -64,13 +62,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { image .BackgroundColor(Rgba32.Blue) .DrawPolygon(color, 10, simplePath) - .Save(output); - } + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); @@ -95,13 +90,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Rectangle.png")) - { image .BackgroundColor(Rgba32.Blue) .Draw(Rgba32.HotPink, 10, new Rectangle(10, 10, 190, 140)) - .Save(output); - } + .Save($"{path}/Rectangle.png"); using (PixelAccessor sourcePixels = image.Lock()) { diff --git a/tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs b/tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs index 83419caaf4..9c62e860a8 100644 --- a/tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/RecolorImageTest.cs @@ -12,6 +12,7 @@ namespace ImageSharp.Tests using ImageSharp.PixelFormats; using Xunit; + using SixLabors.Primitives; public class RecolorImageTest : FileTestBase { @@ -26,11 +27,8 @@ namespace ImageSharp.Tests { using (Image image = file.CreateImage()) { - using (FileStream output = File.OpenWrite($"{path}/{file.FileName}")) - { - image.Fill(brush) - .Save(output); - } + image.Fill(brush) + .Save($"{path}/{file.FileName}"); } } } @@ -46,12 +44,9 @@ namespace ImageSharp.Tests { using (Image image = file.CreateImage()) { - using (FileStream output = File.OpenWrite($"{path}/Shaped_{file.FileName}")) - { - int imageHeight = image.Height; - image.Fill(brush, new Rectangle(0, imageHeight/2 - imageHeight/4, image.Width, imageHeight/2)) - .Save(output); - } + int imageHeight = image.Height; + image.Fill(brush, new Rectangle(0, imageHeight / 2 - imageHeight / 4, image.Width, imageHeight / 2)) + .Save($"{path}/Shaped_{file.FileName}"); } } } diff --git a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs index 6cab7778e0..ba904cb3f2 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidBezierTests.cs @@ -20,7 +20,7 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByFilledPolygon() { string path = this.CreateOutputDirectory("Drawing", "FilledBezier"); - Vector2[] simplePath = new[] { + SixLabors.Primitives.PointF[] simplePath = new SixLabors.Primitives.PointF[] { new Vector2(10, 400), new Vector2(30, 10), new Vector2(240, 30), @@ -28,13 +28,10 @@ namespace ImageSharp.Tests.Drawing }; using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { image .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new Polygon(new BezierLineSegment(simplePath))) - .Save(output); - } + .Fill(Rgba32.HotPink, new Polygon(new CubicBezierLineSegment(simplePath))) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -53,7 +50,7 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByFilledPolygonOpacity() { string path = this.CreateOutputDirectory("Drawing", "FilledBezier"); - Vector2[] simplePath = new[] { + SixLabors.Primitives.PointF[] simplePath = new SixLabors.Primitives.PointF[] { new Vector2(10, 400), new Vector2(30, 10), new Vector2(240, 30), @@ -63,13 +60,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { image .BackgroundColor(Rgba32.Blue) - .Fill(color, new Polygon(new BezierLineSegment(simplePath))) - .Save(output); - } + .Fill(color, new Polygon(new CubicBezierLineSegment(simplePath))) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs index 5e0244d02f..c3af3d5c28 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidComplexPolygonTests.cs @@ -31,16 +31,13 @@ namespace ImageSharp.Tests.Drawing new Vector2(93, 85), new Vector2(65, 137))); IPath clipped = simplePath.Clip(hole1); - // var clipped = new Rectangle(10, 10, 100, 100).Clip(new Rectangle(20, 0, 20, 20)); + // var clipped = new Rectangle(10, 10, 100, 100).Clip(new Rectangle(20, 0, 20, 20)); using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, clipped) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, clipped) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -69,13 +66,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/SimpleOverlapping.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, simplePath.Clip(hole1)) + .Save($"{path}/SimpleOverlapping.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -104,13 +98,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(color, simplePath.Clip(hole1)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(color, simplePath.Clip(hole1)) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index 8ffa62d815..793bcfc9f0 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -23,7 +23,7 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByFilledPolygon() { string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); - Vector2[] simplePath = new[] { + SixLabors.Primitives.PointF[] simplePath = new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) @@ -31,12 +31,9 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Simple.png")) - { - image - .FillPolygon(Rgba32.HotPink, simplePath, new GraphicsOptions(true)) - .Save(output); - } + image + .FillPolygon(Rgba32.HotPink, simplePath, new GraphicsOptions(true)) + .Save($"{path}/Simple.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -49,7 +46,7 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByFilledPolygonWithPattern() { string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); - Vector2[] simplePath = new[] { + SixLabors.Primitives.PointF[] simplePath = new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) @@ -57,12 +54,9 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Pattern.png")) - { - image - .FillPolygon(Brushes.Horizontal(Rgba32.HotPink), simplePath, new GraphicsOptions(true)) - .Save(output); - } + image + .FillPolygon(Brushes.Horizontal(Rgba32.HotPink), simplePath, new GraphicsOptions(true)) + .Save($"{path}/Pattern.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -75,19 +69,18 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByFilledPolygonNoAntialias() { string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); - Vector2[] simplePath = new[] { + SixLabors.Primitives.PointF[] simplePath = new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) }; using (Image image = new Image(500, 500)) - using (FileStream output = File.OpenWrite($"{path}/Simple_NoAntialias.png")) { image .BackgroundColor(Rgba32.Blue) .FillPolygon(Rgba32.HotPink, simplePath, new GraphicsOptions(false)) - .Save(output); + .Save($"{path}/Simple_NoAntialias.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -106,7 +99,7 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByFilledPolygonImage() { string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); - Vector2[] simplePath = new[] { + SixLabors.Primitives.PointF[] simplePath = new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) @@ -114,14 +107,13 @@ namespace ImageSharp.Tests.Drawing using (Image brushImage = TestFile.Create(TestImages.Bmp.Car).CreateImage()) using (Image image = new Image(500, 500)) - using (FileStream output = File.OpenWrite($"{path}/Image.png")) { ImageBrush brush = new ImageBrush(brushImage); image .BackgroundColor(Rgba32.Blue) .FillPolygon(brush, simplePath) - .Save(output); + .Save($"{path}/Image.png"); } } @@ -129,7 +121,7 @@ namespace ImageSharp.Tests.Drawing public void ImageShouldBeOverlayedByFilledPolygonOpacity() { string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); - Vector2[] simplePath = new[] { + SixLabors.Primitives.PointF[] simplePath = new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300) @@ -138,13 +130,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Opacity.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .FillPolygon(color, simplePath) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .FillPolygon(color, simplePath) + .Save($"{path}/Opacity.png"); //shift background color towards forground color by the opacity amount Rgba32 mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); @@ -163,13 +152,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(500, 500)) { - using (FileStream output = File.OpenWrite($"{path}/Rectangle.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new SixLabors.Shapes.Rectangle(10, 10, 190, 140)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, new SixLabors.Shapes.RectangularePolygon(10, 10, 190, 140)) + .Save($"{path}/Rectangle.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -193,13 +179,10 @@ namespace ImageSharp.Tests.Drawing using (Image image = new Image(100, 100)) { - using (FileStream output = File.OpenWrite($"{path}/Triangle.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 3, 30)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 3, 30)) + .Save($"{path}/Triangle.png"); using (PixelAccessor sourcePixels = image.Lock()) { @@ -219,13 +202,10 @@ namespace ImageSharp.Tests.Drawing config.ParallelOptions.MaxDegreeOfParallelism = 1; using (Image image = new Image(config, 100, 100)) { - using (FileStream output = File.OpenWrite($"{path}/Septagon.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 7, 30, -(float)Math.PI)) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 7, 30, -(float)Math.PI)) + .Save($"{path}/Septagon.png"); } } @@ -238,14 +218,11 @@ namespace ImageSharp.Tests.Drawing config.ParallelOptions.MaxDegreeOfParallelism = 1; using (Image image = new Image(config, 100, 100)) { - using (FileStream output = File.OpenWrite($"{path}/ellipse.png")) - { - image - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink, new Ellipse(50, 50, 30, 50) - .Rotate((float)(Math.PI / 3))) - .Save(output); - } + image + .BackgroundColor(Rgba32.Blue) + .Fill(Rgba32.HotPink, new EllipsePolygon(50, 50, 30, 50) + .Rotate((float)(Math.PI / 3))) + .Save($"{path}/ellipse.png"); } } @@ -258,21 +235,18 @@ namespace ImageSharp.Tests.Drawing config.ParallelOptions.MaxDegreeOfParallelism = 1; using (Image image = new Image(config, 200, 200)) { - using (FileStream output = File.OpenWrite($"{path}/clipped-corner.png")) - { - image - .Fill(Rgba32.Blue) - .FillPolygon(Rgba32.HotPink, new[] - { + image + .Fill(Rgba32.Blue) + .FillPolygon(Rgba32.HotPink, new SixLabors.Primitives.PointF[] + { new Vector2( 8, 8 ), new Vector2( 64, 8 ), new Vector2( 64, 64 ), new Vector2( 120, 64 ), new Vector2( 120, 120 ), new Vector2( 8, 120 ) - } ) - .Save(output); - } + }) + .Save($"{path}/clipped-corner.png"); } } } diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs index 60fe44acdf..05a1f1e363 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs @@ -28,7 +28,7 @@ namespace ImageSharp.Tests.Drawing.Text IPath path = new SixLabors.Shapes.Path( new LinearLineSegment( - new Vector2[] { new Vector2(10, 10), new Vector2(20, 10), new Vector2(20, 10), new Vector2(30, 10), })); + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(20, 10), new Vector2(20, 10), new Vector2(30, 10), })); private ProcessorWatchingImage img; @@ -39,7 +39,7 @@ namespace ImageSharp.Tests.Drawing.Text public DrawText_Path() { this.FontCollection = new FontCollection(); - this.Font = this.FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")); + this.Font = this.FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")).CreateFont(12); this.img = new ProcessorWatchingImage(10, 10); } diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs index 4718ed4196..1c8c9f1d16 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs @@ -28,7 +28,7 @@ namespace ImageSharp.Tests.Drawing.Text IPath path = new SixLabors.Shapes.Path( new LinearLineSegment( - new Vector2[] { new Vector2(10, 10), new Vector2(20, 10), new Vector2(20, 10), new Vector2(30, 10), })); + new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(20, 10), new Vector2(20, 10), new Vector2(30, 10), })); private ProcessorWatchingImage img; @@ -39,7 +39,7 @@ namespace ImageSharp.Tests.Drawing.Text public DrawText() { this.FontCollection = new FontCollection(); - this.Font = this.FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")); + this.Font = this.FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")).CreateFont(12); this.img = new ProcessorWatchingImage(10, 10); } diff --git a/tests/ImageSharp.Tests/Drawing/Text/OutputText.cs b/tests/ImageSharp.Tests/Drawing/Text/OutputText.cs index 21646b03f3..ce2a5becf9 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/OutputText.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/OutputText.cs @@ -25,7 +25,7 @@ namespace ImageSharp.Tests.Drawing.Text public OutputText() { this.FontCollection = new FontCollection(); - this.Font = FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")); + this.Font = FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")).CreateFont(12); } [Fact] diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index cf073d3d03..e5af28d8b4 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -31,7 +31,7 @@ namespace ImageSharp.Tests string filename = file.GetFileNameWithoutExtension(bitsPerPixel); using (Image image = file.CreateImage()) { - image.Save($"{path}/{filename}.bmp", new BmpEncoderOptions { BitsPerPixel = bitsPerPixel }); + image.Save($"{path}/{filename}.bmp", new BmpEncoder { BitsPerPixel = bitsPerPixel }); } } } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index ec1a8c4659..4ef8fe0612 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests { using System.IO; - + using ImageSharp.Formats; using ImageSharp.PixelFormats; using Xunit; @@ -36,7 +36,7 @@ namespace ImageSharp.Tests using (Image image = file.CreateImage()) { string filename = path + "/" + file.FileNameWithoutExtension + ".txt"; - File.WriteAllText(filename, image.ToBase64String()); + File.WriteAllText(filename, image.ToBase64String(ImageFormats.Png)); } } } @@ -50,10 +50,7 @@ namespace ImageSharp.Tests { using (Image image = file.CreateImage()) { - using (FileStream output = File.OpenWrite($"{path}/{file.FileName}")) - { - image.Save(output); - } + image.Save($"{path}/{file.FileName}"); } } } @@ -65,14 +62,14 @@ namespace ImageSharp.Tests foreach (TestFile file in Files) { - using (Image srcImage = file.CreateImage()) + using (Image srcImage = Image.Load(file.Bytes, out var mimeType)) { using (Image image = new Image(srcImage)) { using (FileStream output = File.OpenWrite($"{path}/Octree-{file.FileName}")) { image.Quantize(Quantization.Octree) - .Save(output, image.CurrentImageFormat); + .Save(output, mimeType); } } @@ -82,7 +79,7 @@ namespace ImageSharp.Tests using (FileStream output = File.OpenWrite($"{path}/Wu-{file.FileName}")) { image.Quantize(Quantization.Wu) - .Save(output, image.CurrentImageFormat); + .Save(output, mimeType); } } @@ -91,7 +88,7 @@ namespace ImageSharp.Tests using (FileStream output = File.OpenWrite($"{path}/Palette-{file.FileName}")) { image.Quantize(Quantization.Palette) - .Save(output, image.CurrentImageFormat); + .Save(output, mimeType); } } } @@ -138,18 +135,17 @@ namespace ImageSharp.Tests foreach (TestFile file in Files) { byte[] serialized; - using (Image image = file.CreateImage()) + using (Image image = Image.Load(file.Bytes, out IImageFormat mimeType)) using (MemoryStream memoryStream = new MemoryStream()) { - image.Save(memoryStream); + image.Save(memoryStream, mimeType); memoryStream.Flush(); serialized = memoryStream.ToArray(); } using (Image image2 = Image.Load(serialized)) - using (FileStream output = File.OpenWrite($"{path}/{file.FileName}")) { - image2.Save(output); + image2.Save($"{path}/{file.FileName}"); } } } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 89df2d086e..06bfd8990d 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -33,7 +33,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsFalse_CommentsAreRead() { - DecoderOptions options = new DecoderOptions() + GifDecoder options = new GifDecoder() { IgnoreMetadata = false }; @@ -51,7 +51,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsTrue_CommentsAreIgnored() { - DecoderOptions options = new DecoderOptions() + GifDecoder options = new GifDecoder() { IgnoreMetadata = true }; @@ -67,7 +67,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding() { - GifDecoderOptions options = new GifDecoderOptions() + GifDecoder options = new GifDecoder() { TextEncoding = Encoding.Unicode }; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 70cc8e2ba6..c365396863 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -29,7 +29,7 @@ namespace ImageSharp.Tests [Fact] public void Encode_IgnoreMetadataIsFalse_CommentsAreWritten() { - EncoderOptions options = new EncoderOptions() + GifEncoder options = new GifEncoder() { IgnoreMetadata = false }; @@ -40,7 +40,7 @@ namespace ImageSharp.Tests { using (MemoryStream memStream = new MemoryStream()) { - input.Save(memStream, new GifFormat(), options); + input.Save(memStream, options); memStream.Position = 0; using (Image output = Image.Load(memStream)) @@ -56,7 +56,7 @@ namespace ImageSharp.Tests [Fact] public void Encode_IgnoreMetadataIsTrue_CommentsAreNotWritten() { - GifEncoderOptions options = new GifEncoderOptions() + GifEncoder options = new GifEncoder() { IgnoreMetadata = true }; @@ -88,7 +88,7 @@ namespace ImageSharp.Tests using (MemoryStream memStream = new MemoryStream()) { - input.Save(memStream, new GifFormat()); + input.Save(memStream, new GifEncoder()); memStream.Position = 0; using (Image output = Image.Load(memStream)) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 446c5e96ae..9401d098de 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -62,13 +62,12 @@ namespace ImageSharp.Tests byte[] data; using (Image image = provider.GetImage()) { - JpegEncoder encoder = new JpegEncoder(); - JpegEncoderOptions options = new JpegEncoderOptions { Subsample = subsample, Quality = quality }; + JpegEncoder encoder = new JpegEncoder { Subsample = subsample, Quality = quality }; data = new byte[65536]; using (MemoryStream ms = new MemoryStream(data)) { - image.Save(ms, encoder, options); + image.Save(ms, encoder); } } @@ -91,7 +90,7 @@ namespace ImageSharp.Tests image.Save(ms, new JpegEncoder()); ms.Seek(0, SeekOrigin.Begin); - using (JpegDecoderCore decoder = new JpegDecoderCore(null, null)) + using (JpegDecoderCore decoder = new JpegDecoderCore(null, new JpegDecoder())) { Image mirror = decoder.Decode(ms); @@ -125,14 +124,14 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsFalse_ExifProfileIsRead() { - DecoderOptions options = new DecoderOptions() + JpegDecoder decoder = new JpegDecoder() { IgnoreMetadata = false }; TestFile testFile = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan); - using (Image image = testFile.CreateImage(options)) + using (Image image = testFile.CreateImage(decoder)) { Assert.NotNull(image.MetaData.ExifProfile); } @@ -141,7 +140,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsTrue_ExifProfileIgnored() { - DecoderOptions options = new DecoderOptions() + JpegDecoder options = new JpegDecoder() { IgnoreMetadata = true }; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index ab81c69b42..86faeee232 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -17,6 +17,7 @@ namespace ImageSharp.Tests using ImageSharp.Formats.Jpg; using ImageSharp.PixelFormats; using ImageSharp.Processing; + using SixLabors.Primitives; public class JpegEncoderTests : MeasureFixture { @@ -37,14 +38,12 @@ namespace ImageSharp.Tests { using (Image image = provider.GetImage().Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max })) { - image.MetaData.Quality = quality; image.MetaData.ExifProfile = null; // Reduce the size of the file - JpegEncoder encoder = new JpegEncoder(); - JpegEncoderOptions options = new JpegEncoderOptions { Subsample = subsample, Quality = quality }; + JpegEncoder options = new JpegEncoder { Subsample = subsample, Quality = quality }; provider.Utility.TestName += $"{subsample}_Q{quality}"; provider.Utility.SaveTestOutputFile(image, "png"); - provider.Utility.SaveTestOutputFile(image, "jpg", encoder, options); + provider.Utility.SaveTestOutputFile(image, "jpg", options); } } @@ -61,9 +60,7 @@ namespace ImageSharp.Tests using (FileStream outputStream = File.OpenWrite(utility.GetTestOutputFileName("jpg"))) { - JpegEncoder encoder = new JpegEncoder(); - - image.Save(outputStream, encoder, new JpegEncoderOptions() + image.Save(outputStream, new JpegEncoder() { Subsample = subSample, Quality = quality @@ -75,7 +72,7 @@ namespace ImageSharp.Tests [Fact] public void Encode_IgnoreMetadataIsFalse_ExifProfileIsWritten() { - EncoderOptions options = new EncoderOptions() + JpegEncoder options = new JpegEncoder() { IgnoreMetadata = false }; @@ -86,7 +83,7 @@ namespace ImageSharp.Tests { using (MemoryStream memStream = new MemoryStream()) { - input.Save(memStream, new JpegFormat(), options); + input.Save(memStream, options); memStream.Position = 0; using (Image output = Image.Load(memStream)) @@ -100,7 +97,7 @@ namespace ImageSharp.Tests [Fact] public void Encode_IgnoreMetadataIsTrue_ExifProfileIgnored() { - JpegEncoderOptions options = new JpegEncoderOptions() + JpegEncoder options = new JpegEncoder() { IgnoreMetadata = true }; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index f3412e45e2..daf8da6a38 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -82,9 +82,8 @@ namespace ImageSharp.Tests { foreach (Image img in testImages) { - JpegEncoder encoder = new JpegEncoder(); - JpegEncoderOptions options = new JpegEncoderOptions { Quality = quality, Subsample = subsample }; - img.Save(ms, encoder, options); + JpegEncoder options = new JpegEncoder { Quality = quality, Subsample = subsample }; + img.Save(ms, options); ms.Seek(0, SeekOrigin.Begin); } }, diff --git a/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs index b7cd281cd3..b911e11846 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/YCbCrImageTests.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests { using ImageSharp.Formats.Jpg; - + using SixLabors.Primitives; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 195a8dcb3e..6d82b53746 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Tests public static readonly string[] TestFiles = { TestImages.Png.Splash, TestImages.Png.Indexed, TestImages.Png.Interlaced, TestImages.Png.FilterVar, - TestImages.Png.Bad.ChunkLength1, TestImages.Png.Bad.ChunkLength2 + TestImages.Png.Bad.ChunkLength1, TestImages.Png.Bad.ChunkLength2, TestImages.Png.Rgb48Bpp }; [Theory] @@ -35,7 +35,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsFalse_TextChunckIsRead() { - PngDecoderOptions options = new PngDecoderOptions() + PngDecoder options = new PngDecoder() { IgnoreMetadata = false }; @@ -53,7 +53,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_IgnoreMetadataIsTrue_TextChunksAreIgnored() { - PngDecoderOptions options = new PngDecoderOptions() + PngDecoder options = new PngDecoder() { IgnoreMetadata = true }; @@ -69,7 +69,7 @@ namespace ImageSharp.Tests [Fact] public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding() { - PngDecoderOptions options = new PngDecoderOptions() + PngDecoder options = new PngDecoder() { TextEncoding = Encoding.Unicode }; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 02edf7688f..24907cfdb7 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -31,13 +31,13 @@ namespace ImageSharp.Tests { using (Image image = provider.GetImage()) { - PngEncoderOptions options = new PngEncoderOptions() + PngEncoder options = new PngEncoder() { PngColorType = pngColorType }; provider.Utility.TestName += "_" + pngColorType; - provider.Utility.SaveTestOutputFile(image, "png", new PngEncoder(), options); + provider.Utility.SaveTestOutputFile(image, "png", options); } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs index 90f994f366..bac340a71c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs @@ -50,8 +50,7 @@ namespace ImageSharp.Tests.Formats.Png using (MemoryStream ms = new MemoryStream()) { // image.Save(provider.Utility.GetTestOutputFileName("bmp")); - image.MetaData.Quality = 256; - image.Save(ms, new PngEncoder()); + image.Save(ms, new PngEncoder() { PaletteSize = 256 }); ms.Position = 0; using (Image img2 = Image.Load(ms, new PngDecoder())) { diff --git a/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs b/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs new file mode 100644 index 0000000000..59a39c4542 --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageDiscoverMimeType.cs @@ -0,0 +1,111 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System; + using System.IO; + + using ImageSharp.Formats; + using ImageSharp.IO; + using ImageSharp.PixelFormats; + using Moq; + using Xunit; + + /// + /// Tests the class. + /// + public class DiscoverImageFormatTests + { + private readonly Mock fileSystem; + private readonly string FilePath; + private readonly Mock localMimeTypeDetector; + private readonly Mock localImageFormatMock; + + public IImageFormat localImageFormat => localImageFormatMock.Object; + public Configuration LocalConfiguration { get; private set; } + public byte[] Marker { get; private set; } + public MemoryStream DataStream { get; private set; } + public byte[] DecodedData { get; private set; } + private const string localMimeType = "image/local"; + + public DiscoverImageFormatTests() + { + this.localImageFormatMock = new Mock(); + + this.localMimeTypeDetector = new Mock(); + this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); + this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny>())).Returns(localImageFormatMock.Object); + + this.fileSystem = new Mock(); + + this.LocalConfiguration = new Configuration() + { + FileSystem = this.fileSystem.Object + }; + this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector.Object); + + TestFormat.RegisterGloablTestFormat(); + this.Marker = Guid.NewGuid().ToByteArray(); + this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker); + + this.FilePath = Guid.NewGuid().ToString(); + this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); + + TestFileSystem.RegisterGloablTestFormat(); + TestFileSystem.Global.AddFile(this.FilePath, this.DataStream); + } + + [Fact] + public void DiscoverImageFormatByteArray() + { + var type = Image.DetectFormat(DataStream.ToArray()); + Assert.Equal(TestFormat.GlobalTestFormat, type); + } + + [Fact] + public void DiscoverImageFormatByteArray_WithConfig() + { + var type = Image.DetectFormat(this.LocalConfiguration, DataStream.ToArray()); + Assert.Equal(localImageFormat, type); + } + + [Fact] + public void DiscoverImageFormatFile() + { + var type = Image.DetectFormat(this.FilePath); + Assert.Equal(TestFormat.GlobalTestFormat, type); + } + + [Fact] + public void DiscoverImageFormatFilePath_WithConfig() + { + var type = Image.DetectFormat(this.LocalConfiguration, FilePath); + Assert.Equal(localImageFormat, type); + } + + + [Fact] + public void DiscoverImageFormatStream() + { + var type = Image.DetectFormat(this.DataStream); + Assert.Equal(TestFormat.GlobalTestFormat, type); + } + + [Fact] + public void DiscoverImageFormatFileStream_WithConfig() + { + var type = Image.DetectFormat(this.LocalConfiguration, DataStream); + Assert.Equal(localImageFormat, type); + } + + [Fact] + public void DiscoverImageFormatNoDetectorsRegisterdShouldReturnNull() + { + var type = Image.DetectFormat(new Configuration(), DataStream); + Assert.Null(type); + } + } +} diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index 7a5b8ffc53..bb64ceda34 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -20,11 +20,11 @@ namespace ImageSharp.Tests public class ImageLoadTests : IDisposable { private readonly Mock fileSystem; - private readonly IDecoderOptions decoderOptions; private Image returnImage; private Mock localDecoder; - private Mock localFormat; private readonly string FilePath; + private readonly Mock localMimeTypeDetector; + private readonly Mock localImageFormatMock; public Configuration LocalConfiguration { get; private set; } public byte[] Marker { get; private set; } @@ -35,19 +35,16 @@ namespace ImageSharp.Tests { this.returnImage = new Image(1, 1); + this.localImageFormatMock = new Mock(); + this.localDecoder = new Mock(); - this.localFormat = new Mock(); - this.localFormat.Setup(x => x.Decoder).Returns(this.localDecoder.Object); - this.localFormat.Setup(x => x.Encoder).Returns(new Mock().Object); - this.localFormat.Setup(x => x.MimeType).Returns("img/test"); - this.localFormat.Setup(x => x.Extension).Returns("png"); - this.localFormat.Setup(x => x.HeaderSize).Returns(1); - this.localFormat.Setup(x => x.IsSupportedFileFormat(It.IsAny())).Returns(true); - this.localFormat.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); - - this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny(), It.IsAny())) - - .Callback((c, s, o) => { + this.localMimeTypeDetector = new Mock(); + this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); + this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny>())).Returns(localImageFormatMock.Object); + + this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) + + .Callback((c, s) => { using (var ms = new MemoryStream()) { s.CopyTo(ms); @@ -58,14 +55,16 @@ namespace ImageSharp.Tests this.fileSystem = new Mock(); - this.LocalConfiguration = new Configuration(this.localFormat.Object) + this.LocalConfiguration = new Configuration() { FileSystem = this.fileSystem.Object }; + this.LocalConfiguration.AddImageFormatDetector(this.localMimeTypeDetector.Object); + this.LocalConfiguration.SetDecoder(localImageFormatMock.Object, this.localDecoder.Object); + TestFormat.RegisterGloablTestFormat(); this.Marker = Guid.NewGuid().ToByteArray(); this.DataStream = TestFormat.GlobalTestFormat.CreateStream(this.Marker); - this.decoderOptions = new Mock().Object; this.FilePath = Guid.NewGuid().ToString(); this.fileSystem.Setup(x => x.OpenRead(this.FilePath)).Returns(this.DataStream); @@ -80,11 +79,8 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream); Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } [Fact] @@ -94,10 +90,8 @@ namespace ImageSharp.Tests Image img = Image.Load(stream); Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } @@ -108,36 +102,11 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); - - } - - [Fact] - public void LoadFromStreamWithOptions() - { - Image img = Image.Load(this.DataStream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); - - } - - [Fact] - public void LoadFromStreamWithTypeAndOptions() - { - Image img = Image.Load(this.DataStream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } + [Fact] public void LoadFromStreamWithConfig() @@ -146,9 +115,8 @@ namespace ImageSharp.Tests Image img = Image.Load(this.LocalConfiguration, stream); Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, null)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream)); } @@ -160,40 +128,11 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, null)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream)); } - [Fact] - public void LoadFromStreamWithConfigAndOptions() - { - Stream stream = new MemoryStream(); - Image img = Image.Load(this.LocalConfiguration, stream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, this.decoderOptions)); - - } - - [Fact] - public void LoadFromStreamWithTypeAndConfigAndOptions() - { - Stream stream = new MemoryStream(); - Image img = Image.Load(this.LocalConfiguration, stream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, stream, this.decoderOptions)); - - } - - [Fact] public void LoadFromStreamWithDecoder() @@ -202,7 +141,7 @@ namespace ImageSharp.Tests Image img = Image.Load(stream, this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, null)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream)); } [Fact] @@ -213,28 +152,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, null)); - } - - [Fact] - public void LoadFromStreamWithDecoderAndOptions() - { - Stream stream = new MemoryStream(); - Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, this.decoderOptions)); - } - - [Fact] - public void LoadFromStreamWithTypeAndDecoderAndOptions() - { - Stream stream = new MemoryStream(); - Image img = Image.Load(stream, this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, stream)); } [Fact] @@ -243,10 +161,9 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream.ToArray()); Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } @@ -257,34 +174,8 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); - - } - - [Fact] - public void LoadFromBytesWithOptions() - { - Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); - - } - - [Fact] - public void LoadFromBytesWithTypeAndOptions() - { - Image img = Image.Load(this.DataStream.ToArray(), this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } @@ -294,9 +185,8 @@ namespace ImageSharp.Tests Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray()); Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), null)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny())); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -308,49 +198,19 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), null)); - - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithConfigAndOptions() - { - Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray(), this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), this.decoderOptions)); - - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithTypeAndConfigAndOptions() - { - Image img = Image.Load(this.LocalConfiguration, this.DataStream.ToArray(), this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny(), this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, It.IsAny())); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } - [Fact] public void LoadFromBytesWithDecoder() { Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), null)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny())); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -361,28 +221,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), null)); - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithDecoderAndOptions() - { - Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), this.decoderOptions)); - Assert.Equal(this.DataStream.ToArray(), this.DecodedData); - } - - [Fact] - public void LoadFromBytesWithTypeAndDecoderAndOptions() - { - Image img = Image.Load(this.DataStream.ToArray(), this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny(), this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, It.IsAny())); Assert.Equal(this.DataStream.ToArray(), this.DecodedData); } @@ -392,10 +231,9 @@ namespace ImageSharp.Tests Image img = Image.Load(this.DataStream); Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } @@ -406,35 +244,8 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); - - } - - [Fact] - public void LoadFromFileWithOptions() - { - Image img = Image.Load(this.DataStream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); - - } - - [Fact] - public void LoadFromFileWithTypeAndOptions() - { - Image img = Image.Load(this.DataStream, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(TestFormat.GlobalTestFormat.Sample(), img); - Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); - - TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, this.decoderOptions, Configuration.Default); + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, Configuration.Default); } [Fact] @@ -443,9 +254,8 @@ namespace ImageSharp.Tests Image img = Image.Load(this.LocalConfiguration, this.FilePath); Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, null)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream)); } @@ -456,45 +266,17 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, null)); - - } - - [Fact] - public void LoadFromFileWithConfigAndOptions() - { - Image img = Image.Load(this.LocalConfiguration, this.FilePath, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, this.decoderOptions)); - - } - - [Fact] - public void LoadFromFileWithTypeAndConfigAndOptions() - { - Image img = Image.Load(this.LocalConfiguration, this.FilePath, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - Assert.Equal(this.localFormat.Object, img.CurrentImageFormat); - - this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(this.LocalConfiguration, this.DataStream)); } - [Fact] public void LoadFromFileWithDecoder() { Image img = Image.Load(this.FilePath, this.localDecoder.Object); Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, null)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream)); } [Fact] @@ -504,26 +286,7 @@ namespace ImageSharp.Tests Assert.NotNull(img); Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, null)); - } - - [Fact] - public void LoadFromFileWithDecoderAndOptions() - { - Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, this.decoderOptions)); - } - - [Fact] - public void LoadFromFileWithTypeAndDecoderAndOptions() - { - Image img = Image.Load(this.FilePath, this.localDecoder.Object, this.decoderOptions); - - Assert.NotNull(img); - Assert.Equal(this.returnImage, img); - this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream, this.decoderOptions)); + this.localDecoder.Verify(x => x.Decode(Configuration.Default, this.DataStream)); } [Fact] diff --git a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs index 9e9852cb2c..eecb983800 100644 --- a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs @@ -22,37 +22,32 @@ namespace ImageSharp.Tests { private readonly Image Image; private readonly Mock fileSystem; - private readonly Mock format; - private readonly Mock formatNotRegistered; private readonly Mock encoder; private readonly Mock encoderNotInFormat; - private readonly IEncoderOptions encoderOptions; + private Mock localMimeTypeDetector; + private Mock localImageFormat; public ImageSaveTests() { - this.encoder = new Mock(); - this.format = new Mock(); - this.format.Setup(x => x.Encoder).Returns(this.encoder.Object); - this.format.Setup(x => x.Decoder).Returns(new Mock().Object); - this.format.Setup(x => x.MimeType).Returns("img/test"); - this.format.Setup(x => x.Extension).Returns("png"); - this.format.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); + this.localImageFormat = new Mock(); + this.localImageFormat.Setup(x => x.FileExtensions).Returns(new[] { "png" }); + + this.localMimeTypeDetector = new Mock(); + this.localMimeTypeDetector.Setup(x => x.HeaderSize).Returns(1); + this.localMimeTypeDetector.Setup(x => x.DetectFormat(It.IsAny>())).Returns(localImageFormat.Object); + this.encoder = new Mock(); this.encoderNotInFormat = new Mock(); - this.formatNotRegistered = new Mock(); - this.formatNotRegistered.Setup(x => x.Encoder).Returns(this.encoderNotInFormat.Object); - this.formatNotRegistered.Setup(x => x.Decoder).Returns(new Mock().Object); - this.formatNotRegistered.Setup(x => x.MimeType).Returns("img/test"); - this.formatNotRegistered.Setup(x => x.Extension).Returns("png"); - this.formatNotRegistered.Setup(x => x.SupportedExtensions).Returns(new string[] { "png", "jpg" }); this.fileSystem = new Mock(); - this.encoderOptions = new Mock().Object; - this.Image = new Image(new Configuration(this.format.Object) + var config = new Configuration() { FileSystem = this.fileSystem.Object - }, 1, 1); + }; + config.AddImageFormatDetector(this.localMimeTypeDetector.Object); + config.SetEncoder(localImageFormat.Object, this.encoder.Object); + this.Image = new Image(config, 1, 1); } [Fact] @@ -62,19 +57,9 @@ namespace ImageSharp.Tests this.fileSystem.Setup(x => x.Create("path.png")).Returns(stream); this.Image.Save("path.png"); - this.encoder.Verify(x => x.Encode(this.Image, stream, null)); + this.encoder.Verify(x => x.Encode(this.Image, stream)); } - [Fact] - public void SavePathWithOptions() - { - Stream stream = new MemoryStream(); - this.fileSystem.Setup(x => x.Create("path.jpg")).Returns(stream); - - this.Image.Save("path.jpg", this.encoderOptions); - - this.encoder.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); - } [Fact] public void SavePathWithEncoder() @@ -84,61 +69,24 @@ namespace ImageSharp.Tests this.Image.Save("path.jpg", this.encoderNotInFormat.Object); - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, null)); - } - - [Fact] - public void SavePathWithEncoderAndOptions() - { - Stream stream = new MemoryStream(); - this.fileSystem.Setup(x => x.Create("path.jpg")).Returns(stream); - - this.Image.Save("path.jpg", this.encoderNotInFormat.Object, this.encoderOptions); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); - } - - - - [Fact] - public void SavePathWithFormat() - { - Stream stream = new MemoryStream(); - this.fileSystem.Setup(x => x.Create("path.jpg")).Returns(stream); - - this.Image.Save("path.jpg", this.encoderNotInFormat.Object); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, null)); - } - - [Fact] - public void SavePathWithFormatAndOptions() - { - Stream stream = new MemoryStream(); - this.fileSystem.Setup(x => x.Create("path.jpg")).Returns(stream); - - this.Image.Save("path.jpg", this.encoderNotInFormat.Object, this.encoderOptions); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); + this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream)); } [Fact] - public void SaveStream() + public void ToBase64String() { - Stream stream = new MemoryStream(); - this.Image.Save(stream); + var str = this.Image.ToBase64String(localImageFormat.Object); - this.encoder.Verify(x => x.Encode(this.Image, stream, null)); + this.encoder.Verify(x => x.Encode(this.Image, It.IsAny())); } [Fact] - public void SaveStreamWithOptions() + public void SaveStreamWithMime() { Stream stream = new MemoryStream(); + this.Image.Save(stream, localImageFormat.Object); - this.Image.Save(stream, this.encoderOptions); - - this.encoder.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); + this.encoder.Verify(x => x.Encode(this.Image, stream)); } [Fact] @@ -148,37 +96,7 @@ namespace ImageSharp.Tests this.Image.Save(stream, this.encoderNotInFormat.Object); - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, null)); - } - - [Fact] - public void SaveStreamWithEncoderAndOptions() - { - Stream stream = new MemoryStream(); - - this.Image.Save(stream, this.encoderNotInFormat.Object, this.encoderOptions); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); - } - - [Fact] - public void SaveStreamWithFormat() - { - Stream stream = new MemoryStream(); - - this.Image.Save(stream, this.formatNotRegistered.Object); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, null)); - } - - [Fact] - public void SaveStreamWithFormatAndOptions() - { - Stream stream = new MemoryStream(); - - this.Image.Save(stream, this.formatNotRegistered.Object, this.encoderOptions); - - this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream, this.encoderOptions)); + this.encoderNotInFormat.Verify(x => x.Encode(this.Image, stream)); } public void Dispose() diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index a3ec4cec21..3157c27d8d 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -74,10 +74,9 @@ namespace ImageSharp.Tests image.Save(file); } - TestFile c = TestFile.Create("../../TestOutput/Save_DetecedEncoding.png"); - using (Image img = c.CreateImage()) + using (Image img = Image.Load(file, out var mime)) { - Assert.IsType(img.CurrentImageFormat); + Assert.Equal("image/png", mime.DefaultMimeType); } } @@ -85,7 +84,7 @@ namespace ImageSharp.Tests public void Save_UnknownExtensionsEncoding() { string file = TestFile.GetPath("../../TestOutput/Save_DetecedEncoding.tmp"); - InvalidOperationException ex = Assert.Throws( + NotSupportedException ex = Assert.Throws( () => { using (Image image = new Image(10, 10)) @@ -95,23 +94,6 @@ namespace ImageSharp.Tests }); } - [Fact] - public void Save_SetFormat() - { - string file = TestFile.GetPath("../../TestOutput/Save_SetFormat.dat"); - System.IO.DirectoryInfo dir = System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(file)); - using (Image image = new Image(10, 10)) - { - image.Save(file, new PngFormat()); - } - - TestFile c = TestFile.Create("../../TestOutput/Save_SetFormat.dat"); - using (Image img = c.CreateImage()) - { - Assert.IsType(img.CurrentImageFormat); - } - } - [Fact] public void Save_SetEncoding() { @@ -121,11 +103,9 @@ namespace ImageSharp.Tests { image.Save(file, new PngEncoder()); } - - TestFile c = TestFile.Create("../../TestOutput/Save_SetEncoding.dat"); - using (Image img = c.CreateImage()) + using (Image img = Image.Load(file, out var mime)) { - Assert.IsType(img.CurrentImageFormat); + Assert.Equal("image/png", mime.DefaultMimeType); } } } diff --git a/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs b/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs index a6c4b4545d..b59023340b 100644 --- a/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs +++ b/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs @@ -9,7 +9,7 @@ namespace ImageSharp.Tests using System.Numerics; using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; /// @@ -70,22 +70,6 @@ namespace ImageSharp.Tests } } - // TODO: Need a processor in the library with this signature - private static void Fill(Image image, Rectangle region, TPixel color) - where TPixel : struct, IPixel - { - using (PixelAccessor pixels = image.Lock()) - { - for (int y = region.Top; y < region.Bottom; y++) - { - for (int x = region.Left; x < region.Right; x++) - { - pixels[x, y] = color; - } - } - } - } - [Theory] [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.Xyz)] [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.Zyx)] @@ -98,7 +82,7 @@ namespace ImageSharp.Tests { using (Image srcImage = provider.GetImage()) { - Fill(srcImage, new Rectangle(4, 4, 8, 8), NamedColors.Red); + srcImage.Fill(NamedColors.Red, new Rectangle(4, 4, 8, 8)); using (PixelAccessor srcPixels = srcImage.Lock()) { using (PixelArea area = new PixelArea(8, 8, order)) diff --git a/tests/ImageSharp.Tests/ImageComparer.cs b/tests/ImageSharp.Tests/ImageComparer.cs index 9a30cc3633..6cd80e9e83 100644 --- a/tests/ImageSharp.Tests/ImageComparer.cs +++ b/tests/ImageSharp.Tests/ImageComparer.cs @@ -9,7 +9,7 @@ namespace ImageSharp.Tests using ImageSharp; using ImageSharp.Memory; using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; /// diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index bc64d613ab..c60c8978ce 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -28,7 +28,6 @@ namespace ImageSharp.Tests metaData.HorizontalResolution = 4; metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - metaData.Quality = 24; metaData.RepeatCount = 1; metaData.DisposalMethod = DisposalMethod.RestoreToBackground; @@ -39,7 +38,6 @@ namespace ImageSharp.Tests Assert.Equal(4, clone.HorizontalResolution); Assert.Equal(2, clone.VerticalResolution); Assert.Equal(imageProperty, clone.Properties[0]); - Assert.Equal(24, clone.Quality); Assert.Equal(1, clone.RepeatCount); Assert.Equal(DisposalMethod.RestoreToBackground, clone.DisposalMethod); } diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs index 6f003cc4d6..76bb1cda19 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntryTests.cs @@ -167,7 +167,7 @@ namespace ImageSharp.Tests.Icc [Theory] [MemberData( - nameof(IccTestDataTagDataEntry.MultiLocalizedUnicodeTagDataEntryTestData), + nameof(IccTestDataTagDataEntry.MultiLocalizedUnicodeTagDataEntryTestData_Read), MemberType = typeof(IccTestDataTagDataEntry))] internal void ReadMultiLocalizedUnicodeTagDataEntry(byte[] data, IccMultiLocalizedUnicodeTagDataEntry expected) { diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntryTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntryTests.cs index affe9835e9..ea85bd16df 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntryTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntryTests.cs @@ -154,7 +154,7 @@ namespace ImageSharp.Tests.Icc } [Theory] - [MemberData(nameof(IccTestDataTagDataEntry.MultiLocalizedUnicodeTagDataEntryTestData), MemberType = typeof(IccTestDataTagDataEntry))] + [MemberData(nameof(IccTestDataTagDataEntry.MultiLocalizedUnicodeTagDataEntryTestData_Write), MemberType = typeof(IccTestDataTagDataEntry))] internal void WriteMultiLocalizedUnicodeTagDataEntry(byte[] expected, IccMultiLocalizedUnicodeTagDataEntry data) { IccDataWriter writer = CreateWriter(); diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs index 0db64c47fa..34aa24fa66 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs @@ -10,10 +10,10 @@ namespace ImageSharp.Tests.Icc public class IccReaderTests { [Fact] - public void ReadProfile() + public void ReadProfile_NoEntries() { IccReader reader = CreateReader(); - + IccProfile output = reader.Read(IccTestDataProfiles.Header_Random_Array); Assert.Equal(0, output.Entries.Count); @@ -40,6 +40,18 @@ namespace ImageSharp.Tests.Icc Assert.Equal(header.Version, expected.Version); } + [Fact] + public void ReadProfile_DuplicateEntry() + { + IccReader reader = CreateReader(); + + IccProfile output = reader.Read(IccTestDataProfiles.Profile_Random_Array); + + Assert.Equal(2, output.Entries.Count); + Assert.True(ReferenceEquals(output.Entries[0], output.Entries[1])); + } + + private IccReader CreateReader() { return new IccReader(); diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccWriterTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccWriterTests.cs index 6192e6eaee..7e3f8c0c94 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccWriterTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccWriterTests.cs @@ -10,7 +10,7 @@ namespace ImageSharp.Tests.Icc public class IccWriterTests { [Fact] - public void WriteProfile() + public void WriteProfile_NoEntries() { IccWriter writer = CreateWriter(); @@ -23,6 +23,16 @@ namespace ImageSharp.Tests.Icc Assert.Equal(IccTestDataProfiles.Header_Random_Array, output); } + [Fact] + public void WriteProfile_DuplicateEntry() + { + IccWriter writer = CreateWriter(); + + byte[] output = writer.Write(IccTestDataProfiles.Profile_Random_Val); + + Assert.Equal(IccTestDataProfiles.Profile_Random_Array, output); + } + private IccWriter CreateWriter() { return new IccWriter(); diff --git a/tests/ImageSharp.Tests/Numerics/PointFTests.cs b/tests/ImageSharp.Tests/Numerics/PointFTests.cs deleted file mode 100644 index 3b5a72a14c..0000000000 --- a/tests/ImageSharp.Tests/Numerics/PointFTests.cs +++ /dev/null @@ -1,192 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Tests.Numerics -{ - using System; - using System.Globalization; - using System.Numerics; - using System.Reflection; - using Xunit; - - public class PointFTests - { - [Fact] - public void DefaultConstructorTest() - { - Assert.Equal(PointF.Empty, new PointF()); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - [InlineData(float.MinValue, float.MaxValue)] - [InlineData(0.0, 0.0)] - public void NonDefaultConstructorTest(float x, float y) - { - var p1 = new PointF(x, y); - - Assert.Equal(x, p1.X); - Assert.Equal(y, p1.Y); - } - - [Fact] - public void IsEmptyDefaultsTest() - { - Assert.True(PointF.Empty.IsEmpty); - Assert.True(new PointF().IsEmpty); - Assert.True(new PointF(0, 0).IsEmpty); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - public void IsEmptyRandomTest(float x, float y) - { - Assert.False(new PointF(x, y).IsEmpty); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - [InlineData(0, 0)] - public void CoordinatesTest(float x, float y) - { - var p = new PointF(x, y); - Assert.Equal(x, p.X); - Assert.Equal(y, p.Y); - - p.X = 10; - Assert.Equal(10, p.X); - - p.Y = -10.123f; - Assert.Equal(-10.123, p.Y, 3); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue, int.MaxValue, int.MinValue)] - [InlineData(float.MinValue, float.MaxValue, int.MinValue, int.MaxValue)] - [InlineData(0, 0, 0, 0)] - public void ArithmeticTestWithSize(float x, float y, int x1, int y1) - { - var p = new PointF(x, y); - var s = new Size(x1, y1); - - var addExpected = new PointF(x + x1, y + y1); - var subExpected = new PointF(x - x1, y - y1); - Assert.Equal(addExpected, p + s); - Assert.Equal(subExpected, p - s); - Assert.Equal(addExpected, PointF.Add(p, s)); - Assert.Equal(subExpected, PointF.Subtract(p, s)); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MaxValue)] - [InlineData(0, 0)] - public void ArithmeticTestWithSizeF(float x, float y) - { - var p = new PointF(x, y); - var s = new SizeF(y, x); - - var addExpected = new PointF(x + y, y + x); - var subExpected = new PointF(x - y, y - x); - Assert.Equal(addExpected, p + s); - Assert.Equal(subExpected, p - s); - Assert.Equal(addExpected, PointF.Add(p, s)); - Assert.Equal(subExpected, PointF.Subtract(p, s)); - } - - [Fact] - public void RotateTest() - { - var p = new PointF(13, 17); - Matrix3x2 matrix = Matrix3x2Extensions.CreateRotation(45, PointF.Empty); - - var pout = PointF.Rotate(p, matrix); - - Assert.Equal(new PointF(-2.82842732F, 21.2132034F), pout); - } - - [Fact] - public void SkewTest() - { - var p = new PointF(13, 17); - Matrix3x2 matrix = Matrix3x2Extensions.CreateSkew(45, 45, PointF.Empty); - - var pout = PointF.Skew(p, matrix); - Assert.Equal(new PointF(30, 30), pout); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MaxValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - [InlineData(0, 0)] - public void EqualityTest(float x, float y) - { - var pLeft = new PointF(x, y); - var pRight = new PointF(y, x); - - if (x == y) - { - Assert.True(pLeft == pRight); - Assert.False(pLeft != pRight); - Assert.True(pLeft.Equals(pRight)); - Assert.True(pLeft.Equals((object)pRight)); - Assert.Equal(pLeft.GetHashCode(), pRight.GetHashCode()); - return; - } - - Assert.True(pLeft != pRight); - Assert.False(pLeft == pRight); - Assert.False(pLeft.Equals(pRight)); - Assert.False(pLeft.Equals((object)pRight)); - } - - [Fact] - public static void EqualityTest_NotPointF() - { - var point = new PointF(0, 0); - Assert.False(point.Equals(null)); - Assert.False(point.Equals(0)); - - // If PointF implements IEquatable (e.g. in .NET Core), then structs that are implicitly - // convertible to var can potentially be equal. - // See https://github.com/dotnet/corefx/issues/5255. - bool expectsImplicitCastToPointF = typeof(IEquatable).IsAssignableFrom(point.GetType()); - Assert.Equal(expectsImplicitCastToPointF, point.Equals(new Point(0, 0))); - - Assert.False(point.Equals((object)new Point(0, 0))); // No implicit cast - } - - [Fact] - public static void GetHashCodeTest() - { - var point = new PointF(10, 10); - Assert.Equal(point.GetHashCode(), new PointF(10, 10).GetHashCode()); - Assert.NotEqual(point.GetHashCode(), new PointF(20, 10).GetHashCode()); - Assert.NotEqual(point.GetHashCode(), new PointF(10, 20).GetHashCode()); - } - - [Fact] - public void ToStringTest() - { - var p = new PointF(5.1F, -5.123F); - Assert.Equal(string.Format(CultureInfo.CurrentCulture, "PointF [ X={0}, Y={1} ]", p.X, p.Y), p.ToString()); - } - - [Fact] - public void ToStringEmptyTest() - { - var p = new PointF(0, 0); - Assert.Equal("PointF [ Empty ]", p.ToString()); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Numerics/PointTests.cs b/tests/ImageSharp.Tests/Numerics/PointTests.cs deleted file mode 100644 index 9f7abe067a..0000000000 --- a/tests/ImageSharp.Tests/Numerics/PointTests.cs +++ /dev/null @@ -1,252 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Tests -{ - using System.Globalization; - using System.Numerics; - - using Xunit; - - public class PointTests - { - [Fact] - public void DefaultConstructorTest() - { - Assert.Equal(Point.Empty, new Point()); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void NonDefaultConstructorTest(int x, int y) - { - var p1 = new Point(x, y); - var p2 = new Point(new Size(x, y)); - - Assert.Equal(p1, p2); - } - - [Theory] - [InlineData(int.MaxValue)] - [InlineData(int.MinValue)] - [InlineData(0)] - public void SingleIntConstructorTest(int x) - { - var p1 = new Point(x); - var p2 = new Point(unchecked((short)(x & 0xFFFF)), unchecked((short)((x >> 16) & 0xFFFF))); - - Assert.Equal(p1, p2); - } - - [Fact] - public void IsEmptyDefaultsTest() - { - Assert.True(Point.Empty.IsEmpty); - Assert.True(new Point().IsEmpty); - Assert.True(new Point(0, 0).IsEmpty); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - public void IsEmptyRandomTest(int x, int y) - { - Assert.False(new Point(x, y).IsEmpty); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void CoordinatesTest(int x, int y) - { - var p = new Point(x, y); - Assert.Equal(x, p.X); - Assert.Equal(y, p.Y); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void PointFConversionTest(int x, int y) - { - PointF p = new Point(x, y); - Assert.Equal(new PointF(x, y), p); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void SizeConversionTest(int x, int y) - { - var sz = (Size)new Point(x, y); - Assert.Equal(new Size(x, y), sz); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void ArithmeticTest(int x, int y) - { - Point addExpected, subExpected, p = new Point(x, y); - var s = new Size(y, x); - - unchecked - { - addExpected = new Point(x + y, y + x); - subExpected = new Point(x - y, y - x); - } - - Assert.Equal(addExpected, p + s); - Assert.Equal(subExpected, p - s); - Assert.Equal(addExpected, Point.Add(p, s)); - Assert.Equal(subExpected, Point.Subtract(p, s)); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - [InlineData(0, 0)] - public void PointFMathematicalTest(float x, float y) - { - var pf = new PointF(x, y); - Point pCeiling, pTruncate, pRound; - - unchecked - { - pCeiling = new Point((int)MathF.Ceiling(x), (int)MathF.Ceiling(y)); - pTruncate = new Point((int)x, (int)y); - pRound = new Point((int)MathF.Round(x), (int)MathF.Round(y)); - } - - Assert.Equal(pCeiling, Point.Ceiling(pf)); - Assert.Equal(pRound, Point.Round(pf)); - Assert.Equal(pTruncate, (Point)pf); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void OffsetTest(int x, int y) - { - var p1 = new Point(x, y); - var p2 = new Point(y, x); - - p1.Offset(p2); - - Assert.Equal(unchecked(p2.X + p2.Y), p1.X); - Assert.Equal(p1.X, p1.Y); - - p2.Offset(x, y); - Assert.Equal(p1, p2); - } - - [Fact] - public void RotateTest() - { - var p = new Point(13, 17); - Matrix3x2 matrix = Matrix3x2Extensions.CreateRotation(45, Point.Empty); - - var pout = Point.Rotate(p, matrix); - - Assert.Equal(new Point(-3, 21), pout); - } - - [Fact] - public void SkewTest() - { - var p = new Point(13, 17); - Matrix3x2 matrix = Matrix3x2Extensions.CreateSkew(45, 45, Point.Empty); - - var pout = Point.Skew(p, matrix); - Assert.Equal(new Point(30, 30), pout); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void EqualityTest(int x, int y) - { - var p1 = new Point(x, y); - var p2 = new Point(x / 2 - 1, y / 2 - 1); - var p3 = new Point(x, y); - - Assert.True(p1 == p3); - Assert.True(p1 != p2); - Assert.True(p2 != p3); - - Assert.True(p1.Equals(p3)); - Assert.False(p1.Equals(p2)); - Assert.False(p2.Equals(p3)); - - Assert.True(p1.Equals((object)p3)); - Assert.False(p1.Equals((object)p2)); - Assert.False(p2.Equals((object)p3)); - - Assert.Equal(p1.GetHashCode(), p3.GetHashCode()); - } - - [Fact] - public static void EqualityTest_NotPoint() - { - var point = new Point(0, 0); - Assert.False(point.Equals(null)); - Assert.False(point.Equals(0)); - Assert.False(point.Equals(new PointF(0, 0))); - } - - [Fact] - public static void GetHashCodeTest() - { - var point = new Point(10, 10); - Assert.Equal(point.GetHashCode(), new Point(10, 10).GetHashCode()); - Assert.NotEqual(point.GetHashCode(), new Point(20, 10).GetHashCode()); - Assert.NotEqual(point.GetHashCode(), new Point(10, 20).GetHashCode()); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(1, -2, 3, -4)] - public void ConversionTest(int x, int y, int width, int height) - { - var rect = new Rectangle(x, y, width, height); - RectangleF rectF = rect; - Assert.Equal(x, rectF.X); - Assert.Equal(y, rectF.Y); - Assert.Equal(width, rectF.Width); - Assert.Equal(height, rectF.Height); - } - - [Fact] - public void ToStringTest() - { - var p = new Point(5, -5); - Assert.Equal(string.Format(CultureInfo.CurrentCulture, "Point [ X={0}, Y={1} ]", p.X, p.Y), p.ToString()); - } - - [Fact] - public void ToStringEmptyTest() - { - var p = new Point(0, 0); - Assert.Equal("Point [ Empty ]", p.ToString()); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Numerics/RectangleFTests.cs b/tests/ImageSharp.Tests/Numerics/RectangleFTests.cs deleted file mode 100644 index 78fbc68f62..0000000000 --- a/tests/ImageSharp.Tests/Numerics/RectangleFTests.cs +++ /dev/null @@ -1,268 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Tests -{ - using System; - using System.Globalization; - using System.Reflection; - - using Xunit; - - /// - /// Tests the struct. - /// - public class RectangleFTests - { - [Fact] - public void DefaultConstructorTest() - { - Assert.Equal(RectangleF.Empty, new RectangleF()); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)] - [InlineData(float.MaxValue, 0, 0, float.MaxValue)] - [InlineData(0, float.MinValue, float.MaxValue, 0)] - public void NonDefaultConstructorTest(float x, float y, float width, float height) - { - var rect1 = new RectangleF(x, y, width, height); - var p = new PointF(x, y); - var s = new SizeF(width, height); - var rect2 = new RectangleF(p, s); - - Assert.Equal(rect1, rect2); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)] - [InlineData(float.MaxValue, 0, 0, float.MaxValue)] - [InlineData(0, float.MinValue, float.MaxValue, 0)] - public void FromLTRBTest(float left, float top, float right, float bottom) - { - var expected = new RectangleF(left, top, right - left, bottom - top); - var actual = RectangleF.FromLTRB(left, top, right, bottom); - - Assert.Equal(expected, actual); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)] - [InlineData(float.MaxValue, 0, 0, float.MaxValue)] - [InlineData(0, float.MinValue, float.MaxValue, 0)] - public void DimensionsTest(float x, float y, float width, float height) - { - var rect = new RectangleF(x, y, width, height); - var p = new PointF(x, y); - var s = new SizeF(width, height); - - Assert.Equal(p, rect.Location); - Assert.Equal(s, rect.Size); - Assert.Equal(x, rect.X); - Assert.Equal(y, rect.Y); - Assert.Equal(width, rect.Width); - Assert.Equal(height, rect.Height); - Assert.Equal(x, rect.Left); - Assert.Equal(y, rect.Top); - Assert.Equal(x + width, rect.Right); - Assert.Equal(y + height, rect.Bottom); - } - - [Fact] - public void IsEmptyTest() - { - Assert.True(RectangleF.Empty.IsEmpty); - Assert.True(new RectangleF().IsEmpty); - Assert.True(new RectangleF(1, -2, -10, 10).IsEmpty); - Assert.True(new RectangleF(1, -2, 10, -10).IsEmpty); - Assert.True(new RectangleF(1, -2, 0, 0).IsEmpty); - - Assert.False(new RectangleF(0, 0, 10, 10).IsEmpty); - } - - [Theory] - [InlineData(0, 0)] - [InlineData(float.MaxValue, float.MinValue)] - public static void LocationSetTest(float x, float y) - { - var point = new PointF(x, y); - var rect = new RectangleF(10, 10, 10, 10) { Location = point }; - Assert.Equal(point, rect.Location); - Assert.Equal(point.X, rect.X); - Assert.Equal(point.Y, rect.Y); - } - - [Theory] - [InlineData(0, 0)] - [InlineData(float.MaxValue, float.MinValue)] - public static void SizeSetTest(float x, float y) - { - var size = new SizeF(x, y); - var rect = new RectangleF(10, 10, 10, 10) { Size = size }; - Assert.Equal(size, rect.Size); - Assert.Equal(size.Width, rect.Width); - Assert.Equal(size.Height, rect.Height); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)] - [InlineData(float.MaxValue, 0, 0, float.MaxValue)] - [InlineData(0, float.MinValue, float.MaxValue, 0)] - public void EqualityTest(float x, float y, float width, float height) - { - var rect1 = new RectangleF(x, y, width, height); - var rect2 = new RectangleF(width, height, x, y); - - Assert.True(rect1 != rect2); - Assert.False(rect1 == rect2); - Assert.False(rect1.Equals(rect2)); - Assert.False(rect1.Equals((object)rect2)); - } - - [Fact] - public static void EqualityTestNotRectangleF() - { - var rectangle = new RectangleF(0, 0, 0, 0); - Assert.False(rectangle.Equals(null)); - Assert.False(rectangle.Equals(0)); - - // If RectangleF implements IEquatable (e.g. in .NET Core), then classes that are implicitly - // convertible to RectangleF can potentially be equal. - // See https://github.com/dotnet/corefx/issues/5255. - bool expectsImplicitCastToRectangleF = typeof(IEquatable).IsAssignableFrom(rectangle.GetType()); - Assert.Equal(expectsImplicitCastToRectangleF, rectangle.Equals(new Rectangle(0, 0, 0, 0))); - - Assert.False(rectangle.Equals((object)new Rectangle(0, 0, 0, 0))); // No implicit cast - } - - [Fact] - public static void GetHashCodeTest() - { - var rect1 = new RectangleF(10, 10, 10, 10); - var rect2 = new RectangleF(10, 10, 10, 10); - Assert.Equal(rect1.GetHashCode(), rect2.GetHashCode()); - Assert.NotEqual(rect1.GetHashCode(), new RectangleF(20, 10, 10, 10).GetHashCode()); - Assert.NotEqual(rect1.GetHashCode(), new RectangleF(10, 20, 10, 10).GetHashCode()); - Assert.NotEqual(rect1.GetHashCode(), new RectangleF(10, 10, 20, 10).GetHashCode()); - Assert.NotEqual(rect1.GetHashCode(), new RectangleF(10, 10, 10, 20).GetHashCode()); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)] - [InlineData(0, float.MinValue, float.MaxValue, 0)] - public void ContainsTest(float x, float y, float width, float height) - { - var rect = new RectangleF(x, y, width, height); - float X = (x + width) / 2; - float Y = (y + height) / 2; - var p = new PointF(X, Y); - var r = new RectangleF(X, Y, width / 2, height / 2); - - Assert.False(rect.Contains(X, Y)); - Assert.False(rect.Contains(p)); - Assert.False(rect.Contains(r)); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(float.MaxValue / 2, float.MinValue / 2, float.MinValue / 2, float.MaxValue / 2)] - [InlineData(0, float.MinValue, float.MaxValue, 0)] - public void InflateTest(float x, float y, float width, float height) - { - var rect = new RectangleF(x, y, width, height); - var inflatedRect = new RectangleF(x - width, y - height, width + 2 * width, height + 2 * height); - - rect.Inflate(width, height); - Assert.Equal(inflatedRect, rect); - - var s = new SizeF(x, y); - inflatedRect = RectangleF.Inflate(rect, x, y); - - rect.Inflate(s); - Assert.Equal(inflatedRect, rect); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue, float.MaxValue / 2, float.MinValue / 2)] - [InlineData(0, float.MinValue, float.MaxValue, 0)] - public void IntersectTest(float x, float y, float width, float height) - { - var rect1 = new RectangleF(x, y, width, height); - var rect2 = new RectangleF(y, x, width, height); - var expectedRect = RectangleF.Intersect(rect1, rect2); - rect1.Intersect(rect2); - Assert.Equal(expectedRect, rect1); - Assert.False(rect1.IntersectsWith(expectedRect)); - } - - [Fact] - public static void IntersectIntersectingRectsTest() - { - var rect1 = new RectangleF(0, 0, 5, 5); - var rect2 = new RectangleF(1, 1, 3, 3); - var expected = new RectangleF(1, 1, 3, 3); - - Assert.Equal(expected, RectangleF.Intersect(rect1, rect2)); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)] - [InlineData(float.MaxValue, 0, 0, float.MaxValue)] - [InlineData(0, float.MinValue, float.MaxValue, 0)] - public void UnionTest(float x, float y, float width, float height) - { - var a = new RectangleF(x, y, width, height); - var b = new RectangleF(width, height, x, y); - - float x1 = Math.Min(a.X, b.X); - float x2 = Math.Max(a.X + a.Width, b.X + b.Width); - float y1 = Math.Min(a.Y, b.Y); - float y2 = Math.Max(a.Y + a.Height, b.Y + b.Height); - - var expectedRectangle = new RectangleF(x1, y1, x2 - x1, y2 - y1); - - Assert.Equal(expectedRectangle, RectangleF.Union(a, b)); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)] - [InlineData(float.MaxValue, 0, 0, float.MaxValue)] - [InlineData(0, float.MinValue, float.MaxValue, 0)] - public void OffsetTest(float x, float y, float width, float height) - { - var r1 = new RectangleF(x, y, width, height); - var expectedRect = new RectangleF(x + width, y + height, width, height); - var p = new PointF(width, height); - - r1.Offset(p); - Assert.Equal(expectedRect, r1); - - expectedRect.Offset(p); - r1.Offset(width, height); - Assert.Equal(expectedRect, r1); - } - - [Fact] - public void ToStringTest() - { - var r = new RectangleF(5, 5.1F, 1.3F, 1); - Assert.Equal(string.Format(CultureInfo.CurrentCulture, "RectangleF [ X={0}, Y={1}, Width={2}, Height={3} ]", r.X, r.Y, r.Width, r.Height), r.ToString()); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(5, -5, 0.2, -1.3)] - public void ToStringTestEmpty(float x, float y, float width, float height) - { - var r = new RectangleF(x, y, width, height); - Assert.Equal("RectangleF [ Empty ]", r.ToString()); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Numerics/RectangleTests.cs b/tests/ImageSharp.Tests/Numerics/RectangleTests.cs deleted file mode 100644 index 1ef03f0c64..0000000000 --- a/tests/ImageSharp.Tests/Numerics/RectangleTests.cs +++ /dev/null @@ -1,308 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Tests -{ - using System; - using System.Globalization; - - using Xunit; - - /// - /// Tests the struct. - /// - public class RectangleTests - { - [Fact] - public void DefaultConstructorTest() - { - Assert.Equal(Rectangle.Empty, new Rectangle()); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue, int.MaxValue, int.MinValue)] - [InlineData(int.MaxValue, 0, int.MinValue, 0)] - [InlineData(0, 0, 0, 0)] - [InlineData(0, int.MinValue, 0, int.MaxValue)] - public void NonDefaultConstructorTest(int x, int y, int width, int height) - { - var rect1 = new Rectangle(x, y, width, height); - var rect2 = new Rectangle(new Point(x, y), new Size(width, height)); - - Assert.Equal(rect1, rect2); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue, int.MaxValue, int.MinValue)] - [InlineData(int.MaxValue, 0, int.MinValue, 0)] - [InlineData(0, 0, 0, 0)] - [InlineData(0, int.MinValue, 0, int.MaxValue)] - public void FromLTRBTest(int left, int top, int right, int bottom) - { - var rect1 = new Rectangle(left, top, unchecked(right - left), unchecked(bottom - top)); - var rect2 = Rectangle.FromLTRB(left, top, right, bottom); - - Assert.Equal(rect1, rect2); - } - - [Fact] - public void EmptyTest() - { - Assert.True(Rectangle.Empty.IsEmpty); - Assert.True(new Rectangle(0, 0, 0, 0).IsEmpty); - Assert.True(new Rectangle().IsEmpty); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue, int.MaxValue, int.MinValue)] - [InlineData(int.MaxValue, 0, int.MinValue, 0)] - [InlineData(int.MinValue, int.MaxValue, int.MinValue, int.MaxValue)] - [InlineData(0, int.MinValue, 0, int.MaxValue)] - public void NonEmptyTest(int x, int y, int width, int height) - { - Assert.False(new Rectangle(x, y, width, height).IsEmpty); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue, int.MaxValue, int.MinValue)] - [InlineData(int.MaxValue, 0, int.MinValue, 0)] - [InlineData(0, 0, 0, 0)] - [InlineData(0, int.MinValue, 0, int.MaxValue)] - [InlineData(int.MinValue, int.MaxValue, int.MinValue, int.MaxValue)] - public void DimensionsTest(int x, int y, int width, int height) - { - var rect = new Rectangle(x, y, width, height); - Assert.Equal(new Point(x, y), rect.Location); - Assert.Equal(new Size(width, height), rect.Size); - - Assert.Equal(x, rect.X); - Assert.Equal(y, rect.Y); - Assert.Equal(width, rect.Width); - Assert.Equal(height, rect.Height); - Assert.Equal(x, rect.Left); - Assert.Equal(y, rect.Top); - Assert.Equal(unchecked(x + width), rect.Right); - Assert.Equal(unchecked(y + height), rect.Bottom); - - var p = new Point(width, height); - var s = new Size(x, y); - rect.Location = p; - rect.Size = s; - - Assert.Equal(p, rect.Location); - Assert.Equal(s, rect.Size); - - Assert.Equal(width, rect.X); - Assert.Equal(height, rect.Y); - Assert.Equal(x, rect.Width); - Assert.Equal(y, rect.Height); - Assert.Equal(width, rect.Left); - Assert.Equal(height, rect.Top); - Assert.Equal(unchecked(x + width), rect.Right); - Assert.Equal(unchecked(y + height), rect.Bottom); - } - - [Theory] - [InlineData(0, 0)] - [InlineData(int.MaxValue, int.MinValue)] - public static void LocationSetTest(int x, int y) - { - var point = new Point(x, y); - var rect = new Rectangle(10, 10, 10, 10) { Location = point }; - Assert.Equal(point, rect.Location); - Assert.Equal(point.X, rect.X); - Assert.Equal(point.Y, rect.Y); - } - - [Theory] - [InlineData(0, 0)] - [InlineData(int.MaxValue, int.MinValue)] - public static void SizeSetTest(int x, int y) - { - var size = new Size(x, y); - var rect = new Rectangle(10, 10, 10, 10) { Size = size }; - Assert.Equal(size, rect.Size); - Assert.Equal(size.Width, rect.Width); - Assert.Equal(size.Height, rect.Height); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue, int.MaxValue, int.MinValue)] - [InlineData(int.MaxValue, 0, int.MinValue, 0)] - [InlineData(0, int.MinValue, 0, int.MaxValue)] - [InlineData(int.MinValue, int.MaxValue, int.MinValue, int.MaxValue)] - public void EqualityTest(int x, int y, int width, int height) - { - var rect1 = new Rectangle(x, y, width, height); - var rect2 = new Rectangle(width / 2, height / 2, x, y); - - Assert.True(rect1 != rect2); - Assert.False(rect1 == rect2); - Assert.False(rect1.Equals(rect2)); - Assert.False(rect1.Equals((object)rect2)); - } - - [Fact] - public static void EqualityTestNotRectangle() - { - var rectangle = new Rectangle(0, 0, 0, 0); - Assert.False(rectangle.Equals(null)); - Assert.False(rectangle.Equals(0)); - Assert.False(rectangle.Equals(new RectangleF(0, 0, 0, 0))); - } - - [Fact] - public static void GetHashCodeTest() - { - var rect1 = new Rectangle(10, 10, 10, 10); - var rect2 = new Rectangle(10, 10, 10, 10); - Assert.Equal(rect1.GetHashCode(), rect2.GetHashCode()); - Assert.NotEqual(rect1.GetHashCode(), new Rectangle(20, 10, 10, 10).GetHashCode()); - Assert.NotEqual(rect1.GetHashCode(), new Rectangle(10, 20, 10, 10).GetHashCode()); - Assert.NotEqual(rect1.GetHashCode(), new Rectangle(10, 10, 20, 10).GetHashCode()); - Assert.NotEqual(rect1.GetHashCode(), new Rectangle(10, 10, 10, 20).GetHashCode()); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue, float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MaxValue, float.MinValue, float.MaxValue)] - [InlineData(0, 0, 0, 0)] - public void RectangleFConversionTest(float x, float y, float width, float height) - { - var rect = new RectangleF(x, y, width, height); - Rectangle rCeiling, rTruncate, rRound; - - unchecked - { - rCeiling = new Rectangle((int)Math.Ceiling(x), (int)Math.Ceiling(y), - (int)Math.Ceiling(width), (int)Math.Ceiling(height)); - rTruncate = new Rectangle((int)x, (int)y, (int)width, (int)height); - rRound = new Rectangle((int)Math.Round(x), (int)Math.Round(y), - (int)Math.Round(width), (int)Math.Round(height)); - } - - Assert.Equal(rCeiling, Rectangle.Ceiling(rect)); - Assert.Equal(rTruncate, Rectangle.Truncate(rect)); - Assert.Equal(rRound, Rectangle.Round(rect)); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue, int.MinValue, int.MaxValue)] - [InlineData(0, int.MinValue, int.MaxValue, 0)] - public void ContainsTest(int x, int y, int width, int height) - { - var rect = new Rectangle(unchecked(2 * x - width), unchecked(2 * y - height), width, height); - var p = new Point(x, y); - var r = new Rectangle(x, y, width / 2, height / 2); - - Assert.False(rect.Contains(x, y)); - Assert.False(rect.Contains(p)); - Assert.False(rect.Contains(r)); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(int.MaxValue, int.MinValue, int.MinValue, int.MaxValue)] - [InlineData(0, int.MinValue, int.MaxValue, 0)] - public void InflateTest(int x, int y, int width, int height) - { - Rectangle inflatedRect, rect = new Rectangle(x, y, width, height); - unchecked - { - inflatedRect = new Rectangle(x - width, y - height, width + 2 * width, height + 2 * height); - } - - Assert.Equal(inflatedRect, Rectangle.Inflate(rect, width, height)); - - rect.Inflate(width, height); - Assert.Equal(inflatedRect, rect); - - var s = new Size(x, y); - unchecked - { - inflatedRect = new Rectangle(rect.X - x, rect.Y - y, rect.Width + 2 * x, rect.Height + 2 * y); - } - - rect.Inflate(s); - Assert.Equal(inflatedRect, rect); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(int.MaxValue, int.MinValue, int.MinValue, int.MaxValue)] - [InlineData(0, int.MinValue, int.MaxValue, 0)] - public void IntersectTest(int x, int y, int width, int height) - { - var rect = new Rectangle(x, y, width, height); - var expectedRect = Rectangle.Intersect(rect, rect); - rect.Intersect(rect); - Assert.Equal(expectedRect, rect); - Assert.False(rect.IntersectsWith(expectedRect)); - } - - [Fact] - public static void IntersectIntersectingRectsTest() - { - var rect1 = new Rectangle(0, 0, 5, 5); - var rect2 = new Rectangle(1, 1, 3, 3); - var expected = new Rectangle(1, 1, 3, 3); - - Assert.Equal(expected, Rectangle.Intersect(rect1, rect2)); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(int.MaxValue, int.MinValue, int.MinValue, int.MaxValue)] - [InlineData(int.MaxValue, 0, 0, int.MaxValue)] - [InlineData(0, int.MinValue, int.MaxValue, 0)] - public void UnionTest(int x, int y, int width, int height) - { - var a = new Rectangle(x, y, width, height); - var b = new Rectangle(width, height, x, y); - - int x1 = Math.Min(a.X, b.X); - int x2 = Math.Max(a.X + a.Width, b.X + b.Width); - int y1 = Math.Min(a.Y, b.Y); - int y2 = Math.Max(a.Y + a.Height, b.Y + b.Height); - - var expectedRectangle = new Rectangle(x1, y1, x2 - x1, y2 - y1); - - Assert.Equal(expectedRectangle, Rectangle.Union(a, b)); - } - - [Theory] - [InlineData(0, 0, 0, 0)] - [InlineData(int.MaxValue, int.MinValue, int.MinValue, int.MaxValue)] - [InlineData(int.MaxValue, 0, 0, int.MaxValue)] - [InlineData(0, int.MinValue, int.MaxValue, 0)] - public void OffsetTest(int x, int y, int width, int height) - { - var r1 = new Rectangle(x, y, width, height); - var expectedRect = new Rectangle(x + width, y + height, width, height); - var p = new Point(width, height); - - r1.Offset(p); - Assert.Equal(expectedRect, r1); - - expectedRect.Offset(p); - r1.Offset(width, height); - Assert.Equal(expectedRect, r1); - } - - [Fact] - public void ToStringTest() - { - var r = new Rectangle(5, -5, 0, 1); - Assert.Equal(string.Format(CultureInfo.CurrentCulture, "Rectangle [ X={0}, Y={1}, Width={2}, Height={3} ]", r.X, r.Y, r.Width, r.Height), r.ToString()); - } - - [Fact] - public void ToStringTestEmpty() - { - var r = new Rectangle(0, 0, 0, 0); - Assert.Equal("Rectangle [ Empty ]", r.ToString()); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Numerics/SizeFTests.cs b/tests/ImageSharp.Tests/Numerics/SizeFTests.cs deleted file mode 100644 index dfeee762f5..0000000000 --- a/tests/ImageSharp.Tests/Numerics/SizeFTests.cs +++ /dev/null @@ -1,163 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Tests -{ - using System; - using System.Globalization; - using System.Reflection; - using Xunit; - - public class SizeFTests - { - [Fact] - public void DefaultConstructorTest() - { - Assert.Equal(SizeF.Empty, new SizeF()); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - [InlineData(0, 0)] - public void NonDefaultConstructorAndDimensionsTest(float width, float height) - { - var s1 = new SizeF(width, height); - var p1 = new PointF(width, height); - var s2 = new SizeF(s1); - - Assert.Equal(s1, s2); - Assert.Equal(s1, new SizeF(p1)); - Assert.Equal(s2, new SizeF(p1)); - - Assert.Equal(width, s1.Width); - Assert.Equal(height, s1.Height); - - s1.Width = 10; - Assert.Equal(10, s1.Width); - - s1.Height = -10.123f; - Assert.Equal(-10.123, s1.Height, 3); - } - - [Fact] - public void IsEmptyDefaultsTest() - { - Assert.True(SizeF.Empty.IsEmpty); - Assert.True(new SizeF().IsEmpty); - Assert.True(new SizeF(0, 0).IsEmpty); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - public void IsEmptyRandomTest(float width, float height) - { - Assert.False(new SizeF(width, height).IsEmpty); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - [InlineData(0, 0)] - public void ArithmeticTest(float width, float height) - { - var s1 = new SizeF(width, height); - var s2 = new SizeF(height, width); - var addExpected = new SizeF(width + height, width + height); - var subExpected = new SizeF(width - height, height - width); - - Assert.Equal(addExpected, s1 + s2); - Assert.Equal(addExpected, SizeF.Add(s1, s2)); - - Assert.Equal(subExpected, s1 - s2); - Assert.Equal(subExpected, SizeF.Subtract(s1, s2)); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - [InlineData(0, 0)] - public void EqualityTest(float width, float height) - { - var sLeft = new SizeF(width, height); - var sRight = new SizeF(height, width); - - if (width == height) - { - Assert.True(sLeft == sRight); - Assert.False(sLeft != sRight); - Assert.True(sLeft.Equals(sRight)); - Assert.True(sLeft.Equals((object)sRight)); - Assert.Equal(sLeft.GetHashCode(), sRight.GetHashCode()); - return; - } - - Assert.True(sLeft != sRight); - Assert.False(sLeft == sRight); - Assert.False(sLeft.Equals(sRight)); - Assert.False(sLeft.Equals((object)sRight)); - } - - [Fact] - public static void EqualityTest_NotSizeF() - { - var size = new SizeF(0, 0); - Assert.False(size.Equals(null)); - Assert.False(size.Equals(0)); - - // If SizeF implements IEquatable (e.g in .NET Core), then classes that are implicitly - // convertible to SizeF can potentially be equal. - // See https://github.com/dotnet/corefx/issues/5255. - bool expectsImplicitCastToSizeF = typeof(IEquatable).IsAssignableFrom(size.GetType()); - Assert.Equal(expectsImplicitCastToSizeF, size.Equals(new Size(0, 0))); - - Assert.False(size.Equals((object)new Size(0, 0))); // No implicit cast - } - - [Fact] - public static void GetHashCodeTest() - { - var size = new SizeF(10, 10); - Assert.Equal(size.GetHashCode(), new SizeF(10, 10).GetHashCode()); - Assert.NotEqual(size.GetHashCode(), new SizeF(20, 10).GetHashCode()); - Assert.NotEqual(size.GetHashCode(), new SizeF(10, 20).GetHashCode()); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - [InlineData(0, 0)] - public void ConversionTest(float width, float height) - { - var s1 = new SizeF(width, height); - var p1 = (PointF)s1; - var s2 = new Size(unchecked((int)width), unchecked((int)height)); - - Assert.Equal(new PointF(width, height), p1); - Assert.Equal(p1, (PointF)s1); - Assert.Equal(s2, (Size)s1); - } - - [Fact] - public void ToStringTest() - { - var sz = new SizeF(10, 5); - Assert.Equal(string.Format(CultureInfo.CurrentCulture, "SizeF [ Width={0}, Height={1} ]", sz.Width, sz.Height), sz.ToString()); - } - - [Fact] - public void ToStringTestEmpty() - { - var sz = new SizeF(0, 0); - Assert.Equal("SizeF [ Empty ]", sz.ToString()); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Numerics/SizeTests.cs b/tests/ImageSharp.Tests/Numerics/SizeTests.cs deleted file mode 100644 index 010cdad3c4..0000000000 --- a/tests/ImageSharp.Tests/Numerics/SizeTests.cs +++ /dev/null @@ -1,195 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp.Tests -{ - using System.Globalization; - using Xunit; - - /// - /// Tests the struct. - /// - public class SizeTests - { - [Fact] - public void DefaultConstructorTest() - { - Assert.Equal(Size.Empty, new Size()); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void NonDefaultConstructorTest(int width, int height) - { - var s1 = new Size(width, height); - var s2 = new Size(new Point(width, height)); - - Assert.Equal(s1, s2); - - s1.Width = 10; - Assert.Equal(10, s1.Width); - - s1.Height = -10; - Assert.Equal(-10, s1.Height); - } - - [Fact] - public void IsEmptyDefaultsTest() - { - Assert.True(Size.Empty.IsEmpty); - Assert.True(new Size().IsEmpty); - Assert.True(new Size(0, 0).IsEmpty); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - public void IsEmptyRandomTest(int width, int height) - { - Assert.False(new Size(width, height).IsEmpty); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void DimensionsTest(int width, int height) - { - var p = new Size(width, height); - Assert.Equal(width, p.Width); - Assert.Equal(height, p.Height); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void PointFConversionTest(int width, int height) - { - SizeF sz = new Size(width, height); - Assert.Equal(new SizeF(width, height), sz); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void SizeConversionTest(int width, int height) - { - var sz = (Point)new Size(width, height); - Assert.Equal(new Point(width, height), sz); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void ArithmeticTest(int width, int height) - { - var sz1 = new Size(width, height); - var sz2 = new Size(height, width); - Size addExpected, subExpected; - - unchecked - { - addExpected = new Size(width + height, height + width); - subExpected = new Size(width - height, height - width); - } - - Assert.Equal(addExpected, sz1 + sz2); - Assert.Equal(subExpected, sz1 - sz2); - Assert.Equal(addExpected, Size.Add(sz1, sz2)); - Assert.Equal(subExpected, Size.Subtract(sz1, sz2)); - } - - [Theory] - [InlineData(float.MaxValue, float.MinValue)] - [InlineData(float.MinValue, float.MinValue)] - [InlineData(float.MaxValue, float.MaxValue)] - [InlineData(0, 0)] - public void PointFMathematicalTest(float width, float height) - { - var szF = new SizeF(width, height); - Size pCeiling, pTruncate, pRound; - - unchecked - { - pCeiling = new Size((int)MathF.Ceiling(width), (int)MathF.Ceiling(height)); - pTruncate = new Size((int)width, (int)height); - pRound = new Size((int)MathF.Round(width), (int)MathF.Round(height)); - } - - Assert.Equal(pCeiling, Size.Ceiling(szF)); - Assert.Equal(pRound, Size.Round(szF)); - Assert.Equal(pTruncate, (Size)szF); - } - - [Theory] - [InlineData(int.MaxValue, int.MinValue)] - [InlineData(int.MinValue, int.MinValue)] - [InlineData(int.MaxValue, int.MaxValue)] - [InlineData(0, 0)] - public void EqualityTest(int width, int height) - { - var p1 = new Size(width, height); - var p2 = new Size(unchecked(width - 1), unchecked(height - 1)); - var p3 = new Size(width, height); - - Assert.True(p1 == p3); - Assert.True(p1 != p2); - Assert.True(p2 != p3); - - Assert.True(p1.Equals(p3)); - Assert.False(p1.Equals(p2)); - Assert.False(p2.Equals(p3)); - - Assert.True(p1.Equals((object)p3)); - Assert.False(p1.Equals((object)p2)); - Assert.False(p2.Equals((object)p3)); - - Assert.Equal(p1.GetHashCode(), p3.GetHashCode()); - } - - [Fact] - public static void EqualityTest_NotSize() - { - var size = new Size(0, 0); - Assert.False(size.Equals(null)); - Assert.False(size.Equals(0)); - Assert.False(size.Equals(new SizeF(0, 0))); - } - - [Fact] - public static void GetHashCodeTest() - { - var size = new Size(10, 10); - Assert.Equal(size.GetHashCode(), new Size(10, 10).GetHashCode()); - Assert.NotEqual(size.GetHashCode(), new Size(20, 10).GetHashCode()); - Assert.NotEqual(size.GetHashCode(), new Size(10, 20).GetHashCode()); - } - - [Fact] - public void ToStringTest() - { - var sz = new Size(10, 5); - Assert.Equal(string.Format(CultureInfo.CurrentCulture, "Size [ Width={0}, Height={1} ]", sz.Width, sz.Height), sz.ToString()); - } - - [Fact] - public void ToStringTestEmpty() - { - var sz = new Size(0, 0); - Assert.Equal("Size [ Empty ]", sz.ToString()); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs index 45962c5893..97d5505923 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs @@ -24,7 +24,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(NormalBlendFunctionData))] public void NormalBlendFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.NormalBlendFunction(back, source, amount); + Vector4 actual = PorterDuffFunctions.Normal((Vector4)back, source, amount); Assert.Equal(expected, actual); } @@ -43,7 +43,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(MultiplyFunctionData))] public void MultiplyFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.MultiplyFunction(back, source, amount); + Vector4 actual = PorterDuffFunctions.Multiply((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -62,7 +62,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(AddFunctionData))] public void AddFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.MultiplyFunction(back, source, amount); + Vector4 actual = PorterDuffFunctions.Multiply((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -81,7 +81,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(SubstractFunctionData))] public void SubstractFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.SubstractFunction(back, source, amount); + Vector4 actual = PorterDuffFunctions.Substract((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -100,7 +100,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(ScreenFunctionData))] public void ScreenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.ScreenFunction(back, source, amount); + Vector4 actual = PorterDuffFunctions.Screen((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -119,7 +119,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(DarkenFunctionData))] public void DarkenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.DarkenFunction(back, source, amount); + Vector4 actual = PorterDuffFunctions.Darken((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -138,7 +138,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(LightenFunctionData))] public void LightenFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.LightenFunction(back, source, amount); + Vector4 actual = PorterDuffFunctions.Lighten((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -157,7 +157,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(OverlayFunctionData))] public void OverlayFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.OverlayFunction(back, source, amount); + Vector4 actual = PorterDuffFunctions.Overlay((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } @@ -176,7 +176,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders [MemberData(nameof(HardLightFunctionData))] public void HardLightFunction(TestVector4 back, TestVector4 source, float amount, TestVector4 expected) { - Vector4 actual = PorterDuffFunctions.HardLightFunction(back, source, amount); + Vector4 actual = PorterDuffFunctions.HardLight((Vector4)back, source, amount); VectorAssert.Equal(expected, actual, 5); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs index 8932f1ffe9..b2a663d074 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs @@ -32,7 +32,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void NormalBlendFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.NormalBlendFunction(back, source, amount); + TPixel actual = PorterDuffFunctions.Normal((TPixel)(TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -41,7 +41,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void NormalBlendFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultNormalPixelBlender().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.Normal().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -51,7 +51,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultNormalPixelBlender().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.Normal().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -71,7 +71,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void MultiplyFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.MultiplyFunction(back, source, amount); + TPixel actual = PorterDuffFunctions.Multiply((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -80,7 +80,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void MultiplyFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultMultiplyPixelBlender().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.Multiply().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -90,7 +90,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultMultiplyPixelBlender().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.Multiply().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -110,7 +110,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void AddFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.AddFunction(back, source, amount); + TPixel actual = PorterDuffFunctions.Add((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -119,7 +119,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void AddFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultAddPixelBlender().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.Add().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -129,7 +129,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultAddPixelBlender().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.Add().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -149,7 +149,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void SubstractFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.SubstractFunction(back, source, amount); + TPixel actual = PorterDuffFunctions.Substract((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -158,7 +158,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void SubstractFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultSubstractPixelBlender().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.Substract().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -168,7 +168,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultSubstractPixelBlender().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.Substract().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -188,7 +188,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void ScreenFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.ScreenFunction(back, source, amount); + TPixel actual = PorterDuffFunctions.Screen((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -197,7 +197,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void ScreenFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultScreenPixelBlender().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.Screen().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -207,7 +207,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultScreenPixelBlender().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.Screen().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -227,7 +227,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void DarkenFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.DarkenFunction(back, source, amount); + TPixel actual = PorterDuffFunctions.Darken((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -236,7 +236,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void DarkenFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultDarkenPixelBlender().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.Darken().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -246,7 +246,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultDarkenPixelBlender().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.Darken().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -266,7 +266,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void LightenFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.LightenFunction(back, source, amount); + TPixel actual = PorterDuffFunctions.Lighten((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -275,7 +275,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void LightenFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultLightenPixelBlender().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.Lighten().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -285,7 +285,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultLightenPixelBlender().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.Lighten().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -305,7 +305,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void OverlayFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.OverlayFunction(back, source, amount); + TPixel actual = PorterDuffFunctions.Overlay((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -314,7 +314,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void OverlayFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultOverlayPixelBlender().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.Overlay().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -324,7 +324,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultOverlayPixelBlender().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.Overlay().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -344,7 +344,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void HardLightFunction(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = PorterDuffFunctions.HardLightFunction(back, source, amount); + TPixel actual = PorterDuffFunctions.HardLight((TPixel)back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -353,7 +353,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders public void HardLightFunction_Blender(TestPixel back, TestPixel source, float amount, TestPixel expected) where TPixel : struct, IPixel { - TPixel actual = new DefaultHardLightPixelBlender().Blend(back, source, amount); + TPixel actual = new DefaultPixelBlenders.HardLight().Blend(back, source, amount); VectorAssert.Equal(expected, actual, 2); } @@ -363,7 +363,7 @@ namespace ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { Span dest = new Span(new TPixel[1]); - new DefaultHardLightPixelBlender().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.HardLight().Blend(dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs index ce81499eda..6bcada0ff5 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs @@ -15,27 +15,55 @@ namespace ImageSharp.Tests.PixelFormats public partial class PixelOperationsTests { + + public static TheoryData BlenderMappings = new TheoryData() { - { new TestPixel(), typeof(DefaultNormalPixelBlender), PixelBlenderMode.Normal }, - { new TestPixel(), typeof(DefaultScreenPixelBlender), PixelBlenderMode.Screen }, - { new TestPixel(), typeof(DefaultHardLightPixelBlender), PixelBlenderMode.HardLight }, - { new TestPixel(), typeof(DefaultOverlayPixelBlender), PixelBlenderMode.Overlay }, - { new TestPixel(), typeof(DefaultDarkenPixelBlender), PixelBlenderMode.Darken }, - { new TestPixel(), typeof(DefaultLightenPixelBlender), PixelBlenderMode.Lighten }, - { new TestPixel(), typeof(DefaultAddPixelBlender), PixelBlenderMode.Add }, - { new TestPixel(), typeof(DefaultSubstractPixelBlender), PixelBlenderMode.Substract }, - { new TestPixel(), typeof(DefaultMultiplyPixelBlender), PixelBlenderMode.Multiply }, - - { new TestPixel(), typeof(DefaultNormalPixelBlender), PixelBlenderMode.Normal }, - { new TestPixel(), typeof(DefaultScreenPixelBlender), PixelBlenderMode.Screen }, - { new TestPixel(), typeof(DefaultHardLightPixelBlender), PixelBlenderMode.HardLight }, - { new TestPixel(), typeof(DefaultOverlayPixelBlender), PixelBlenderMode.Overlay }, - { new TestPixel(), typeof(DefaultDarkenPixelBlender), PixelBlenderMode.Darken }, - { new TestPixel(), typeof(DefaultLightenPixelBlender), PixelBlenderMode.Lighten }, - { new TestPixel(), typeof(DefaultAddPixelBlender), PixelBlenderMode.Add }, - { new TestPixel(), typeof(DefaultSubstractPixelBlender), PixelBlenderMode.Substract }, - { new TestPixel(), typeof(DefaultMultiplyPixelBlender), PixelBlenderMode.Multiply }, + { new TestPixel(), typeof(DefaultPixelBlenders.Normal), PixelBlenderMode.Normal }, + { new TestPixel(), typeof(DefaultPixelBlenders.Screen), PixelBlenderMode.Screen }, + { new TestPixel(), typeof(DefaultPixelBlenders.HardLight), PixelBlenderMode.HardLight }, + { new TestPixel(), typeof(DefaultPixelBlenders.Overlay), PixelBlenderMode.Overlay }, + { new TestPixel(), typeof(DefaultPixelBlenders.Darken), PixelBlenderMode.Darken }, + { new TestPixel(), typeof(DefaultPixelBlenders.Lighten), PixelBlenderMode.Lighten }, + { new TestPixel(), typeof(DefaultPixelBlenders.Add), PixelBlenderMode.Add }, + { new TestPixel(), typeof(DefaultPixelBlenders.Substract), PixelBlenderMode.Substract }, + { new TestPixel(), typeof(DefaultPixelBlenders.Multiply), PixelBlenderMode.Multiply }, + + { new TestPixel(), typeof(DefaultPixelBlenders.Src), PixelBlenderMode.Src }, + { new TestPixel(), typeof(DefaultPixelBlenders.Atop), PixelBlenderMode.Atop }, + { new TestPixel(), typeof(DefaultPixelBlenders.Over), PixelBlenderMode.Over }, + { new TestPixel(), typeof(DefaultPixelBlenders.In), PixelBlenderMode.In }, + { new TestPixel(), typeof(DefaultPixelBlenders.Out), PixelBlenderMode.Out }, + { new TestPixel(), typeof(DefaultPixelBlenders.Dest), PixelBlenderMode.Dest }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestAtop), PixelBlenderMode.DestAtop }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestOver), PixelBlenderMode.DestOver }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestIn), PixelBlenderMode.DestIn }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestOut), PixelBlenderMode.DestOut }, + { new TestPixel(), typeof(DefaultPixelBlenders.Clear), PixelBlenderMode.Clear }, + { new TestPixel(), typeof(DefaultPixelBlenders.Xor), PixelBlenderMode.Xor }, + + { new TestPixel(), typeof(DefaultPixelBlenders.Normal), PixelBlenderMode.Normal }, + { new TestPixel(), typeof(DefaultPixelBlenders.Screen), PixelBlenderMode.Screen }, + { new TestPixel(), typeof(DefaultPixelBlenders.HardLight), PixelBlenderMode.HardLight }, + { new TestPixel(), typeof(DefaultPixelBlenders.Overlay), PixelBlenderMode.Overlay }, + { new TestPixel(), typeof(DefaultPixelBlenders.Darken), PixelBlenderMode.Darken }, + { new TestPixel(), typeof(DefaultPixelBlenders.Lighten), PixelBlenderMode.Lighten }, + { new TestPixel(), typeof(DefaultPixelBlenders.Add), PixelBlenderMode.Add }, + { new TestPixel(), typeof(DefaultPixelBlenders.Substract), PixelBlenderMode.Substract }, + { new TestPixel(), typeof(DefaultPixelBlenders.Multiply), PixelBlenderMode.Multiply }, + { new TestPixel(), typeof(DefaultPixelBlenders.Src), PixelBlenderMode.Src }, + { new TestPixel(), typeof(DefaultPixelBlenders.Atop), PixelBlenderMode.Atop }, + { new TestPixel(), typeof(DefaultPixelBlenders.Over), PixelBlenderMode.Over }, + { new TestPixel(), typeof(DefaultPixelBlenders.In), PixelBlenderMode.In }, + { new TestPixel(), typeof(DefaultPixelBlenders.Out), PixelBlenderMode.Out }, + { new TestPixel(), typeof(DefaultPixelBlenders.Dest), PixelBlenderMode.Dest }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestAtop), PixelBlenderMode.DestAtop }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestOver), PixelBlenderMode.DestOver }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestIn), PixelBlenderMode.DestIn }, + { new TestPixel(), typeof(DefaultPixelBlenders.DestOut), PixelBlenderMode.DestOut }, + { new TestPixel(), typeof(DefaultPixelBlenders.Clear), PixelBlenderMode.Clear }, + { new TestPixel(), typeof(DefaultPixelBlenders.Xor), PixelBlenderMode.Xor }, + }; [Theory] diff --git a/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs b/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs index e792de22f0..642df598a3 100644 --- a/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs +++ b/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Binarization { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class BinaryThresholdTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Binarization/DitherTest.cs b/tests/ImageSharp.Tests/Processing/Binarization/DitherTest.cs index 2948c10460..a06397c864 100644 --- a/tests/ImageSharp.Tests/Processing/Binarization/DitherTest.cs +++ b/tests/ImageSharp.Tests/Processing/Binarization/DitherTest.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Tests.Processing.Binarization using ImageSharp.Dithering; using ImageSharp.Dithering.Ordered; using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class DitherTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/ColorMatrix/BlackWhiteTest.cs b/tests/ImageSharp.Tests/Processing/ColorMatrix/BlackWhiteTest.cs index d825b4993a..4dc70fb0f5 100644 --- a/tests/ImageSharp.Tests/Processing/ColorMatrix/BlackWhiteTest.cs +++ b/tests/ImageSharp.Tests/Processing/ColorMatrix/BlackWhiteTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.ColorMatrix { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class BlackWhiteTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/ColorMatrix/ColorBlindnessTest.cs b/tests/ImageSharp.Tests/Processing/ColorMatrix/ColorBlindnessTest.cs index b56ec3471a..bc1c8ad226 100644 --- a/tests/ImageSharp.Tests/Processing/ColorMatrix/ColorBlindnessTest.cs +++ b/tests/ImageSharp.Tests/Processing/ColorMatrix/ColorBlindnessTest.cs @@ -7,7 +7,7 @@ namespace ImageSharp.Tests.Processing.ColorMatrix { using ImageSharp.PixelFormats; using ImageSharp.Processing; - + using SixLabors.Primitives; using Xunit; public class ColorBlindnessTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/ColorMatrix/GrayscaleTest.cs b/tests/ImageSharp.Tests/Processing/ColorMatrix/GrayscaleTest.cs index 89a388e4d4..9bf55a6d25 100644 --- a/tests/ImageSharp.Tests/Processing/ColorMatrix/GrayscaleTest.cs +++ b/tests/ImageSharp.Tests/Processing/ColorMatrix/GrayscaleTest.cs @@ -7,7 +7,7 @@ namespace ImageSharp.Tests.Processing.ColorMatrix { using ImageSharp.PixelFormats; using ImageSharp.Processing; - + using SixLabors.Primitives; using Xunit; public class GrayscaleTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/ColorMatrix/HueTest.cs b/tests/ImageSharp.Tests/Processing/ColorMatrix/HueTest.cs index b71905374a..ba1cf2b8f7 100644 --- a/tests/ImageSharp.Tests/Processing/ColorMatrix/HueTest.cs +++ b/tests/ImageSharp.Tests/Processing/ColorMatrix/HueTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.ColorMatrix { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class HueTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/ColorMatrix/KodachromeTest.cs b/tests/ImageSharp.Tests/Processing/ColorMatrix/KodachromeTest.cs index 3a5d4f0d34..971cdb6d81 100644 --- a/tests/ImageSharp.Tests/Processing/ColorMatrix/KodachromeTest.cs +++ b/tests/ImageSharp.Tests/Processing/ColorMatrix/KodachromeTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.ColorMatrix { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class KodachromeTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/ColorMatrix/LomographTest.cs b/tests/ImageSharp.Tests/Processing/ColorMatrix/LomographTest.cs index bfa37eef4e..5b41cdb3b7 100644 --- a/tests/ImageSharp.Tests/Processing/ColorMatrix/LomographTest.cs +++ b/tests/ImageSharp.Tests/Processing/ColorMatrix/LomographTest.cs @@ -8,7 +8,7 @@ namespace ImageSharp.Tests using System.IO; using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class LomographTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/ColorMatrix/PolaroidTest.cs b/tests/ImageSharp.Tests/Processing/ColorMatrix/PolaroidTest.cs index 2bf1c36989..48f7a6c0a8 100644 --- a/tests/ImageSharp.Tests/Processing/ColorMatrix/PolaroidTest.cs +++ b/tests/ImageSharp.Tests/Processing/ColorMatrix/PolaroidTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.ColorMatrix { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class PolaroidTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/ColorMatrix/SaturationTest.cs b/tests/ImageSharp.Tests/Processing/ColorMatrix/SaturationTest.cs index 9212c09e83..a4a4f3bb51 100644 --- a/tests/ImageSharp.Tests/Processing/ColorMatrix/SaturationTest.cs +++ b/tests/ImageSharp.Tests/Processing/ColorMatrix/SaturationTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.ColorMatrix { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class SaturationTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/ColorMatrix/SepiaTest.cs b/tests/ImageSharp.Tests/Processing/ColorMatrix/SepiaTest.cs index de536050ba..af554e30d8 100644 --- a/tests/ImageSharp.Tests/Processing/ColorMatrix/SepiaTest.cs +++ b/tests/ImageSharp.Tests/Processing/ColorMatrix/SepiaTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.ColorMatrix { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class SepiaTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs index b5ee876de7..ef049a539a 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Convolution { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class BoxBlurTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs index 220c0f4664..d5817ab14f 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs @@ -7,7 +7,7 @@ namespace ImageSharp.Tests.Processing.Convolution { using ImageSharp.PixelFormats; using ImageSharp.Processing; - + using SixLabors.Primitives; using Xunit; public class DetectEdgesTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Convolution/GaussianBlurTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/GaussianBlurTest.cs index dbaed9290c..fa4e4b0b6b 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/GaussianBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/GaussianBlurTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Convolution { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class GaussianBlurTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Convolution/GaussianSharpenTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/GaussianSharpenTest.cs index 44296d9751..d15042ee69 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/GaussianSharpenTest.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/GaussianSharpenTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Convolution { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class GaussianSharpenTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Effects/AlphaTest.cs b/tests/ImageSharp.Tests/Processing/Effects/AlphaTest.cs index 63366dc1da..34a24e70be 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/AlphaTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/AlphaTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Effects { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class AlphaTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs index c3fda4cd4b..63efbf3e73 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Effects { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class BackgroundColorTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Effects/BrightnessTest.cs b/tests/ImageSharp.Tests/Processing/Effects/BrightnessTest.cs index 4c0217fed0..c3b37705a9 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/BrightnessTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/BrightnessTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Effects { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class BrightnessTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Effects/ContrastTest.cs b/tests/ImageSharp.Tests/Processing/Effects/ContrastTest.cs index ac217e9f6a..892eb93622 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/ContrastTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/ContrastTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Effects { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class ContrastTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Effects/InvertTest.cs b/tests/ImageSharp.Tests/Processing/Effects/InvertTest.cs index 80e3450926..3d8b3d1a1f 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/InvertTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/InvertTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Effects { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class InvertTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs b/tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs index 7d02ace3da..3d0e8f1177 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class OilPaintTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs b/tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs index 740b78c558..253f1f4598 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Effects { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class PixelateTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs index a233e204cb..d0633dca59 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Overlays { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class GlowTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs index 85ccfca6f0..56fcf0ee0d 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs @@ -6,7 +6,7 @@ namespace ImageSharp.Tests.Processing.Overlays { using ImageSharp.PixelFormats; - + using SixLabors.Primitives; using Xunit; public class VignetteTest : FileTestBase diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs index 008d041e7e..fb195254e3 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs @@ -7,7 +7,7 @@ namespace ImageSharp.Tests.Processing.Transforms { using ImageSharp.PixelFormats; using ImageSharp.Processing; - + using SixLabors.Primitives; using Xunit; public class ResizeTests : FileTestBase diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs index 20fff50a89..32a4a8e57b 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs @@ -10,83 +10,124 @@ namespace ImageSharp.Tests { internal static class IccTestDataProfiles { - public static readonly IccProfileHeader Header_Random_Write = new IccProfileHeader + public static readonly IccProfileHeader Header_Random_Write = CreateHeaderRandomValue( + 562, // should be overwritten + new IccProfileId(1, 2, 3, 4), // should be overwritten + "ijkl"); // should be overwritten to "acsp" + + public static readonly IccProfileHeader Header_Random_Read = CreateHeaderRandomValue(132, +#if !NETSTANDARD1_1 + new IccProfileId(2931428592, 418415738, 3086756963, 2237536530), +#else + IccProfileId.Zero, +#endif + "acsp"); + + public static readonly byte[] Header_Random_Array = CreateHeaderRandomArray(132, 0, new byte[] { - Class = IccProfileClass.DisplayDevice, - CmmType = "abcd", - CreationDate = new DateTime(1990, 11, 26, 7, 21, 42), - CreatorSignature = "dcba", - DataColorSpace = IccColorSpaceType.Rgb, - DeviceAttributes = IccDeviceAttribute.ChromaBlackWhite | IccDeviceAttribute.OpacityTransparent, - DeviceManufacturer = 123456789u, - DeviceModel = 987654321u, - FileSignature = "ijkl", // should be overwritten to "acsp" - Flags = IccProfileFlag.Embedded | IccProfileFlag.Independent, - Id = new IccProfileId(1, 2, 3, 4), // should be overwritten - PcsIlluminant = new Vector3(4, 5, 6), - PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation, - ProfileConnectionSpace = IccColorSpaceType.CieXyz, - RenderingIntent = IccRenderingIntent.AbsoluteColorimetric, - Size = 562, // should be overwritten - Version = new Version(4, 3, 0), - }; +#if !NETSTANDARD1_1 + 0xAE, 0xBA, 0x0C, 0xF0, 0x18, 0xF0, 0x84, 0x7A, 0xB7, 0xFC, 0x2C, 0x63, 0x85, 0x5E, 0x19, 0x12, +#else + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +#endif + }); - public static readonly IccProfileHeader Header_Random_Read = new IccProfileHeader + public static IccProfileHeader CreateHeaderRandomValue(uint size, IccProfileId id, string fileSignature) { - Class = IccProfileClass.DisplayDevice, - CmmType = "abcd", - CreationDate = new DateTime(1990, 11, 26, 7, 21, 42), - CreatorSignature = "dcba", - DataColorSpace = IccColorSpaceType.Rgb, - DeviceAttributes = IccDeviceAttribute.ChromaBlackWhite | IccDeviceAttribute.OpacityTransparent, - DeviceManufacturer = 123456789u, - DeviceModel = 987654321u, - FileSignature = "acsp", - Flags = IccProfileFlag.Embedded | IccProfileFlag.Independent, + return new IccProfileHeader + { + Class = IccProfileClass.DisplayDevice, + CmmType = "abcd", + CreationDate = new DateTime(1990, 11, 26, 7, 21, 42), + CreatorSignature = "dcba", + DataColorSpace = IccColorSpaceType.Rgb, + DeviceAttributes = IccDeviceAttribute.ChromaBlackWhite | IccDeviceAttribute.OpacityTransparent, + DeviceManufacturer = 123456789u, + DeviceModel = 987654321u, + FileSignature = "acsp", + Flags = IccProfileFlag.Embedded | IccProfileFlag.Independent, #if !NETSTANDARD1_1 - Id = new IccProfileId(2931428592, 418415738, 3086756963, 2237536530), + Id = new IccProfileId(2931428592, 418415738, 3086756963, 2237536530), #else Id = IccProfileId.Zero, #endif - PcsIlluminant = new Vector3(4, 5, 6), - PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation, - ProfileConnectionSpace = IccColorSpaceType.CieXyz, - RenderingIntent = IccRenderingIntent.AbsoluteColorimetric, - Size = 132, - Version = new Version(4, 3, 0), - }; + PcsIlluminant = new Vector3(4, 5, 6), + PrimaryPlatformSignature = IccPrimaryPlatformType.MicrosoftCorporation, + ProfileConnectionSpace = IccColorSpaceType.CieXyz, + RenderingIntent = IccRenderingIntent.AbsoluteColorimetric, + Size = size, + Version = new Version(4, 3, 0), + }; + } - public static readonly byte[] Header_Random_Array = + public static byte[] CreateHeaderRandomArray(uint size, uint nrOfEntries, byte[] profileId) { - 0x00, 0x00, 0x00, 0x84, // Size (132) - 0x61, 0x62, 0x63, 0x64, // CmmType - 0x04, 0x30, 0x00, 0x00, // Version - 0x6D, 0x6E, 0x74, 0x72, // Class - 0x52, 0x47, 0x42, 0x20, // DataColorSpace - 0x58, 0x59, 0x5A, 0x20, // ProfileConnectionSpace - 0x07, 0xC6, 0x00, 0x0B, 0x00, 0x1A, 0x00, 0x07, 0x00, 0x15, 0x00, 0x2A, // CreationDate - 0x61, 0x63, 0x73, 0x70, // FileSignature - 0x4D, 0x53, 0x46, 0x54, // PrimaryPlatformSignature - 0x00, 0x00, 0x00, 0x01, // Flags - 0x07, 0x5B, 0xCD, 0x15, // DeviceManufacturer - 0x3A, 0xDE, 0x68, 0xB1, // DeviceModel - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, // DeviceAttributes - 0x00, 0x00, 0x00, 0x03, // RenderingIntent - 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // PcsIlluminant - 0x64, 0x63, 0x62, 0x61, // CreatorSignature + return ArrayHelper.Concat( + new byte[] + { + (byte)(size >> 24), (byte)(size >> 16), (byte)(size >> 8), (byte)size, // Size + 0x61, 0x62, 0x63, 0x64, // CmmType + 0x04, 0x30, 0x00, 0x00, // Version + 0x6D, 0x6E, 0x74, 0x72, // Class + 0x52, 0x47, 0x42, 0x20, // DataColorSpace + 0x58, 0x59, 0x5A, 0x20, // ProfileConnectionSpace + 0x07, 0xC6, 0x00, 0x0B, 0x00, 0x1A, 0x00, 0x07, 0x00, 0x15, 0x00, 0x2A, // CreationDate + 0x61, 0x63, 0x73, 0x70, // FileSignature + 0x4D, 0x53, 0x46, 0x54, // PrimaryPlatformSignature + 0x00, 0x00, 0x00, 0x01, // Flags + 0x07, 0x5B, 0xCD, 0x15, // DeviceManufacturer + 0x3A, 0xDE, 0x68, 0xB1, // DeviceModel + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, // DeviceAttributes + 0x00, 0x00, 0x00, 0x03, // RenderingIntent + 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // PcsIlluminant + 0x64, 0x63, 0x62, 0x61, // CreatorSignature + }, + profileId, + new byte[] + { + // Padding + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + // Nr of tag table entries (0) + (byte)(nrOfEntries >> 24), (byte)(nrOfEntries >> 16), (byte)(nrOfEntries >> 8), (byte)nrOfEntries + }); + } + + public static byte[] Profile_Random_Array = ArrayHelper.Concat(CreateHeaderRandomArray(168, 2, new byte[] + { +#if !NETSTANDARD1_1 + 0xA9, 0x71, 0x8F, 0xC1, 0x1E, 0x2D, 0x64, 0x1B, 0x10, 0xF4, 0x7D, 0x6A, 0x5B, 0xF6, 0xAC, 0xB9 +#else + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +#endif + }), + new byte[] + { + 0x00, 0x00, 0x00, 0x00, // tag signature (Unknown) + 0x00, 0x00, 0x00, 0x9C, // tag offset (156) + 0x00, 0x00, 0x00, 0x0C, // tag size (12) + + 0x00, 0x00, 0x00, 0x00, // tag signature (Unknown) + 0x00, 0x00, 0x00, 0x9C, // tag offset (156) + 0x00, 0x00, 0x00, 0x0C, // tag size (12) + }, + IccTestDataTagDataEntry.TagDataEntryHeader_UnknownArr, + IccTestDataTagDataEntry.Unknown_Arr + ); + public static IccProfile Profile_Random_Val = new IccProfile(CreateHeaderRandomValue(168, #if !NETSTANDARD1_1 - 0xAE, 0xBA, 0x0C, 0xF0, 0x18, 0xF0, 0x84, 0x7A, 0xB7, 0xFC, 0x2C, 0x63, 0x85, 0x5E, 0x19, 0x12, // Id + new IccProfileId(0xA9718FC1, 0x1E2D641B, 0x10F47D6A, 0x5BF6ACB9), #else - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Id + IccProfileId.Zero, #endif - // Padding - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - // Nr of tag table entries (0) - 0x00, 0x00, 0x00, 0x00, - }; + "acsp"), + new IccTagDataEntry[] + { + IccTestDataTagDataEntry.Unknown_Val, + IccTestDataTagDataEntry.Unknown_Val + }); } } diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs index 769ec3a016..05942ab618 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs @@ -455,21 +455,29 @@ namespace ImageSharp.Tests #region MultiLocalizedUnicodeTagDataEntry - private static readonly IccLocalizedString LocalizedString_Rand1 = new IccLocalizedString(new CultureInfo("en-US"), IccTestDataPrimitives.Unicode_ValRand2); - private static readonly IccLocalizedString LocalizedString_Rand2 = new IccLocalizedString(new CultureInfo("de-DE"), IccTestDataPrimitives.Unicode_ValRand3); + private static readonly IccLocalizedString LocalizedString_Rand_enUs = new IccLocalizedString(new CultureInfo("en-US"), IccTestDataPrimitives.Unicode_ValRand2); + private static readonly IccLocalizedString LocalizedString_Rand_deDE = new IccLocalizedString(new CultureInfo("de-DE"), IccTestDataPrimitives.Unicode_ValRand3); + private static readonly IccLocalizedString LocalizedString_Rand2_deDE = new IccLocalizedString(new CultureInfo("de-DE"), IccTestDataPrimitives.Unicode_ValRand2); + private static readonly IccLocalizedString LocalizedString_Rand_en = new IccLocalizedString(new CultureInfo("en"), IccTestDataPrimitives.Unicode_ValRand2); + private static readonly IccLocalizedString LocalizedString_Rand_Invariant = new IccLocalizedString(CultureInfo.InvariantCulture, IccTestDataPrimitives.Unicode_ValRand3); - private static readonly IccLocalizedString[] LocalizedString_RandArr1 = new IccLocalizedString[] + private static readonly IccLocalizedString[] LocalizedString_RandArr_enUs_deDE = new IccLocalizedString[] { - LocalizedString_Rand1, - LocalizedString_Rand2, + LocalizedString_Rand_enUs, + LocalizedString_Rand_deDE, }; - private static readonly IccLocalizedString[] LocalizedString_RandArr2 = new IccLocalizedString[] + private static readonly IccLocalizedString[] LocalizedString_RandArr_en_Invariant = new IccLocalizedString[] { - LocalizedString_Rand2, - LocalizedString_Rand1, + LocalizedString_Rand_en, + LocalizedString_Rand_Invariant, + }; + private static readonly IccLocalizedString[] LocalizedString_SameArr_enUs_deDE = new IccLocalizedString[] + { + LocalizedString_Rand_enUs, + LocalizedString_Rand2_deDE }; - public static readonly IccMultiLocalizedUnicodeTagDataEntry MultiLocalizedUnicode_Val = new IccMultiLocalizedUnicodeTagDataEntry(LocalizedString_RandArr1); + public static readonly IccMultiLocalizedUnicodeTagDataEntry MultiLocalizedUnicode_Val = new IccMultiLocalizedUnicodeTagDataEntry(LocalizedString_RandArr_enUs_deDE); public static readonly byte[] MultiLocalizedUnicode_Arr = ArrayHelper.Concat ( IccTestDataPrimitives.UInt32_2, @@ -487,9 +495,70 @@ namespace ImageSharp.Tests IccTestDataPrimitives.Unicode_Rand3 ); - public static readonly object[][] MultiLocalizedUnicodeTagDataEntryTestData = + public static readonly IccMultiLocalizedUnicodeTagDataEntry MultiLocalizedUnicode_Val2 = new IccMultiLocalizedUnicodeTagDataEntry(LocalizedString_RandArr_en_Invariant); + public static readonly byte[] MultiLocalizedUnicode_Arr2_Read = ArrayHelper.Concat + ( + IccTestDataPrimitives.UInt32_2, + new byte[] { 0x00, 0x00, 0x00, 0x0C }, // 12 + + new byte[] { (byte)'e', (byte)'n', 0x00, 0x00 }, + new byte[] { 0x00, 0x00, 0x00, 0x0C }, // 12 + new byte[] { 0x00, 0x00, 0x00, 0x28 }, // 40 + + new byte[] { 0x00, 0x00, 0x00, 0x00 }, + new byte[] { 0x00, 0x00, 0x00, 0x0E }, // 14 + new byte[] { 0x00, 0x00, 0x00, 0x34 }, // 52 + + IccTestDataPrimitives.Unicode_Rand2, + IccTestDataPrimitives.Unicode_Rand3 + ); + + public static readonly byte[] MultiLocalizedUnicode_Arr2_Write = ArrayHelper.Concat + ( + IccTestDataPrimitives.UInt32_2, + new byte[] { 0x00, 0x00, 0x00, 0x0C }, // 12 + + new byte[] { (byte)'e', (byte)'n', 0x00, 0x00 }, + new byte[] { 0x00, 0x00, 0x00, 0x0C }, // 12 + new byte[] { 0x00, 0x00, 0x00, 0x28 }, // 40 + + new byte[] { (byte)'x', (byte)'x', 0x00, 0x00 }, + new byte[] { 0x00, 0x00, 0x00, 0x0E }, // 14 + new byte[] { 0x00, 0x00, 0x00, 0x34 }, // 52 + + IccTestDataPrimitives.Unicode_Rand2, + IccTestDataPrimitives.Unicode_Rand3 + ); + + public static readonly IccMultiLocalizedUnicodeTagDataEntry MultiLocalizedUnicode_Val3 = new IccMultiLocalizedUnicodeTagDataEntry(LocalizedString_SameArr_enUs_deDE); + public static readonly byte[] MultiLocalizedUnicode_Arr3 = ArrayHelper.Concat + ( + IccTestDataPrimitives.UInt32_2, + new byte[] { 0x00, 0x00, 0x00, 0x0C }, // 12 + + new byte[] { (byte)'e', (byte)'n', (byte)'U', (byte)'S' }, + new byte[] { 0x00, 0x00, 0x00, 0x0C }, // 12 + new byte[] { 0x00, 0x00, 0x00, 0x28 }, // 40 + + new byte[] { (byte)'d', (byte)'e', (byte)'D', (byte)'E' }, + new byte[] { 0x00, 0x00, 0x00, 0x0C }, // 12 + new byte[] { 0x00, 0x00, 0x00, 0x28 }, // 40 + + IccTestDataPrimitives.Unicode_Rand2 + ); + + public static readonly object[][] MultiLocalizedUnicodeTagDataEntryTestData_Read = + { + new object[] { MultiLocalizedUnicode_Arr, MultiLocalizedUnicode_Val }, + new object[] { MultiLocalizedUnicode_Arr2_Read, MultiLocalizedUnicode_Val2 }, + new object[] { MultiLocalizedUnicode_Arr3, MultiLocalizedUnicode_Val3 }, + }; + + public static readonly object[][] MultiLocalizedUnicodeTagDataEntryTestData_Write = { new object[] { MultiLocalizedUnicode_Arr, MultiLocalizedUnicode_Val }, + new object[] { MultiLocalizedUnicode_Arr2_Write, MultiLocalizedUnicode_Val2 }, + new object[] { MultiLocalizedUnicode_Arr3, MultiLocalizedUnicode_Val3 }, }; #endregion @@ -601,8 +670,8 @@ namespace ImageSharp.Tests ( new IccProfileSequenceIdentifier[] { - new IccProfileSequenceIdentifier(IccTestDataNonPrimitives.ProfileId_ValRand, LocalizedString_RandArr1), - new IccProfileSequenceIdentifier(IccTestDataNonPrimitives.ProfileId_ValRand, LocalizedString_RandArr1), + new IccProfileSequenceIdentifier(IccTestDataNonPrimitives.ProfileId_ValRand, LocalizedString_RandArr_enUs_deDE), + new IccProfileSequenceIdentifier(IccTestDataNonPrimitives.ProfileId_ValRand, LocalizedString_RandArr_enUs_deDE), } ); public static readonly byte[] ProfileSequenceIdentifier_Arr = ArrayHelper.Concat @@ -951,7 +1020,7 @@ namespace ImageSharp.Tests IccTestDataPrimitives.UInt16_7, IccTestDataPrimitives.UInt16_2, IccTestDataPrimitives.UInt16_5, - + IccTestDataPrimitives.Ascii_Rand, new byte[] { 0 } ); diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index f1b78383cb..c0f9deebb3 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -11,7 +11,7 @@ namespace ImageSharp.Tests using System.IO; using System.Linq; using System.Reflection; - + using ImageSharp.Formats; using ImageSharp.PixelFormats; /// @@ -135,13 +135,12 @@ namespace ImageSharp.Tests /// /// Creates a new image. /// - /// The options for the decoder. /// /// The . /// - public Image CreateImage(IDecoderOptions options) + public Image CreateImage(IImageDecoder decoder) { - return Image.Load(this.Bytes, options); + return Image.Load(this.image.Configuration, this.Bytes, decoder); } /// diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 318df5ead3..5a3cd102e7 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -19,13 +19,13 @@ namespace ImageSharp.Tests /// /// A test image file. /// - public class TestFormat : ImageSharp.Formats.IImageFormat + public class TestFormat : IConfigurationModule, IImageFormat { public static TestFormat GlobalTestFormat { get; } = new TestFormat(); public static void RegisterGloablTestFormat() { - Configuration.Default.AddImageFormat(GlobalTestFormat); + Configuration.Default.Configure(GlobalTestFormat); } public TestFormat() @@ -58,14 +58,15 @@ namespace ImageSharp.Tests Dictionary _sampleImages = new Dictionary(); - public void VerifyDecodeCall(byte[] marker, IDecoderOptions options, Configuration config) + public void VerifyDecodeCall(byte[] marker, Configuration config) { - DecodeOperation[] discovered = this.DecodeCalls.Where(x => x.IsMatch(marker, options, config)).ToArray(); + DecodeOperation[] discovered = this.DecodeCalls.Where(x => x.IsMatch(marker, config)).ToArray(); Assert.True(discovered.Any(), "No calls to decode on this formate with the proveded options happend"); - foreach (DecodeOperation d in discovered) { + foreach (DecodeOperation d in discovered) + { this.DecodeCalls.Remove(d); } } @@ -79,7 +80,7 @@ namespace ImageSharp.Tests { this._sampleImages.Add(typeof(TPixel), new Image(1, 1)); } - + return (Image)this._sampleImages[typeof(TPixel)]; } } @@ -92,7 +93,15 @@ namespace ImageSharp.Tests public int HeaderSize => this.header.Length; - public bool IsSupportedFileFormat(byte[] header) + public string Name => this.Extension; + + public string DefaultMimeType => this.MimeType; + + public IEnumerable MimeTypes => new[] { this.MimeType }; + + public IEnumerable FileExtensions => this.SupportedExtensions; + + public bool IsSupportedFileFormat(ReadOnlySpan header) { if (header.Length < this.header.Length) { @@ -107,18 +116,21 @@ namespace ImageSharp.Tests } return true; } + + public void Configure(Configuration host) + { + host.AddImageFormatDetector(new TestHeader(this)); + host.SetEncoder(this, new TestEncoder(this)); + host.SetDecoder(this, new TestDecoder(this)); + } + public struct DecodeOperation { public byte[] marker; - public IDecoderOptions options; internal Configuration config; - public bool IsMatch(byte[] testMarker, IDecoderOptions testOptions, Configuration config) + public bool IsMatch(byte[] testMarker, Configuration config) { - if (this.options != testOptions) - { - return false; - } if (this.config != config) { @@ -141,6 +153,26 @@ namespace ImageSharp.Tests } } + public class TestHeader : IImageFormatDetector + { + + private TestFormat testFormat; + + public int HeaderSize => testFormat.HeaderSize; + + public IImageFormat DetectFormat(ReadOnlySpan header) + { + if (testFormat.IsSupportedFileFormat(header)) + return testFormat; + + return null; + } + + public TestHeader(TestFormat testFormat) + { + this.testFormat = testFormat; + } + } public class TestDecoder : ImageSharp.Formats.IImageDecoder { private TestFormat testFormat; @@ -150,8 +182,13 @@ namespace ImageSharp.Tests this.testFormat = testFormat; } + public IEnumerable MimeTypes => new[] { testFormat.MimeType }; + + public IEnumerable FileExtensions => testFormat.SupportedExtensions; + + public int HeaderSize => testFormat.HeaderSize; - public Image Decode(Configuration config, Stream stream, IDecoderOptions options) where TPixel : struct, IPixel + public Image Decode(Configuration config, Stream stream) where TPixel : struct, IPixel { var ms = new MemoryStream(); @@ -160,13 +197,14 @@ namespace ImageSharp.Tests this.testFormat.DecodeCalls.Add(new DecodeOperation { marker = marker, - options = options, config = config }); // TODO record this happend so we an verify it. return this.testFormat.Sample(); } + + public bool IsSupportedFileFormat(Span header) => testFormat.IsSupportedFileFormat(header); } public class TestEncoder : ImageSharp.Formats.IImageEncoder @@ -178,7 +216,11 @@ namespace ImageSharp.Tests this.testFormat = testFormat; } - public void Encode(Image image, Stream stream, IEncoderOptions options) where TPixel : struct, IPixel + public IEnumerable MimeTypes => new[] { testFormat.MimeType }; + + public IEnumerable FileExtensions => testFormat.SupportedExtensions; + + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { // TODO record this happend so we an verify it. } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 471d61abb0..f35720f199 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -25,6 +25,7 @@ namespace ImageSharp.Tests public const string Powerpoint = "Png/pp.png"; public const string SplashInterlaced = "Png/splash-interlaced.png"; public const string Interlaced = "Png/interlaced.png"; + public const string Rgb48Bpp = "Png/rgb-48bpp.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Png/rgb-48bpp.png b/tests/ImageSharp.Tests/TestImages/Formats/Png/rgb-48bpp.png new file mode 100644 index 0000000000..edbedcc049 --- /dev/null +++ b/tests/ImageSharp.Tests/TestImages/Formats/Png/rgb-48bpp.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d3d6028bb193ccf6025f11b90882ed952185684f58347383aaf23586ca4bc059 +size 972960 diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 2901238856..47085cf5f4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -97,18 +97,16 @@ namespace ImageSharp.Tests /// The requested extension /// Optional encoder /// Optional encoder options - public void SaveTestOutputFile(Image image, string extension = null, IImageEncoder encoder = null, IEncoderOptions options = null, string tag = null) + public void SaveTestOutputFile(Image image, string extension = null, IImageEncoder encoder = null, string tag = null) where TPixel : struct, IPixel { string path = this.GetTestOutputFileName(extension: extension, tag:tag); extension = Path.GetExtension(path); - IImageFormat format = GetImageFormatByExtension(extension); - - encoder = encoder ?? format.Encoder; + encoder = encoder ?? GetImageFormatByExtension(extension); using (FileStream stream = File.OpenWrite(path)) { - image.Save(stream, encoder, options); + image.Save(stream, encoder); } } @@ -123,16 +121,16 @@ namespace ImageSharp.Tests this.Init(method.DeclaringType.Name, method.Name); } - private static IImageFormat GetImageFormatByExtension(string extension) + private static IImageEncoder GetImageFormatByExtension(string extension) { extension = extension?.TrimStart('.'); - return Configuration.Default.ImageFormats.First(f => f.SupportedExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); + var format = Configuration.Default.FindFormatByFileExtensions(extension); + return Configuration.Default.FindEncoder(format); } private string GetTestOutputDir() { string testGroupName = Path.GetFileNameWithoutExtension(this.TestGroupName); - return CreateOutputDirectory(testGroupName); } }