diff --git a/ImageSharp.sln b/ImageSharp.sln
index 223d7c3c16..2802e7ba8a 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.26228.4
+VisualStudioVersion = 15.0.26228.9
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject
@@ -22,6 +22,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}"
+ ProjectSection(SolutionItems) = preProject
+ src\README.md = src\README.md
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{56801022-D71A-4FBE-BC5B-CBA08E2284EC}"
EndProject
diff --git a/README.md b/README.md
index 967bccf8aa..6ba113e922 100644
--- a/README.md
+++ b/README.md
@@ -9,8 +9,11 @@
[](https://github.com/JimBobSquarePants/ImageSharp/issues)
[](https://github.com/JimBobSquarePants/ImageSharp/stargazers)
[](https://github.com/JimBobSquarePants/ImageSharp/network)
-[](https://gitter.im/ImageSharp/General?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[](https://gitter.im/ImageSharp/General?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://twitter.com/intent/tweet?hashtags=imagesharp,dotnet,oss&text=ImageSharp.+A+new+cross-platform+2D+graphics+API+in+C%23&url=https%3a%2f%2fgithub.com%2fJimBobSquarePants%2fImageSharp&via=james_m_south)
+[](#backers)
+[](#sponsors)
+
| |Build Status|Code Coverage|
@@ -74,7 +77,7 @@ Here's an example of the code required to resize an image using the default Bicu
On platforms supporting netstandard 1.3+
```csharp
-using (Image image = new Image("foo.jpg"))
+using (Image image = Image.Load("foo.jpg"))
{
image.Resize(image.Width / 2, image.Height / 2)
.Grayscale()
@@ -85,7 +88,7 @@ on netstandard 1.1 - 1.2
```csharp
using (FileStream stream = File.OpenRead("foo.jpg"))
using (FileStream output = File.OpenWrite("bar.jpg"))
-using (Image image = new Image(stream))
+using (Image image = Image.Load(stream))
{
image.Resize(image.Width / 2, image.Height / 2)
.Grayscale()
@@ -93,12 +96,6 @@ using (Image image = new Image(stream))
}
```
-Individual processors can be initialised and apply processing against images. This allows nesting which brings the potential for powerful combinations of processing methods:
-
-```csharp
-new BrightnessProcessor(50).Apply(sourceImage, sourceImage.Bounds);
-```
-
Setting individual pixel values is perfomed as follows:
```csharp
@@ -132,3 +129,73 @@ Core Team
- [Anton Firsov](https://github.com/antonfirsov)
- [Olivia Ifrim](https://github.com/olivif)
- [Scott Williams](https://github.com/tocsoft)
+
+### Backers
+
+Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/imagesharp#backer)]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+### Sponsors
+
+Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/imagesharp#sponsor)]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/appveyor.yml b/appveyor.yml
index c456a8d722..6b7ba946ec 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,6 +1,9 @@
version: 1.0.0.{build}
image: Visual Studio 2017
+# prevent the double build when a branch has an active PR
+skip_branch_with_pr: true
+
init:
- ps: iex ((new-object net.webclient).DownloadString('https://gist.githubusercontent.com/PureKrome/0f79e25693d574807939/raw/8cf3160c9516ef1f4effc825c0a44acc918a0b5a/appveyor-build-info.ps'))
@@ -17,7 +20,7 @@ deploy:
# MyGet Deployment for builds & releases
- provider: NuGet
server: https://www.myget.org/F/imagesharp/api/v2/package
- symbol_server: https://www.myget.org/F/imagesharp/api/v2/package # https://nuget.symbolsource.org/MyGet/imagesharp
+ symbol_server: https://www.myget.org/F/imagesharp/symbols/api/v2/package
api_key:
secure: fz0rUrt3B1HczUC1ZehwVsrFSWX9WZGDQoueDztLte9/+yQG+BBU7UrO+coE8lUf
artifact: /.*\.nupkg/
diff --git a/build/Program.cs b/build/Program.cs
index 6e04dc1df4..4e59b22145 100644
--- a/build/Program.cs
+++ b/build/Program.cs
@@ -63,21 +63,21 @@ namespace ConsoleApplication
/// The arguments.
public static void Main(string[] args)
{
- var resetmode = args.Contains("reset");
+ bool resetmode = args.Contains("reset");
// Find the project root
- var root = Path.GetFullPath(Path.Combine(LibGit2Sharp.Repository.Discover("."), ".."));
+ string root = Path.GetFullPath(Path.Combine(LibGit2Sharp.Repository.Discover("."), ".."));
// Lets find the repo
- var repo = new LibGit2Sharp.Repository(root);
+ Repository repo = new LibGit2Sharp.Repository(root);
// Lets find all the project.json files in the src folder (don't care about versioning `tests`)
- var projectFiles = Directory.EnumerateFiles(Path.Combine(root, "src"), "*.csproj", SearchOption.AllDirectories);
+ IEnumerable projectFiles = Directory.EnumerateFiles(Path.Combine(root, "src"), "*.csproj", SearchOption.AllDirectories);
ResetProject(projectFiles);
// Open them and convert them to source projects
- var projects = projectFiles.Select(x => ProjectRootElement.Open(x, ProjectCollection.GlobalProjectCollection, true))
+ List projects = projectFiles.Select(x => ProjectRootElement.Open(x, ProjectCollection.GlobalProjectCollection, true))
.Select(x => new SourceProject(x, repo.Info.WorkingDirectory))
.ToList();
@@ -89,7 +89,7 @@ namespace ConsoleApplication
CreateBuildScript(projects, root);
- foreach (var p in projects)
+ foreach (SourceProject p in projects)
{
Console.WriteLine($"{p.Name} {p.FinalVersionNumber}");
}
@@ -98,10 +98,10 @@ namespace ConsoleApplication
private static void CreateBuildScript(IEnumerable projects, string root)
{
- var outputDir = Path.GetFullPath(Path.Combine(root, @"artifacts\bin\ImageSharp"));
+ string outputDir = Path.GetFullPath(Path.Combine(root, @"artifacts\bin\ImageSharp"));
- var sb = new StringBuilder();
- foreach (var p in projects)
+ StringBuilder sb = new StringBuilder();
+ foreach (SourceProject p in projects)
{
sb.AppendLine($@"dotnet pack --configuration Release --output ""{outputDir}"" ""{p.ProjectFilePath}""");
}
@@ -111,17 +111,17 @@ namespace ConsoleApplication
private static void UpdateVersionNumbers(IEnumerable projects)
{
- foreach (var p in projects)
+ foreach (SourceProject p in projects)
{
// create a backup file so we can rollback later without breaking formatting
File.Copy(p.FullProjectFilePath, $"{p.FullProjectFilePath}.bak", true);
}
- foreach (var p in projects)
+ foreach (SourceProject p in projects)
{
// TODO force update of all dependent projects to point to the newest build.
// we skip the build number and standard CI prefix on first commits
- var newVersion = p.FinalVersionNumber;
+ string newVersion = p.FinalVersionNumber;
p.UpdateVersion(newVersion);
}
@@ -133,13 +133,13 @@ namespace ConsoleApplication
string branch = repo.Head.FriendlyName;
// lets see if we are running in appveyor and if we are use the environment variables instead of the head
- var appveryorBranch = Environment.GetEnvironmentVariable("APPVEYOR_REPO_BRANCH");
+ string appveryorBranch = Environment.GetEnvironmentVariable("APPVEYOR_REPO_BRANCH");
if (!string.IsNullOrWhiteSpace(appveryorBranch))
{
branch = appveryorBranch;
}
- var prNumber = Environment.GetEnvironmentVariable("APPVEYOR_PULL_REQUEST_NUMBER");
+ string prNumber = Environment.GetEnvironmentVariable("APPVEYOR_PULL_REQUEST_NUMBER");
if (!string.IsNullOrWhiteSpace(prNumber))
{
branch = $"PR{int.Parse(prNumber):000}";
@@ -159,7 +159,7 @@ namespace ConsoleApplication
private static void CaclulateProjectVersionNumber(List projects, Repository repo)
{
- var branch = CurrentBranch(repo);
+ string branch = CurrentBranch(repo);
// populate the dependency chains
projects.ForEach(x => x.PopulateDependencies(projects));
@@ -176,7 +176,7 @@ namespace ConsoleApplication
}
// revert the project.json change be reverting it but skipp all the git stuff as its not needed
- foreach (var p in projectPaths)
+ foreach (string p in projectPaths)
{
if (File.Exists($"{p}.bak"))
{
@@ -303,7 +303,7 @@ namespace ConsoleApplication
/// The branch.
internal void CalculateVersion(Repository repo, string branch)
{
- foreach (var c in repo.Commits)
+ foreach (Commit c in repo.Commits)
{
if (!this.ApplyCommit(c, repo))
{
@@ -335,7 +335,7 @@ namespace ConsoleApplication
this.CommitCountSinceVersionChange++;
// return false if this is a version number root
- var projectFileChange = changes.Where(x => x.Path?.Equals(this.ProjectFilePath, StringComparison.OrdinalIgnoreCase) == true).FirstOrDefault();
+ TreeEntryChanges projectFileChange = changes.Where(x => x.Path?.Equals(this.ProjectFilePath, StringComparison.OrdinalIgnoreCase) == true).FirstOrDefault();
if (projectFileChange != null)
{
if (projectFileChange.Status == ChangeKind.Added)
@@ -345,13 +345,13 @@ namespace ConsoleApplication
}
else
{
- var blob = repo.Lookup(projectFileChange.Oid);
- using (var s = blob.GetContentStream())
+ Blob blob = repo.Lookup(projectFileChange.Oid);
+ using (Stream s = blob.GetContentStream())
{
- using (var reader = XmlReader.Create(s))
+ using (XmlReader reader = XmlReader.Create(s))
{
- var proj = ProjectRootElement.Create(reader);
- var version = new NuGetVersion(proj.Properties.FirstOrDefault(x => x.Name == "VersionPrefix").Value);
+ ProjectRootElement proj = ProjectRootElement.Create(reader);
+ NuGetVersion version = new NuGetVersion(proj.Properties.FirstOrDefault(x => x.Name == "VersionPrefix").Value);
if (version != this.Version)
{
// version changed
@@ -370,9 +370,9 @@ namespace ConsoleApplication
private bool ApplyCommit(Commit commit, Repository repo)
{
- foreach (var parent in commit.Parents)
+ foreach (Commit parent in commit.Parents)
{
- var changes = repo.Diff.Compare(parent.Tree, commit.Tree);
+ TreeChanges changes = repo.Diff.Compare(parent.Tree, commit.Tree);
foreach (TreeEntryChanges change in changes)
{
@@ -399,7 +399,7 @@ namespace ConsoleApplication
private string CalculateVersionNumber(string branch)
{
- var version = this.Version.ToFullString();
+ string version = this.Version.ToFullString();
// master only
if (this.CommitCountSinceVersionChange == 1 && branch == "master")
@@ -414,12 +414,12 @@ namespace ConsoleApplication
return version;
}
- var rootSpecialVersion = string.Empty;
+ string rootSpecialVersion = string.Empty;
if (this.Version.IsPrerelease)
{
// probably a much easy way for doing this but it work sell enough for a build script
- var parts = version.Split(new[] { '-' }, 2);
+ string[] parts = version.Split(new[] { '-' }, 2);
version = parts[0];
rootSpecialVersion = parts[1];
}
@@ -447,7 +447,7 @@ namespace ConsoleApplication
branch = "-" + branch;
}
- var maxLength = 20; // dotnet will fail to populate the package if the tag is > 20
+ int maxLength = 20; // dotnet will fail to populate the package if the tag is > 20
maxLength -= rootSpecialVersion.Length; // this is a required tag
maxLength -= 7; // for the counter and dashes
diff --git a/build/icons/imagesharp-logo-128.png b/build/icons/imagesharp-logo-128.png
index 6d05c222cd..3fd4963dd3 100644
Binary files a/build/icons/imagesharp-logo-128.png and b/build/icons/imagesharp-logo-128.png differ
diff --git a/build/icons/imagesharp-logo-256.png b/build/icons/imagesharp-logo-256.png
index fc59b03e1a..d40880a63e 100644
Binary files a/build/icons/imagesharp-logo-256.png and b/build/icons/imagesharp-logo-256.png differ
diff --git a/build/icons/imagesharp-logo-32.png b/build/icons/imagesharp-logo-32.png
index 0fd4411ce4..8fcae249de 100644
Binary files a/build/icons/imagesharp-logo-32.png and b/build/icons/imagesharp-logo-32.png differ
diff --git a/build/icons/imagesharp-logo-512.png b/build/icons/imagesharp-logo-512.png
index 5d5fb854ea..fcde03ec48 100644
Binary files a/build/icons/imagesharp-logo-512.png and b/build/icons/imagesharp-logo-512.png differ
diff --git a/build/icons/imagesharp-logo-64.png b/build/icons/imagesharp-logo-64.png
index 4e97906e51..b43538a6fa 100644
Binary files a/build/icons/imagesharp-logo-64.png and b/build/icons/imagesharp-logo-64.png differ
diff --git a/build/icons/imagesharp-logo-heading.png b/build/icons/imagesharp-logo-heading.png
index b10d367bfd..35a945930a 100644
Binary files a/build/icons/imagesharp-logo-heading.png and b/build/icons/imagesharp-logo-heading.png differ
diff --git a/build/icons/imagesharp-logo.png b/build/icons/imagesharp-logo.png
index ed1c36c5ea..fcde03ec48 100644
Binary files a/build/icons/imagesharp-logo.png and b/build/icons/imagesharp-logo.png differ
diff --git a/build/icons/imagesharp-logo.svg b/build/icons/imagesharp-logo.svg
index 2df3cc80ce..cd4dfa117d 100644
--- a/build/icons/imagesharp-logo.svg
+++ b/build/icons/imagesharp-logo.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs b/src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs
index d77a6d5941..6e092bf185 100644
--- a/src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs
+++ b/src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs
@@ -18,10 +18,9 @@ namespace ImageSharp.Drawing.Brushes
///
/// Percent10 Hatch Pattern
///
- /// note 2d arrays when configured using initalizer look inverted
- /// ---> Y axis
+ /// ---> x axis
/// ^
- /// | X - axis
+ /// | y - axis
/// |
/// see PatternBrush for details about how to make new patterns work
private static readonly bool[,] Percent10Pattern =
@@ -37,10 +36,10 @@ namespace ImageSharp.Drawing.Brushes
///
private static readonly bool[,] Percent20Pattern =
{
- { true, false, true, false },
- { false, false, false, false },
- { false, true, false, true },
- { false, false, false, false }
+ { true, false, false, false },
+ { false, false, true, false },
+ { true, false, false, false },
+ { false, false, true, false }
};
///
@@ -48,7 +47,10 @@ namespace ImageSharp.Drawing.Brushes
///
private static readonly bool[,] HorizontalPattern =
{
- { false, true, false, false },
+ { false },
+ { true },
+ { false },
+ { false }
};
///
@@ -56,7 +58,10 @@ namespace ImageSharp.Drawing.Brushes
///
private static readonly bool[,] MinPattern =
{
- { false, false, false, true },
+ { false },
+ { false },
+ { false },
+ { true }
};
///
@@ -64,10 +69,7 @@ namespace ImageSharp.Drawing.Brushes
///
private static readonly bool[,] VerticalPattern =
{
- { false },
- { true },
- { false },
- { false }
+ { false, true, false, false },
};
///
@@ -75,10 +77,10 @@ namespace ImageSharp.Drawing.Brushes
///
private static readonly bool[,] ForwardDiagonalPattern =
{
- { true, false, false, false },
- { false, true, false, false },
+ { false, false, false, true },
{ false, false, true, false },
- { false, false, false, true }
+ { false, true, false, false },
+ { true, false, false, false }
};
///
@@ -86,10 +88,10 @@ namespace ImageSharp.Drawing.Brushes
///
private static readonly bool[,] BackwardDiagonalPattern =
{
- { false, false, false, true },
- { false, false, true, false },
+ { true, false, false, false },
{ false, true, false, false },
- { true, false, false, false }
+ { false, false, true, false },
+ { false, false, false, true }
};
///
diff --git a/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs
index 2707c00642..ace929bd6a 100644
--- a/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs
+++ b/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs
@@ -34,7 +34,7 @@ namespace ImageSharp.Drawing.Brushes
///
public BrushApplicator CreateApplicator(PixelAccessor sourcePixels, RectangleF region)
{
- return new ImageBrushApplicator(this.image, region);
+ return new ImageBrushApplicator(sourcePixels, this.image, region);
}
///
@@ -71,12 +71,16 @@ namespace ImageSharp.Drawing.Brushes
///
/// The region.
///
- public ImageBrushApplicator(IImageBase image, RectangleF region)
+ ///
+ /// The sourcePixels.
+ ///
+ public ImageBrushApplicator(PixelAccessor sourcePixels, IImageBase image, RectangleF region)
+ : base(sourcePixels)
{
this.source = image.Lock();
this.xLength = image.Width;
this.yLength = image.Height;
- this.offset = new Vector2((float)Math.Max(Math.Floor(region.Top), 0), (float)Math.Max(Math.Floor(region.Left), 0));
+ this.offset = new Vector2(MathF.Max(MathF.Floor(region.Top), 0), MathF.Max(MathF.Floor(region.Left), 0));
}
///
@@ -87,18 +91,18 @@ namespace ImageSharp.Drawing.Brushes
///
/// The color
///
- public override TColor this[int x, int y]
+ internal override TColor this[int x, int y]
{
get
{
- var point = new Vector2(x, y);
+ Vector2 point = new Vector2(x, y);
// Offset the requested pixel by the value in the rectangle (the shapes position)
point = point - this.offset;
- x = (int)point.X % this.xLength;
- y = (int)point.Y % this.yLength;
+ int srcX = (int)point.X % this.xLength;
+ int srcY = (int)point.Y % this.yLength;
- return this.source[x, y];
+ return this.source[srcX, srcY];
}
}
@@ -107,6 +111,37 @@ namespace ImageSharp.Drawing.Brushes
{
this.source.Dispose();
}
+
+ ///
+ internal override void Apply(float[] scanlineBuffer, int scanlineWidth, int offset, int x, int y)
+ {
+ Guard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
+
+ using (PinnedBuffer buffer = new PinnedBuffer(scanlineBuffer))
+ {
+ BufferSpan slice = buffer.Slice(offset);
+
+ for (int xPos = 0; xPos < scanlineWidth; xPos++)
+ {
+ int targetX = xPos + x;
+ int targetY = y;
+
+ float opacity = slice[xPos];
+ if (opacity > Constants.Epsilon)
+ {
+ Vector4 backgroundVector = this.Target[targetX, targetY].ToVector4();
+
+ Vector4 sourceVector = this[targetX, targetY].ToVector4();
+
+ Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
+
+ TColor packed = default(TColor);
+ packed.PackFromVector4(finalColor);
+ this.Target[targetX, targetY] = packed;
+ }
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs
index 741ab3f005..df492a764e 100644
--- a/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs
+++ b/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs
@@ -30,15 +30,6 @@ namespace ImageSharp.Drawing.Brushes
/// 0
/// 0
///
- /// Warning when use array initializer across multiple lines the bools look inverted i.e.
- /// new bool[,]{
- /// {true, false, false},
- /// {false,true, false}
- /// }
- /// would be
- /// 10
- /// 01
- /// 00
///
/// The pixel format.
public class PatternBrush : IBrush
@@ -47,12 +38,19 @@ namespace ImageSharp.Drawing.Brushes
///
/// The pattern.
///
- private readonly TColor[][] pattern;
+ private readonly Fast2DArray pattern;
+ private readonly Fast2DArray patternVector;
///
- /// The stride width.
+ /// Initializes a new instance of the class.
///
- private readonly int stride;
+ /// Color of the fore.
+ /// Color of the back.
+ /// The pattern.
+ public PatternBrush(TColor foreColor, TColor backColor, bool[,] pattern)
+ : this(foreColor, backColor, new Fast2DArray(pattern))
+ {
+ }
///
/// Initializes a new instance of the class.
@@ -60,26 +58,23 @@ namespace ImageSharp.Drawing.Brushes
/// Color of the fore.
/// Color of the back.
/// The pattern.
- public PatternBrush(TColor foreColor, TColor backColor, bool[,] pattern)
+ internal PatternBrush(TColor foreColor, TColor backColor, Fast2DArray pattern)
{
- this.stride = pattern.GetLength(1);
-
- // Convert the multidimension array into a jagged one.
- int height = pattern.GetLength(0);
- this.pattern = new TColor[height][];
- for (int x = 0; x < height; x++)
+ Vector4 foreColorVector = foreColor.ToVector4();
+ Vector4 backColorVector = backColor.ToVector4();
+ this.pattern = new Fast2DArray(pattern.Width, pattern.Height);
+ this.patternVector = new Fast2DArray(pattern.Width, pattern.Height);
+ for (int i = 0; i < pattern.Data.Length; i++)
{
- this.pattern[x] = new TColor[this.stride];
- for (int y = 0; y < this.stride; y++)
+ if (pattern.Data[i])
{
- if (pattern[x, y])
- {
- this.pattern[x][y] = foreColor;
- }
- else
- {
- this.pattern[x][y] = backColor;
- }
+ this.pattern.Data[i] = foreColor;
+ this.patternVector.Data[i] = foreColorVector;
+ }
+ else
+ {
+ this.pattern.Data[i] = backColor;
+ this.patternVector.Data[i] = backColorVector;
}
}
}
@@ -91,13 +86,13 @@ namespace ImageSharp.Drawing.Brushes
internal PatternBrush(PatternBrush brush)
{
this.pattern = brush.pattern;
- this.stride = brush.stride;
+ this.patternVector = brush.patternVector;
}
///
public BrushApplicator CreateApplicator(PixelAccessor sourcePixels, RectangleF region)
{
- return new PatternBrushApplicator(this.pattern, this.stride);
+ return new PatternBrushApplicator(sourcePixels, this.pattern, this.patternVector);
}
///
@@ -105,31 +100,23 @@ namespace ImageSharp.Drawing.Brushes
///
private class PatternBrushApplicator : BrushApplicator
{
- ///
- /// The patter x-length.
- ///
- private readonly int xLength;
-
- ///
- /// The stride width.
- ///
- private readonly int stride;
-
///
/// The pattern.
///
- private readonly TColor[][] pattern;
+ private readonly Fast2DArray pattern;
+ private readonly Fast2DArray patternVector;
///
/// Initializes a new instance of the class.
///
+ /// The sourcePixels.
/// The pattern.
- /// The stride.
- public PatternBrushApplicator(TColor[][] pattern, int stride)
+ /// The patternVector.
+ public PatternBrushApplicator(PixelAccessor sourcePixels, Fast2DArray pattern, Fast2DArray patternVector)
+ : base(sourcePixels)
{
this.pattern = pattern;
- this.xLength = pattern.Length;
- this.stride = stride;
+ this.patternVector = patternVector;
}
///
@@ -140,14 +127,15 @@ namespace ImageSharp.Drawing.Brushes
///
/// The Color.
///
- public override TColor this[int x, int y]
+ internal override TColor this[int x, int y]
{
get
{
- x = x % this.xLength;
- y = y % this.stride;
+ x = x % this.pattern.Width;
+ y = y % this.pattern.Height;
- return this.pattern[x][y];
+ // 2d array index at row/column
+ return this.pattern[y, x];
}
}
@@ -156,6 +144,38 @@ namespace ImageSharp.Drawing.Brushes
{
// noop
}
+
+ ///
+ internal override void Apply(float[] scanlineBuffer, int scanlineWidth, int offset, int x, int y)
+ {
+ Guard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
+
+ using (PinnedBuffer buffer = new PinnedBuffer(scanlineBuffer))
+ {
+ BufferSpan slice = buffer.Slice(offset);
+
+ for (int xPos = 0; xPos < scanlineWidth; xPos++)
+ {
+ int targetX = xPos + x;
+ int targetY = y;
+
+ float opacity = slice[xPos];
+ if (opacity > Constants.Epsilon)
+ {
+ Vector4 backgroundVector = this.Target[targetX, targetY].ToVector4();
+
+ // 2d array index at row/column
+ Vector4 sourceVector = this.patternVector[targetY % this.patternVector.Height, targetX % this.patternVector.Width];
+
+ Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
+
+ TColor packed = default(TColor);
+ packed.PackFromVector4(finalColor);
+ this.Target[targetX, targetY] = packed;
+ }
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
index b66827e491..46444e5503 100644
--- a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
+++ b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
@@ -7,6 +7,7 @@ namespace ImageSharp.Drawing.Processors
{
using System;
using System.Numerics;
+ using System.Runtime.CompilerServices;
///
/// primitive that converts a point in to a color for discovering the fill color based on an implementation
@@ -16,15 +17,68 @@ namespace ImageSharp.Drawing.Processors
public abstract class BrushApplicator : IDisposable // disposable will be required if/when there is an ImageBrush
where TColor : struct, IPixel
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The target.
+ internal BrushApplicator(PixelAccessor target)
+ {
+ this.Target = target;
+ }
+
+ ///
+ /// Gets the destinaion
+ ///
+ protected PixelAccessor Target { get; }
+
///
/// Gets the color for a single pixel.
///
/// The x cordinate.
/// The y cordinate.
/// The a that should be applied to the pixel.
- public abstract TColor this[int x, int y] { get; }
+ internal abstract TColor this[int x, int y] { get; }
///
public abstract void Dispose();
+
+ ///
+ /// Applies the opactiy weighting for each pixel in a scanline to the target based on the pattern contained in the brush.
+ ///
+ /// The a collection of opacity values between 0 and 1 to be merged with the brushed color value before being applied to the target.
+ /// The number of pixels effected by this scanline.
+ /// The offset fromthe begining of the opacity data starts.
+ /// The x position in the target pixel space that the start of the scanline data corresponds to.
+ /// The y position in the target pixel space that whole scanline corresponds to.
+ /// scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.
+ internal virtual void Apply(float[] scanlineBuffer, int scanlineWidth, int offset, int x, int y)
+ {
+ DebugGuard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
+
+ using (PinnedBuffer buffer = new PinnedBuffer(scanlineBuffer))
+ {
+ BufferSpan slice = buffer.Slice(offset);
+
+ for (int xPos = 0; xPos < scanlineWidth; xPos++)
+ {
+ int targetX = xPos + x;
+ int targetY = y;
+
+ float opacity = slice[xPos];
+ if (opacity > Constants.Epsilon)
+ {
+ Vector4 backgroundVector = this.Target[targetX, targetY].ToVector4();
+
+ Vector4 sourceVector = this[targetX, targetY].ToVector4();
+
+ Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
+
+ TColor packed = default(TColor);
+ packed.PackFromVector4(finalColor);
+ this.Target[targetX, targetY] = packed;
+ }
+ }
+ }
+ }
}
}
diff --git a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs
index 542c3cfed6..257eeb3ae5 100644
--- a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs
+++ b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs
@@ -65,11 +65,6 @@ namespace ImageSharp.Drawing.Brushes
///
private class RecolorBrushApplicator : BrushApplicator
{
- ///
- /// The source pixel accessor.
- ///
- private readonly PixelAccessor source;
-
///
/// The source color.
///
@@ -93,8 +88,8 @@ namespace ImageSharp.Drawing.Brushes
/// Color of the target.
/// The threshold .
public RecolorBrushApplicator(PixelAccessor sourcePixels, TColor sourceColor, TColor targetColor, float threshold)
+ : base(sourcePixels)
{
- this.source = sourcePixels;
this.sourceColor = sourceColor.ToVector4();
this.targetColor = targetColor.ToVector4();
@@ -114,17 +109,17 @@ namespace ImageSharp.Drawing.Brushes
///
/// The color
///
- public override TColor this[int x, int y]
+ internal override TColor this[int x, int y]
{
get
{
// Offset the requested pixel by the value in the rectangle (the shapes position)
- TColor result = this.source[x, y];
+ TColor result = this.Target[x, y];
Vector4 background = result.ToVector4();
float distance = Vector4.DistanceSquared(background, this.sourceColor);
if (distance <= this.threshold)
{
- var lerpAmount = (this.threshold - distance) / this.threshold;
+ float lerpAmount = (this.threshold - distance) / this.threshold;
Vector4 blended = Vector4BlendTransforms.PremultipliedLerp(
background,
this.targetColor,
@@ -140,6 +135,46 @@ namespace ImageSharp.Drawing.Brushes
public override void Dispose()
{
}
+
+ ///
+ internal override void Apply(float[] scanlineBuffer, int scanlineWidth, int offset, int x, int y)
+ {
+ Guard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
+
+ using (PinnedBuffer buffer = new PinnedBuffer(scanlineBuffer))
+ {
+ BufferSpan slice = buffer.Slice(offset);
+
+ for (int xPos = 0; xPos < scanlineWidth; xPos++)
+ {
+ int targetX = xPos + x;
+ int targetY = y;
+
+ float opacity = slice[xPos];
+ if (opacity > Constants.Epsilon)
+ {
+ Vector4 backgroundVector = this.Target[targetX, targetY].ToVector4();
+
+ Vector4 sourceVector = backgroundVector;
+ float distance = Vector4.DistanceSquared(sourceVector, this.sourceColor);
+ if (distance <= this.threshold)
+ {
+ float lerpAmount = (this.threshold - distance) / this.threshold;
+ sourceVector = Vector4BlendTransforms.PremultipliedLerp(
+ sourceVector,
+ this.targetColor,
+ lerpAmount);
+
+ Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
+
+ TColor packed = default(TColor);
+ packed.PackFromVector4(finalColor);
+ this.Target[targetX, targetY] = packed;
+ }
+ }
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs
index 30351dbe1b..125b07bcac 100644
--- a/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs
+++ b/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs
@@ -42,7 +42,7 @@ namespace ImageSharp.Drawing.Brushes
///
public BrushApplicator CreateApplicator(PixelAccessor sourcePixels, RectangleF region)
{
- return new SolidBrushApplicator(this.color);
+ return new SolidBrushApplicator(sourcePixels, this.color);
}
///
@@ -54,14 +54,18 @@ namespace ImageSharp.Drawing.Brushes
/// The solid color.
///
private readonly TColor color;
+ private readonly Vector4 colorVector;
///
/// Initializes a new instance of the class.
///
/// The color.
- public SolidBrushApplicator(TColor color)
+ /// The sourcePixels.
+ public SolidBrushApplicator(PixelAccessor sourcePixels, TColor color)
+ : base(sourcePixels)
{
this.color = color;
+ this.colorVector = color.ToVector4();
}
///
@@ -72,13 +76,43 @@ namespace ImageSharp.Drawing.Brushes
///
/// The color
///
- public override TColor this[int x, int y] => this.color;
+ internal override TColor this[int x, int y] => this.color;
///
public override void Dispose()
{
// noop
}
+
+ ///
+ internal override void Apply(float[] scanlineBuffer, int scanlineWidth, int offset, int x, int y)
+ {
+ Guard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
+
+ using (PinnedBuffer buffer = new PinnedBuffer(scanlineBuffer))
+ {
+ BufferSpan slice = buffer.Slice(offset);
+
+ for (int xPos = 0; xPos < scanlineWidth; xPos++)
+ {
+ int targetX = xPos + x;
+ int targetY = y;
+
+ float opacity = slice[xPos];
+ if (opacity > Constants.Epsilon)
+ {
+ Vector4 backgroundVector = this.Target[targetX, targetY].ToVector4();
+ Vector4 sourceVector = this.colorVector;
+
+ Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
+
+ TColor packed = default(TColor);
+ packed.PackFromVector4(finalColor);
+ this.Target[targetX, targetY] = packed;
+ }
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/GraphicsOptions.cs b/src/ImageSharp.Drawing/GraphicsOptions.cs
index 7e569c9a5f..a21617eadf 100644
--- a/src/ImageSharp.Drawing/GraphicsOptions.cs
+++ b/src/ImageSharp.Drawing/GraphicsOptions.cs
@@ -20,6 +20,11 @@ namespace ImageSharp.Drawing
///
public bool Antialias;
+ ///
+ /// The number of subpixels to use while rendering with antialiasing enabled.
+ ///
+ public int AntialiasSubpixelDepth;
+
///
/// Initializes a new instance of the struct.
///
@@ -27,6 +32,7 @@ namespace ImageSharp.Drawing
public GraphicsOptions(bool enableAntialiasing)
{
this.Antialias = enableAntialiasing;
+ this.AntialiasSubpixelDepth = 16;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
index cc1c526ae3..351764bb95 100644
--- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
+++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
@@ -2,7 +2,7 @@
An extension to ImageSharp that allows the drawing of images, paths, and text.ImageSharp.Drawing
- 1.0.0-alpha3
+ 1.0.0-alpha5James Jackson-South and contributorsnetstandard1.1true
@@ -40,7 +40,7 @@
All
-
+ ..\..\ImageSharp.ruleset
diff --git a/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs b/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs
index 2fa5fe43f2..1b5df75742 100644
--- a/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs
+++ b/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs
@@ -19,10 +19,10 @@ namespace ImageSharp.Drawing
/// A representation of this
public static Rectangle Convert(this SixLabors.Shapes.Rectangle source)
{
- int left = (int)Math.Floor(source.Left);
- int right = (int)Math.Ceiling(source.Right);
- int top = (int)Math.Floor(source.Top);
- int bottom = (int)Math.Ceiling(source.Bottom);
+ 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);
}
}
diff --git a/src/ImageSharp.Drawing/Paths/ShapeRegion.cs b/src/ImageSharp.Drawing/Paths/ShapeRegion.cs
index b02c5c2e5b..0868945318 100644
--- a/src/ImageSharp.Drawing/Paths/ShapeRegion.cs
+++ b/src/ImageSharp.Drawing/Paths/ShapeRegion.cs
@@ -5,6 +5,7 @@
namespace ImageSharp.Drawing
{
+ using System;
using System.Buffers;
using System.Numerics;
@@ -39,30 +40,7 @@ namespace ImageSharp.Drawing
public override Rectangle Bounds { get; }
///
- public override int ScanX(int x, float[] buffer, int length, int offset)
- {
- Vector2 start = new Vector2(x, this.Bounds.Top - 1);
- Vector2 end = new Vector2(x, this.Bounds.Bottom + 1);
- Vector2[] innerbuffer = ArrayPool.Shared.Rent(length);
- try
- {
- int count = this.Shape.FindIntersections(start, end, innerbuffer, length, 0);
-
- for (int i = 0; i < count; i++)
- {
- buffer[i + offset] = innerbuffer[i].Y;
- }
-
- return count;
- }
- finally
- {
- ArrayPool.Shared.Return(innerbuffer);
- }
- }
-
- ///
- public override int ScanY(int y, float[] buffer, int length, int offset)
+ public override int Scan(float y, float[] buffer, int length, int offset)
{
Vector2 start = new Vector2(this.Bounds.Left - 1, y);
Vector2 end = new Vector2(this.Bounds.Right + 1, y);
diff --git a/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs b/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs
index 79a5d6b15a..e3716124e3 100644
--- a/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs
+++ b/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs
@@ -146,7 +146,7 @@ namespace ImageSharp.Drawing.Pens
public override ColoredPointInfo GetColor(int x, int y, PointInfo info)
{
- var result = default(ColoredPointInfo);
+ ColoredPointInfo result = default(ColoredPointInfo);
result.Color = this.brush[x, y];
if (info.DistanceFromPath < this.halfWidth)
@@ -178,7 +178,7 @@ namespace ImageSharp.Drawing.Pens
this.pattern = new float[pattern.Length + 1];
this.pattern[0] = 0;
- for (var i = 0; i < pattern.Length; i++)
+ for (int i = 0; i < pattern.Length; i++)
{
this.totalLength += pattern[i] * width;
this.pattern[i + 1] = this.totalLength;
@@ -199,10 +199,10 @@ namespace ImageSharp.Drawing.Pens
public override ColoredPointInfo GetColor(int x, int y, PointInfo info)
{
- var infoResult = default(ColoredPointInfo);
+ ColoredPointInfo infoResult = default(ColoredPointInfo);
infoResult.DistanceFromElement = float.MaxValue; // is really outside the element
- var length = info.DistanceAlongPath % this.totalLength;
+ float length = info.DistanceAlongPath % this.totalLength;
// we can treat the DistanceAlongPath and DistanceFromPath as x,y coords for the pattern
// we need to calcualte the distance from the outside edge of the pattern
@@ -221,10 +221,10 @@ namespace ImageSharp.Drawing.Pens
distanceWAway = info.DistanceFromPath - this.halfWidth;
}
- for (var i = 0; i < this.pattern.Length - 1; i++)
+ for (int i = 0; i < this.pattern.Length - 1; i++)
{
- var start = this.pattern[i];
- var end = this.pattern[i + 1];
+ float start = this.pattern[i];
+ float end = this.pattern[i + 1];
if (length >= start && length < end)
{
@@ -238,12 +238,12 @@ namespace ImageSharp.Drawing.Pens
else
{
// this is a none solid part
- var distanceFromStart = length - start;
- var distanceFromEnd = end - length;
+ float distanceFromStart = length - start;
+ float distanceFromEnd = end - length;
- var closestEdge = Math.Min(distanceFromStart, distanceFromEnd);
+ float closestEdge = MathF.Min(distanceFromStart, distanceFromEnd);
- var distanceAcross = closestEdge;
+ float distanceAcross = closestEdge;
if (distanceWAway > 0)
{
diff --git a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
index 1c1de45cbc..c67ba0370b 100644
--- a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
@@ -15,7 +15,7 @@ namespace ImageSharp.Drawing.Processors
/// Combines two images together by blending the pixels.
///
/// The pixel format.
- public class DrawImageProcessor : ImageProcessor
+ internal class DrawImageProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
index 95f4ab4726..89ba0968bb 100644
--- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
@@ -17,7 +17,7 @@ namespace ImageSharp.Drawing.Processors
///
/// The type of the color.
///
- public class DrawPathProcessor : ImageProcessor
+ internal class DrawPathProcessor : ImageProcessor
where TColor : struct, IPixel
{
private const float AntialiasFactor = 1f;
diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs
index 9fa01075d4..635829e9f1 100644
--- a/src/ImageSharp.Drawing/Processors/FillProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/FillProcessor.cs
@@ -16,8 +16,8 @@ namespace ImageSharp.Drawing.Processors
/// Using the bursh as a source of pixels colors blends the brush color with source.
///
/// The pixel format.
- public class FillProcessor : ImageProcessor
- where TColor : struct, IPixel
+ internal class FillProcessor : ImageProcessor
+ where TColor : struct, IPixel
{
///
/// The brush.
diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
index 4f468c7070..80a3e67932 100644
--- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
@@ -17,7 +17,7 @@ namespace ImageSharp.Drawing.Processors
///
/// The type of the color.
///
- public class FillRegionProcessor : ImageProcessor
+ internal class FillRegionProcessor : ImageProcessor
where TColor : struct, IPixel
{
private const float AntialiasFactor = 1f;
@@ -57,315 +57,136 @@ namespace ImageSharp.Drawing.Processors
///
protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
{
- Rectangle rect = this.Region.Bounds;
-
- int polyStartY = sourceRectangle.Y - DrawPadding;
- int polyEndY = sourceRectangle.Bottom + DrawPadding;
- int startX = sourceRectangle.X - DrawPadding;
- int endX = sourceRectangle.Right + DrawPadding;
-
- int minX = Math.Max(sourceRectangle.Left, startX);
- int maxX = Math.Min(sourceRectangle.Right - 1, endX);
- int minY = Math.Max(sourceRectangle.Top, polyStartY);
- int maxY = Math.Min(sourceRectangle.Bottom - 1, polyEndY);
+ Region region = this.Region;
+ Rectangle rect = region.Bounds;
// Align start/end positions.
- minX = Math.Max(0, minX);
- maxX = Math.Min(source.Width, maxX);
- minY = Math.Max(0, minY);
- maxY = Math.Min(source.Height, maxY);
+ int minX = Math.Max(0, rect.Left);
+ int maxX = Math.Min(source.Width, rect.Right);
+ int minY = Math.Max(0, rect.Top);
+ int maxY = Math.Min(source.Height, rect.Bottom);
+ if (minX >= maxX)
+ {
+ return; // no effect inside image;
+ }
+
+ if (minY >= maxY)
+ {
+ return; // no effect inside image;
+ }
ArrayPool arrayPool = ArrayPool.Shared;
- int maxIntersections = this.Region.MaxIntersections;
+ int maxIntersections = region.MaxIntersections;
+ float subpixelCount = 4;
+ if (this.Options.Antialias)
+ {
+ subpixelCount = this.Options.AntialiasSubpixelDepth;
+ if (subpixelCount < 4)
+ {
+ subpixelCount = 4;
+ }
+ }
using (PixelAccessor sourcePixels = source.Lock())
using (BrushApplicator applicator = this.Brush.CreateApplicator(sourcePixels, rect))
{
- Parallel.For(
- minY,
- maxY,
- this.ParallelOptions,
- (int y) =>
+ float[] buffer = arrayPool.Rent(maxIntersections);
+ int scanlineWidth = maxX - minX;
+ float[] scanline = ArrayPool.Shared.Rent(scanlineWidth);
+ try
{
- float[] buffer = arrayPool.Rent(maxIntersections);
-
- try
+ bool scanlineDirty = true;
+ for (int y = minY; y < maxY; y++)
{
- float right = endX;
-
- // foreach line we get all the points where this line crosses the polygon
- int pointsFound = this.Region.ScanY(y, buffer, maxIntersections, 0);
- if (pointsFound == 0)
+ if (scanlineDirty)
{
- // nothing on this line skip
- return;
- }
-
- QuickSort(buffer, pointsFound);
-
- int currentIntersection = 0;
- float nextPoint = buffer[0];
- float lastPoint = float.MinValue;
- bool isInside = false;
-
- for (int x = minX; x < maxX; x++)
- {
- if (!isInside)
- {
- if (x < (nextPoint - DrawPadding) && x > (lastPoint + DrawPadding))
- {
- if (nextPoint == right)
- {
- // we are in the ends run skip it
- x = maxX;
- continue;
- }
-
- // lets just jump forward
- x = (int)Math.Floor(nextPoint) - DrawPadding;
- }
- }
-
- bool onCorner = false;
-
- // there seems to be some issue with this switch.
- if (x >= nextPoint)
+ // clear the buffer
+ for (int x = 0; x < scanlineWidth; x++)
{
- currentIntersection++;
- lastPoint = nextPoint;
- if (currentIntersection == pointsFound)
- {
- nextPoint = right;
- }
- else
- {
- nextPoint = buffer[currentIntersection];
-
- // double point from a corner flip the bit back and move on again
- if (nextPoint == lastPoint)
- {
- onCorner = true;
- isInside ^= true;
- currentIntersection++;
- if (currentIntersection == pointsFound)
- {
- nextPoint = right;
- }
- else
- {
- nextPoint = buffer[currentIntersection];
- }
- }
- }
-
- isInside ^= true;
+ scanline[x] = 0;
}
- float opacity = 1;
- if (!isInside && !onCorner)
- {
- if (this.Options.Antialias)
- {
- float distance = float.MaxValue;
- if (x == lastPoint || x == nextPoint)
- {
- // we are to far away from the line
- distance = 0;
- }
- else if (nextPoint - AntialiasFactor < x)
- {
- // we are near the left of the line
- distance = nextPoint - x;
- }
- else if (lastPoint + AntialiasFactor > x)
- {
- // we are near the right of the line
- distance = x - lastPoint;
- }
- else
- {
- // we are to far away from the line
- continue;
- }
- opacity = 1 - (distance / AntialiasFactor);
- }
- else
- {
- continue;
- }
- }
-
- if (opacity > Constants.Epsilon)
- {
- Vector4 backgroundVector = sourcePixels[x, y].ToVector4();
- Vector4 sourceVector = applicator[x, y].ToVector4();
-
- Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
-
- TColor packed = default(TColor);
- packed.PackFromVector4(finalColor);
- sourcePixels[x, y] = packed;
- }
+ scanlineDirty = false;
}
- }
- finally
- {
- arrayPool.Return(buffer);
- }
- });
-
- if (this.Options.Antialias)
- {
- // we only need to do the X can for antialiasing purposes
- Parallel.For(
- minX,
- maxX,
- this.ParallelOptions,
- (int x) =>
- {
- float[] buffer = arrayPool.Rent(maxIntersections);
- try
+ float subpixelFraction = 1f / subpixelCount;
+ float subpixelFractionPoint = subpixelFraction / subpixelCount;
+ for (float subPixel = (float)y; subPixel < y + 1; subPixel += subpixelFraction)
{
- float left = polyStartY;
- float right = polyEndY;
-
- // foreach line we get all the points where this line crosses the polygon
- int pointsFound = this.Region.ScanX(x, buffer, maxIntersections, 0);
+ int pointsFound = region.Scan(subPixel, buffer, maxIntersections, 0);
if (pointsFound == 0)
{
- // nothign on this line skip
- return;
+ // nothing on this line skip
+ continue;
}
QuickSort(buffer, pointsFound);
- int currentIntersection = 0;
- float nextPoint = buffer[0];
- float lastPoint = left;
- bool isInside = false;
-
- for (int y = minY; y < maxY; y++)
+ for (int point = 0; point < pointsFound; point += 2)
{
- if (!isInside)
+ // points will be paired up
+ float scanStart = buffer[point] - minX;
+ float scanEnd = buffer[point + 1] - minX;
+ int startX = (int)MathF.Floor(scanStart);
+ int endX = (int)MathF.Floor(scanEnd);
+
+ if (startX >= 0 && startX < scanline.Length)
{
- if (y < (nextPoint - DrawPadding) && y > (lastPoint + DrawPadding))
+ for (float x = scanStart; x < startX + 1; x += subpixelFraction)
{
- if (nextPoint == right)
- {
- // we are in the ends run skip it
- y = maxY;
- continue;
- }
-
- // lets just jump forward
- y = (int)Math.Floor(nextPoint) - DrawPadding;
+ scanline[startX] += subpixelFractionPoint;
+ scanlineDirty = true;
}
}
- else
+
+ if (endX >= 0 && endX < scanline.Length)
{
- if (y < nextPoint - DrawPadding)
+ for (float x = endX; x < scanEnd; x += subpixelFraction)
{
- if (nextPoint == right)
- {
- // we are in the ends run skip it
- y = maxY;
- continue;
- }
-
- // lets just jump forward
- y = (int)Math.Floor(nextPoint);
+ scanline[endX] += subpixelFractionPoint;
+ scanlineDirty = true;
}
}
- bool onCorner = false;
-
- if (y >= nextPoint)
+ int nextX = startX + 1;
+ endX = Math.Min(endX, scanline.Length); // reduce to end to the right edge
+ if (nextX >= 0)
{
- currentIntersection++;
- lastPoint = nextPoint;
- if (currentIntersection == pointsFound)
- {
- nextPoint = right;
- }
- else
+ for (int x = nextX; x < endX; x++)
{
- nextPoint = buffer[currentIntersection];
-
- // double point from a corner flip the bit back and move on again
- if (nextPoint == lastPoint)
- {
- onCorner = true;
- isInside ^= true;
- currentIntersection++;
- if (currentIntersection == pointsFound)
- {
- nextPoint = right;
- }
- else
- {
- nextPoint = buffer[currentIntersection];
- }
- }
+ scanline[x] += subpixelFraction;
+ scanlineDirty = true;
}
-
- isInside ^= true;
}
+ }
+ }
- float opacity = 1;
- if (!isInside && !onCorner)
+ if (scanlineDirty)
+ {
+ if (!this.Options.Antialias)
+ {
+ for (int x = 0; x < scanlineWidth; x++)
{
- if (this.Options.Antialias)
+ if (scanline[x] > 0.5)
{
- float distance = float.MaxValue;
- if (y == lastPoint || y == nextPoint)
- {
- // we are to far away from the line
- distance = 0;
- }
- else if (nextPoint - AntialiasFactor < y)
- {
- // we are near the left of the line
- distance = nextPoint - y;
- }
- else if (lastPoint + AntialiasFactor > y)
- {
- // we are near the right of the line
- distance = y - lastPoint;
- }
- else
- {
- // we are to far away from the line
- continue;
- }
- opacity = 1 - (distance / AntialiasFactor);
+ scanline[x] = 1;
}
else
{
- continue;
+ scanline[x] = 0;
}
}
-
- // don't set full opactiy color as it will have been gotten by the first scan
- if (opacity > Constants.Epsilon && opacity < 1)
- {
- Vector4 backgroundVector = sourcePixels[x, y].ToVector4();
- Vector4 sourceVector = applicator[x, y].ToVector4();
- Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
- finalColor.W = backgroundVector.W;
-
- TColor packed = default(TColor);
- packed.PackFromVector4(finalColor);
- sourcePixels[x, y] = packed;
- }
}
+
+ applicator.Apply(scanline, scanlineWidth, 0, minX, y);
}
- finally
- {
- arrayPool.Return(buffer);
- }
- });
+ }
+ }
+ finally
+ {
+ arrayPool.Return(buffer);
+ ArrayPool.Shared.Return(scanline);
}
}
}
diff --git a/src/ImageSharp.Drawing/Region.cs b/src/ImageSharp.Drawing/Region.cs
index fe1dc52221..8cab885021 100644
--- a/src/ImageSharp.Drawing/Region.cs
+++ b/src/ImageSharp.Drawing/Region.cs
@@ -19,28 +19,18 @@ namespace ImageSharp.Drawing
/// Gets the bounding box that entirely surrounds this region.
///
///
- /// This should always contains all possible points returned from either or .
+ /// This should always contains all possible points returned from .
///
public abstract Rectangle Bounds { get; }
///
- /// Scans the X axis for intersections.
- ///
- /// The position along the X axis to find intersections.
- /// The buffer.
- /// The length.
- /// The offset.
- /// The number of intersections found.
- public abstract int ScanX(int x, float[] buffer, int length, int offset);
-
- ///
- /// Scans the Y axis for intersections.
+ /// Scans the X axis for intersections at the Y axis position.
///
/// The position along the y axis to find intersections.
/// The buffer.
/// The length.
/// The offset.
/// The number of intersections found.
- public abstract int ScanY(int y, float[] buffer, int length, int offset);
+ public abstract int Scan(float y, float[] buffer, int length, int offset);
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Text/DrawText.cs b/src/ImageSharp.Drawing/Text/DrawText.cs
index 28781fab22..1f5f4cdb12 100644
--- a/src/ImageSharp.Drawing/Text/DrawText.cs
+++ b/src/ImageSharp.Drawing/Text/DrawText.cs
@@ -18,6 +18,8 @@ namespace ImageSharp
///
public static partial class ImageExtensions
{
+ private static readonly Vector2 DefaultTextDpi = new Vector2(72);
+
///
/// Draws the text onto the the image filled via the brush.
///
@@ -169,7 +171,12 @@ namespace ImageSharp
TextRenderer renderer = new TextRenderer(glyphBuilder);
- Vector2 dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution);
+ Vector2 dpi = DefaultTextDpi;
+ if (options.UseImageResolution)
+ {
+ dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution);
+ }
+
FontSpan style = new FontSpan(font)
{
ApplyKerning = options.ApplyKerning,
diff --git a/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
index e707ef5e50..b58a40b34d 100644
--- a/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
+++ b/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
@@ -20,6 +20,11 @@ namespace ImageSharp.Drawing
///
public bool Antialias;
+ ///
+ /// The number of subpixels to use while rendering with antialiasing enabled.
+ ///
+ public int AntialiasSubpixelDepth;
+
///
/// Whether the text should be drawing with kerning enabled.
///
@@ -30,6 +35,12 @@ namespace ImageSharp.Drawing
///
public float TabWidth;
+ ///
+ /// Flag weather to use the current image resultion to for point size scaling.
+ /// If this is [false] the text renders at 72dpi otherwise it renders at Image resolution
+ ///
+ public bool UseImageResolution;
+
///
/// Initializes a new instance of the struct.
///
@@ -39,6 +50,8 @@ namespace ImageSharp.Drawing
this.Antialias = enableAntialiasing;
this.ApplyKerning = true;
this.TabWidth = 4;
+ this.AntialiasSubpixelDepth = 16;
+ this.UseImageResolution = false;
}
///
@@ -50,7 +63,10 @@ namespace ImageSharp.Drawing
///
public static implicit operator TextGraphicsOptions(GraphicsOptions options)
{
- return new TextGraphicsOptions(options.Antialias);
+ return new TextGraphicsOptions(options.Antialias)
+ {
+ AntialiasSubpixelDepth = options.AntialiasSubpixelDepth
+ };
}
///
@@ -62,7 +78,10 @@ namespace ImageSharp.Drawing
///
public static explicit operator GraphicsOptions(TextGraphicsOptions options)
{
- return new GraphicsOptions(options.Antialias);
+ return new GraphicsOptions(options.Antialias)
+ {
+ AntialiasSubpixelDepth = options.AntialiasSubpixelDepth
+ };
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs
index 5c040e04c5..7d3b12ea0b 100644
--- a/src/ImageSharp/Colors/Color.BulkOperations.cs
+++ b/src/ImageSharp/Colors/Color.BulkOperations.cs
@@ -24,8 +24,8 @@ namespace ImageSharp
/// SIMD optimized bulk implementation of
/// that works only with `count` divisible by .
///
- /// The to the source colors.
- /// The to the dstination vectors.
+ /// The to the source colors.
+ /// The to the dstination vectors.
/// The number of pixels to convert.
///
/// Implementation adapted from:
@@ -38,10 +38,16 @@ namespace ImageSharp
///
///
internal static unsafe void ToVector4SimdAligned(
- BufferPointer sourceColors,
- BufferPointer destVectors,
+ BufferSpan sourceColors,
+ BufferSpan destVectors,
int count)
{
+ if (!Vector.IsHardwareAccelerated)
+ {
+ throw new InvalidOperationException(
+ "Color.BulkOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!");
+ }
+
int vecSize = Vector.Count;
DebugGuard.IsTrue(
@@ -85,14 +91,14 @@ namespace ImageSharp
vf.CopyTo(fTemp, i);
}
- BufferPointer.Copy(tempBuf, (BufferPointer)destVectors, unpackedRawCount);
+ BufferSpan.Copy(tempBuf, (BufferSpan)destVectors, unpackedRawCount);
}
}
///
- internal override void ToVector4(BufferPointer sourceColors, BufferPointer destVectors, int count)
+ internal override void ToVector4(BufferSpan sourceColors, BufferSpan destVectors, int count)
{
- if (count < 256)
+ if (count < 256 || !Vector.IsHardwareAccelerated)
{
// Doesn't worth to bother with SIMD:
base.ToVector4(sourceColors, destVectors, count);
@@ -117,7 +123,7 @@ namespace ImageSharp
}
///
- internal override unsafe void PackFromXyzBytes(BufferPointer sourceBytes, BufferPointer destColors, int count)
+ internal override unsafe void PackFromXyzBytes(BufferSpan sourceBytes, BufferSpan destColors, int count)
{
byte* source = (byte*)sourceBytes;
byte* destination = (byte*)destColors;
@@ -132,7 +138,7 @@ namespace ImageSharp
}
///
- internal override unsafe void ToXyzBytes(BufferPointer sourceColors, BufferPointer destBytes, int count)
+ internal override unsafe void ToXyzBytes(BufferSpan sourceColors, BufferSpan destBytes, int count)
{
byte* source = (byte*)sourceColors;
byte* destination = (byte*)destBytes;
@@ -149,19 +155,19 @@ namespace ImageSharp
}
///
- internal override void PackFromXyzwBytes(BufferPointer sourceBytes, BufferPointer destColors, int count)
+ internal override void PackFromXyzwBytes(BufferSpan sourceBytes, BufferSpan destColors, int count)
{
- BufferPointer.Copy(sourceBytes, destColors, count);
+ BufferSpan.Copy(sourceBytes, destColors, count);
}
///
- internal override void ToXyzwBytes(BufferPointer sourceColors, BufferPointer destBytes, int count)
+ internal override void ToXyzwBytes(BufferSpan sourceColors, BufferSpan destBytes, int count)
{
- BufferPointer.Copy(sourceColors, destBytes, count);
+ BufferSpan.Copy(sourceColors, destBytes, count);
}
///
- internal override unsafe void PackFromZyxBytes(BufferPointer sourceBytes, BufferPointer destColors, int count)
+ internal override unsafe void PackFromZyxBytes(BufferSpan sourceBytes, BufferSpan destColors, int count)
{
byte* source = (byte*)sourceBytes;
byte* destination = (byte*)destColors;
@@ -176,7 +182,7 @@ namespace ImageSharp
}
///
- internal override unsafe void ToZyxBytes(BufferPointer sourceColors, BufferPointer destBytes, int count)
+ internal override unsafe void ToZyxBytes(BufferSpan sourceColors, BufferSpan destBytes, int count)
{
byte* source = (byte*)sourceColors;
byte* destination = (byte*)destBytes;
@@ -193,7 +199,7 @@ namespace ImageSharp
}
///
- internal override unsafe void PackFromZyxwBytes(BufferPointer sourceBytes, BufferPointer destColors, int count)
+ internal override unsafe void PackFromZyxwBytes(BufferSpan sourceBytes, BufferSpan destColors, int count)
{
byte* source = (byte*)sourceBytes;
byte* destination = (byte*)destColors;
@@ -208,7 +214,7 @@ namespace ImageSharp
}
///
- internal override unsafe void ToZyxwBytes(BufferPointer sourceColors, BufferPointer destBytes, int count)
+ internal override unsafe void ToZyxwBytes(BufferSpan sourceColors, BufferSpan destBytes, int count)
{
byte* source = (byte*)sourceColors;
byte* destination = (byte*)destBytes;
diff --git a/src/ImageSharp/Colors/ColorspaceTransforms.cs b/src/ImageSharp/Colors/ColorspaceTransforms.cs
index cda7022705..74f5cb7175 100644
--- a/src/ImageSharp/Colors/ColorspaceTransforms.cs
+++ b/src/ImageSharp/Colors/ColorspaceTransforms.cs
@@ -105,12 +105,12 @@ namespace ImageSharp
float s = color.S;
float v = color.V;
- if (Math.Abs(s) < Constants.Epsilon)
+ if (MathF.Abs(s) < Constants.Epsilon)
{
return new Color(v, v, v, 1);
}
- float h = (Math.Abs(color.H - 360) < Constants.Epsilon) ? 0 : color.H / 60;
+ float h = (MathF.Abs(color.H - 360) < Constants.Epsilon) ? 0 : color.H / 60;
int i = (int)Math.Truncate(h);
float f = h - i;
@@ -178,9 +178,9 @@ namespace ImageSharp
float s = color.S;
float l = color.L;
- if (Math.Abs(l) > Constants.Epsilon)
+ if (MathF.Abs(l) > Constants.Epsilon)
{
- if (Math.Abs(s) < Constants.Epsilon)
+ if (MathF.Abs(s) < Constants.Epsilon)
{
r = g = b = l;
}
diff --git a/src/ImageSharp/Colors/PackedPixel/Argb.cs b/src/ImageSharp/Colors/PackedPixel/Argb.cs
index 70fd7de8a7..d03c098cdd 100644
--- a/src/ImageSharp/Colors/PackedPixel/Argb.cs
+++ b/src/ImageSharp/Colors/PackedPixel/Argb.cs
@@ -307,7 +307,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y, float z, float w)
{
- var value = new Vector4(x, y, z, w);
+ Vector4 value = new Vector4(x, y, z, w);
return Pack(ref value);
}
@@ -333,7 +333,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(ref Vector3 vector)
{
- var value = new Vector4(vector, 1);
+ Vector4 value = new Vector4(vector, 1);
return Pack(ref value);
}
diff --git a/src/ImageSharp/Colors/PackedPixel/Bgr565.cs b/src/ImageSharp/Colors/PackedPixel/Bgr565.cs
index 77d9434785..2975d4ad90 100644
--- a/src/ImageSharp/Colors/PackedPixel/Bgr565.cs
+++ b/src/ImageSharp/Colors/PackedPixel/Bgr565.cs
@@ -110,9 +110,9 @@ namespace ImageSharp
public void ToXyzBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
}
///
@@ -120,10 +120,10 @@ namespace ImageSharp
public void ToXyzwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
@@ -131,9 +131,9 @@ namespace ImageSharp
public void ToZyxBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
}
///
@@ -141,10 +141,10 @@ namespace ImageSharp
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs
index 259b1c9b47..7b6169f9c6 100644
--- a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs
+++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs
@@ -29,12 +29,12 @@ namespace ImageSharp
///
/// Bulk version of
///
- /// The to the source vectors.
- /// The to the destination colors.
+ /// The to the source vectors.
+ /// The to the destination colors.
/// The number of pixels to convert.
internal virtual void PackFromVector4(
- BufferPointer sourceVectors,
- BufferPointer destColors,
+ BufferSpan sourceVectors,
+ BufferSpan destColors,
int count)
{
Vector4* sp = (Vector4*)sourceVectors.PointerAtOffset;
@@ -55,12 +55,12 @@ namespace ImageSharp
///
/// Bulk version of .
///
- /// The to the source colors.
- /// The to the destination vectors.
+ /// The to the source colors.
+ /// The to the destination vectors.
/// The number of pixels to convert.
internal virtual void ToVector4(
- BufferPointer sourceColors,
- BufferPointer destVectors,
+ BufferSpan sourceColors,
+ BufferSpan destVectors,
int count)
{
byte* sp = (byte*)sourceColors;
@@ -78,12 +78,12 @@ namespace ImageSharp
///
/// Bulk version of that converts data in .
///
- /// The to the source bytes.
- /// The to the destination colors.
+ /// The to the source bytes.
+ /// The to the destination colors.
/// The number of pixels to convert.
internal virtual void PackFromXyzBytes(
- BufferPointer sourceBytes,
- BufferPointer destColors,
+ BufferSpan sourceBytes,
+ BufferSpan destColors,
int count)
{
byte* sp = (byte*)sourceBytes;
@@ -102,15 +102,15 @@ namespace ImageSharp
///
/// Bulk version of .
///
- /// The to the source colors.
- /// The to the destination bytes.
+ /// The to the source colors.
+ /// The to the destination bytes.
/// The number of pixels to convert.
- internal virtual void ToXyzBytes(BufferPointer sourceColors, BufferPointer destBytes, int count)
+ internal virtual void ToXyzBytes(BufferSpan sourceColors, BufferSpan destBytes, int count)
{
byte* sp = (byte*)sourceColors;
byte[] dest = destBytes.Array;
- for (int i = destBytes.Offset; i < destBytes.Offset + (count * 3); i += 3)
+ for (int i = destBytes.Start; i < destBytes.Start + (count * 3); i += 3)
{
TColor c = Unsafe.Read(sp);
c.ToXyzBytes(dest, i);
@@ -121,12 +121,12 @@ namespace ImageSharp
///
/// Bulk version of that converts data in .
///
- /// The to the source bytes.
- /// The to the destination colors.
+ /// The to the source bytes.
+ /// The to the destination colors.
/// The number of pixels to convert.
internal virtual void PackFromXyzwBytes(
- BufferPointer sourceBytes,
- BufferPointer destColors,
+ BufferSpan sourceBytes,
+ BufferSpan destColors,
int count)
{
byte* sp = (byte*)sourceBytes;
@@ -145,18 +145,18 @@ namespace ImageSharp
///
/// Bulk version of .
///
- /// The to the source colors.
- /// The to the destination bytes.
+ /// The to the source colors.
+ /// The to the destination bytes.
/// The number of pixels to convert.
internal virtual void ToXyzwBytes(
- BufferPointer sourceColors,
- BufferPointer destBytes,
+ BufferSpan sourceColors,
+ BufferSpan destBytes,
int count)
{
byte* sp = (byte*)sourceColors;
byte[] dest = destBytes.Array;
- for (int i = destBytes.Offset; i < destBytes.Offset + (count * 4); i += 4)
+ for (int i = destBytes.Start; i < destBytes.Start + (count * 4); i += 4)
{
TColor c = Unsafe.Read(sp);
c.ToXyzwBytes(dest, i);
@@ -167,12 +167,12 @@ namespace ImageSharp
///
/// Bulk version of that converts data in .
///
- /// The to the source bytes.
- /// The to the destination colors.
+ /// The to the source bytes.
+ /// The to the destination colors.
/// The number of pixels to convert.
internal virtual void PackFromZyxBytes(
- BufferPointer sourceBytes,
- BufferPointer destColors,
+ BufferSpan sourceBytes,
+ BufferSpan destColors,
int count)
{
byte* sp = (byte*)sourceBytes;
@@ -191,15 +191,15 @@ namespace ImageSharp
///
/// Bulk version of .
///
- /// The to the source colors.
- /// The to the destination bytes.
+ /// The to the source colors.
+ /// The to the destination bytes.
/// The number of pixels to convert.
- internal virtual void ToZyxBytes(BufferPointer sourceColors, BufferPointer destBytes, int count)
+ internal virtual void ToZyxBytes(BufferSpan sourceColors, BufferSpan destBytes, int count)
{
byte* sp = (byte*)sourceColors;
byte[] dest = destBytes.Array;
- for (int i = destBytes.Offset; i < destBytes.Offset + (count * 3); i += 3)
+ for (int i = destBytes.Start; i < destBytes.Start + (count * 3); i += 3)
{
TColor c = Unsafe.Read(sp);
c.ToZyxBytes(dest, i);
@@ -210,12 +210,12 @@ namespace ImageSharp
///
/// Bulk version of that converts data in .
///
- /// The to the source bytes.
- /// The to the destination colors.
+ /// The to the source bytes.
+ /// The to the destination colors.
/// The number of pixels to convert.
internal virtual void PackFromZyxwBytes(
- BufferPointer sourceBytes,
- BufferPointer destColors,
+ BufferSpan sourceBytes,
+ BufferSpan destColors,
int count)
{
byte* sp = (byte*)sourceBytes;
@@ -234,18 +234,18 @@ namespace ImageSharp
///
/// Bulk version of .
///
- /// The to the source colors.
- /// The to the destination bytes.
+ /// The to the source colors.
+ /// The to the destination bytes.
/// The number of pixels to convert.
internal virtual void ToZyxwBytes(
- BufferPointer sourceColors,
- BufferPointer destBytes,
+ BufferSpan sourceColors,
+ BufferSpan destBytes,
int count)
{
byte* sp = (byte*)sourceColors;
byte[] dest = destBytes.Array;
- for (int i = destBytes.Offset; i < destBytes.Offset + (count * 4); i += 4)
+ for (int i = destBytes.Start; i < destBytes.Start + (count * 4); i += 4)
{
TColor c = Unsafe.Read(sp);
c.ToZyxwBytes(dest, i);
diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs
index b34c1e88b7..46c24be6f9 100644
--- a/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs
+++ b/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs
@@ -127,8 +127,8 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
bytes[startIndex + 2] = 0;
}
@@ -143,8 +143,8 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
bytes[startIndex + 2] = 0;
bytes[startIndex + 3] = 255;
}
@@ -161,8 +161,8 @@ namespace ImageSharp
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = 0;
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
}
///
@@ -177,8 +177,8 @@ namespace ImageSharp
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = 0;
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
bytes[startIndex + 3] = 255;
}
@@ -237,8 +237,8 @@ namespace ImageSharp
// Clamp the value between min and max values
// Round rather than truncate.
- uint word2 = (uint)((int)(float)Math.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF);
- uint word1 = (uint)(((int)(float)Math.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10);
+ uint word2 = (uint)((int)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF);
+ uint word1 = (uint)(((int)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10);
return word2 | word1;
}
diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs
index f33ac25a64..74229a914f 100644
--- a/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs
+++ b/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs
@@ -135,9 +135,9 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
}
///
@@ -151,10 +151,10 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
@@ -168,9 +168,9 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
}
///
@@ -184,10 +184,10 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
@@ -231,10 +231,10 @@ namespace ImageSharp
const float MinNeg = -MaxPos;
// Clamp the value between min and max values
- ulong word4 = ((ulong)(float)Math.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00;
- ulong word3 = ((ulong)(float)Math.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10;
- ulong word2 = ((ulong)(float)Math.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20;
- ulong word1 = ((ulong)(float)Math.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30;
+ ulong word4 = ((ulong)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00;
+ ulong word3 = ((ulong)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10;
+ ulong word2 = ((ulong)MathF.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20;
+ ulong word1 = ((ulong)MathF.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30;
return word4 | word3 | word2 | word1;
}
diff --git a/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs b/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs
index 56f3040703..65a5e7a5f6 100644
--- a/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs
+++ b/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs
@@ -109,9 +109,9 @@ namespace ImageSharp
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
}
///
@@ -120,10 +120,10 @@ namespace ImageSharp
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
@@ -132,9 +132,9 @@ namespace ImageSharp
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
}
///
@@ -143,10 +143,10 @@ namespace ImageSharp
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
diff --git a/src/ImageSharp/Colors/PackedPixel/Rgba64.cs b/src/ImageSharp/Colors/PackedPixel/Rgba64.cs
index 816401d4e0..becc4d072a 100644
--- a/src/ImageSharp/Colors/PackedPixel/Rgba64.cs
+++ b/src/ImageSharp/Colors/PackedPixel/Rgba64.cs
@@ -108,9 +108,9 @@ namespace ImageSharp
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
}
///
@@ -119,10 +119,10 @@ namespace ImageSharp
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
@@ -131,9 +131,9 @@ namespace ImageSharp
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
}
///
@@ -142,10 +142,10 @@ namespace ImageSharp
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
diff --git a/src/ImageSharp/Colors/PackedPixel/Short2.cs b/src/ImageSharp/Colors/PackedPixel/Short2.cs
index 802df7c1d4..167a1e786f 100644
--- a/src/ImageSharp/Colors/PackedPixel/Short2.cs
+++ b/src/ImageSharp/Colors/PackedPixel/Short2.cs
@@ -125,8 +125,8 @@ namespace ImageSharp
vector += Round;
vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
bytes[startIndex + 2] = 0;
}
@@ -141,8 +141,8 @@ namespace ImageSharp
vector += Round;
vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
bytes[startIndex + 2] = 0;
bytes[startIndex + 3] = 255;
}
@@ -159,8 +159,8 @@ namespace ImageSharp
vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes);
bytes[startIndex] = 0;
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
}
///
@@ -175,8 +175,8 @@ namespace ImageSharp
vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes);
bytes[startIndex] = 0;
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
bytes[startIndex + 3] = 255;
}
diff --git a/src/ImageSharp/Colors/PackedPixel/Short4.cs b/src/ImageSharp/Colors/PackedPixel/Short4.cs
index 2517ef7a84..e1a559c326 100644
--- a/src/ImageSharp/Colors/PackedPixel/Short4.cs
+++ b/src/ImageSharp/Colors/PackedPixel/Short4.cs
@@ -131,9 +131,9 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
}
///
@@ -147,10 +147,10 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
@@ -164,9 +164,9 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
}
///
@@ -180,10 +180,10 @@ namespace ImageSharp
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
- bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
- bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
- bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
- bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
+ bytes[startIndex] = (byte)MathF.Round(vector.Z);
+ bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
+ bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
+ bytes[startIndex + 3] = (byte)MathF.Round(vector.W);
}
///
diff --git a/src/ImageSharp/Colors/Spaces/CieLab.cs b/src/ImageSharp/Colors/Spaces/CieLab.cs
index ecc1bca5ad..921158174c 100644
--- a/src/ImageSharp/Colors/Spaces/CieLab.cs
+++ b/src/ImageSharp/Colors/Spaces/CieLab.cs
@@ -95,11 +95,11 @@ namespace ImageSharp.Colors.Spaces
// y /= 1F;
z /= 1.08883F;
- x = x > 0.008856F ? (float)Math.Pow(x, 0.3333333F) : ((903.3F * x) + 16F) / 116F;
- y = y > 0.008856F ? (float)Math.Pow(y, 0.3333333F) : ((903.3F * y) + 16F) / 116F;
- z = z > 0.008856F ? (float)Math.Pow(z, 0.3333333F) : ((903.3F * z) + 16F) / 116F;
+ x = x > 0.008856F ? MathF.Pow(x, 0.3333333F) : ((903.3F * x) + 16F) / 116F;
+ y = y > 0.008856F ? MathF.Pow(y, 0.3333333F) : ((903.3F * y) + 16F) / 116F;
+ z = z > 0.008856F ? MathF.Pow(z, 0.3333333F) : ((903.3F * z) + 16F) / 116F;
- float l = Math.Max(0, (116F * y) - 16F);
+ float l = MathF.Max(0, (116F * y) - 16F);
float a = 500F * (x - y);
float b = 200F * (y - z);
diff --git a/src/ImageSharp/Colors/Spaces/Cmyk.cs b/src/ImageSharp/Colors/Spaces/Cmyk.cs
index 53618312c7..c81a55c0bb 100644
--- a/src/ImageSharp/Colors/Spaces/Cmyk.cs
+++ b/src/ImageSharp/Colors/Spaces/Cmyk.cs
@@ -93,9 +93,9 @@ namespace ImageSharp.Colors.Spaces
float m = 1f - (color.G / 255F);
float y = 1f - (color.B / 255F);
- float k = Math.Min(c, Math.Min(m, y));
+ float k = MathF.Min(c, MathF.Min(m, y));
- if (Math.Abs(k - 1.0f) <= Constants.Epsilon)
+ if (MathF.Abs(k - 1.0f) <= Constants.Epsilon)
{
return new Cmyk(0, 0, 0, 1);
}
diff --git a/src/ImageSharp/Colors/Spaces/Hsl.cs b/src/ImageSharp/Colors/Spaces/Hsl.cs
index 66f4a52bcc..1d655ec326 100644
--- a/src/ImageSharp/Colors/Spaces/Hsl.cs
+++ b/src/ImageSharp/Colors/Spaces/Hsl.cs
@@ -83,27 +83,27 @@ namespace ImageSharp.Colors.Spaces
float g = color.G / 255F;
float b = color.B / 255F;
- float max = Math.Max(r, Math.Max(g, b));
- float min = Math.Min(r, Math.Min(g, b));
+ float max = MathF.Max(r, MathF.Max(g, b));
+ float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
float h = 0;
float s = 0;
float l = (max + min) / 2;
- if (Math.Abs(chroma) < Constants.Epsilon)
+ if (MathF.Abs(chroma) < Constants.Epsilon)
{
return new Hsl(0, s, l);
}
- if (Math.Abs(r - max) < Constants.Epsilon)
+ if (MathF.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
- else if (Math.Abs(g - max) < Constants.Epsilon)
+ else if (MathF.Abs(g - max) < Constants.Epsilon)
{
h = 2 + ((b - r) / chroma);
}
- else if (Math.Abs(b - max) < Constants.Epsilon)
+ else if (MathF.Abs(b - max) < Constants.Epsilon)
{
h = 4 + ((r - g) / chroma);
}
diff --git a/src/ImageSharp/Colors/Spaces/Hsv.cs b/src/ImageSharp/Colors/Spaces/Hsv.cs
index b34977e2d9..e171c95282 100644
--- a/src/ImageSharp/Colors/Spaces/Hsv.cs
+++ b/src/ImageSharp/Colors/Spaces/Hsv.cs
@@ -83,27 +83,27 @@ namespace ImageSharp.Colors.Spaces
float g = color.G / 255F;
float b = color.B / 255F;
- float max = Math.Max(r, Math.Max(g, b));
- float min = Math.Min(r, Math.Min(g, b));
+ float max = MathF.Max(r, MathF.Max(g, b));
+ float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
float h = 0;
float s = 0;
float v = max;
- if (Math.Abs(chroma) < Constants.Epsilon)
+ if (MathF.Abs(chroma) < Constants.Epsilon)
{
return new Hsv(0, s, v);
}
- if (Math.Abs(r - max) < Constants.Epsilon)
+ if (MathF.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
- else if (Math.Abs(g - max) < Constants.Epsilon)
+ else if (MathF.Abs(g - max) < Constants.Epsilon)
{
h = 2 + ((b - r) / chroma);
}
- else if (Math.Abs(b - max) < Constants.Epsilon)
+ else if (MathF.Abs(b - max) < Constants.Epsilon)
{
h = 4 + ((r - g) / chroma);
}
diff --git a/src/ImageSharp/Colors/Vector4BlendTransforms.cs b/src/ImageSharp/Colors/Vector4BlendTransforms.cs
index 2fa6aad4b4..a7e2e0e919 100644
--- a/src/ImageSharp/Colors/Vector4BlendTransforms.cs
+++ b/src/ImageSharp/Colors/Vector4BlendTransforms.cs
@@ -5,7 +5,6 @@
namespace ImageSharp
{
- using System;
using System.Numerics;
///
@@ -198,13 +197,13 @@ namespace ImageSharp
amount = amount.Clamp(0, 1);
// Santize on zero alpha
- if (Math.Abs(backdrop.W) < Constants.Epsilon)
+ if (MathF.Abs(backdrop.W) < Constants.Epsilon)
{
source.W *= amount;
return source;
}
- if (Math.Abs(source.W) < Constants.Epsilon)
+ if (MathF.Abs(source.W) < Constants.Epsilon)
{
return backdrop;
}
@@ -248,7 +247,7 @@ namespace ImageSharp
///
private static float BlendSoftLight(float b, float s)
{
- return s <= .5F ? ((2F * b * s) + (b * b * (1F - (2F * s)))) : (float)((Math.Sqrt(b) * ((2F * s) - 1F)) + (2F * b * (1F - s)));
+ return s <= .5F ? ((2F * b * s) + (b * b * (1F - (2F * s)))) : (MathF.Sqrt(b) * ((2F * s) - 1F)) + (2F * b * (1F - s));
}
///
@@ -261,7 +260,7 @@ namespace ImageSharp
///
private static float BlendDodge(float b, float s)
{
- return Math.Abs(s - 1F) < Constants.Epsilon ? s : Math.Min(b / (1F - s), 1F);
+ return MathF.Abs(s - 1F) < Constants.Epsilon ? s : MathF.Min(b / (1F - s), 1F);
}
///
@@ -274,7 +273,7 @@ namespace ImageSharp
///
private static float BlendBurn(float b, float s)
{
- return Math.Abs(s) < Constants.Epsilon ? s : Math.Max(1F - ((1F - b) / s), 0F);
+ return MathF.Abs(s) < Constants.Epsilon ? s : MathF.Max(1F - ((1F - b) / s), 0F);
}
///
diff --git a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs
index 23fce0173c..9f3aa405ed 100644
--- a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs
+++ b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs
@@ -57,7 +57,7 @@ namespace ImageSharp
return signal * 12.92F;
}
- return (1.055F * (float)Math.Pow(signal, 0.41666666F)) - 0.055F;
+ return (1.055F * MathF.Pow(signal, 0.41666666F)) - 0.055F;
}
///
@@ -77,7 +77,7 @@ namespace ImageSharp
return signal / 12.92F;
}
- return (float)Math.Pow((signal + 0.055F) / 1.055F, 2.4F);
+ return MathF.Pow((signal + 0.055F) / 1.055F, 2.4F);
}
}
}
diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs
index b59cf54f52..224b267e40 100644
--- a/src/ImageSharp/Common/Helpers/ImageMaths.cs
+++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs
@@ -53,13 +53,13 @@ namespace ImageSharp
public static float Gaussian(float x, float sigma)
{
const float Numerator = 1.0f;
- float denominator = (float)(Math.Sqrt(2 * Math.PI) * sigma);
+ float denominator = MathF.Sqrt(2 * MathF.PI) * sigma;
float exponentNumerator = -x * x;
float exponentDenominator = (float)(2 * Math.Pow(sigma, 2));
float left = Numerator / denominator;
- float right = (float)Math.Exp(exponentNumerator / exponentDenominator);
+ float right = MathF.Exp(exponentNumerator / exponentDenominator);
return left * right;
}
@@ -110,10 +110,10 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float SinC(float x)
{
- if (Math.Abs(x) > Constants.Epsilon)
+ if (MathF.Abs(x) > Constants.Epsilon)
{
- x *= (float)Math.PI;
- return Clean((float)Math.Sin(x) / x);
+ x *= MathF.PI;
+ return Clean(MathF.Sin(x) / x);
}
return 1.0f;
@@ -129,7 +129,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float DegreesToRadians(float degrees)
{
- return degrees * (float)(Math.PI / 180);
+ return degrees * (MathF.PI / 180);
}
///
@@ -196,19 +196,19 @@ namespace ImageSharp
switch (channel)
{
case RgbaComponent.R:
- delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().X - b) > Constants.Epsilon;
+ delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().X - b) > Constants.Epsilon;
break;
case RgbaComponent.G:
- delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Y - b) > Constants.Epsilon;
+ delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Y - b) > Constants.Epsilon;
break;
case RgbaComponent.B:
- delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Z - b) > Constants.Epsilon;
+ delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Z - b) > Constants.Epsilon;
break;
default:
- delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().W - b) > Constants.Epsilon;
+ delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().W - b) > Constants.Epsilon;
break;
}
@@ -297,7 +297,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float Clean(float x)
{
- if (Math.Abs(x) < Constants.Epsilon)
+ if (MathF.Abs(x) < Constants.Epsilon)
{
return 0F;
}
diff --git a/src/ImageSharp/Common/Helpers/MathF.cs b/src/ImageSharp/Common/Helpers/MathF.cs
new file mode 100644
index 0000000000..2ee700789c
--- /dev/null
+++ b/src/ImageSharp/Common/Helpers/MathF.cs
@@ -0,0 +1,144 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Provides single-precision floating point constants and static methods for trigonometric, logarithmic, and other common mathematical functions.
+ ///
+ // ReSharper disable InconsistentNaming
+ internal static class MathF
+ {
+ ///
+ /// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, π.
+ ///
+ public const float PI = (float)Math.PI;
+
+ /// Returns the absolute value of a single-precision floating-point number.
+ /// A number that is greater than or equal to , but less than or equal to .
+ /// A single-precision floating-point number, x, such that 0 ≤ x ≤.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Abs(float f)
+ {
+ return Math.Abs(f);
+ }
+
+ /// Returns the smallest integral value that is greater than or equal to the specified single-precision floating-point number.
+ /// A single-precision floating-point number.
+ /// The smallest integral value that is greater than or equal to .
+ /// If is equal to , ,
+ /// or , that value is returned.
+ /// Note that this method returns a instead of an integral type.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Ceiling(float f)
+ {
+ return (float)Math.Ceiling(f);
+ }
+
+ /// Returns e raised to the specified power.
+ /// A number specifying a power.
+ ///
+ /// The number e raised to the power .
+ /// If equals or , that value is returned.
+ /// If equals , 0 is returned.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Exp(float f)
+ {
+ return (float)Math.Exp(f);
+ }
+
+ /// Returns the largest integer less than or equal to the specified single-precision floating-point number.
+ /// A single-precision floating-point number.
+ /// The largest integer less than or equal to .
+ /// If is equal to , ,
+ /// or , that value is returned.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Floor(float f)
+ {
+ return (float)Math.Floor(f);
+ }
+
+ /// Returns the larger of two single-precision floating-point numbers.
+ /// The first of two single-precision floating-point numbers to compare.
+ /// The second of two single-precision floating-point numbers to compare.
+ /// Parameter or , whichever is larger.
+ /// If , or , or both and are
+ /// equal to , is returned.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Max(float val1, float val2)
+ {
+ return Math.Max(val1, val2);
+ }
+
+ /// Returns the smaller of two single-precision floating-point numbers.
+ /// The first of two single-precision floating-point numbers to compare.
+ /// The second of two single-precision floating-point numbers to compare.
+ /// Parameter or , whichever is smaller.
+ /// If , , or both and are equal
+ /// to , is returned.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Min(float val1, float val2)
+ {
+ return Math.Min(val1, val2);
+ }
+
+ /// Returns a specified number raised to the specified power.
+ /// A single-precision floating-point number to be raised to a power.
+ /// A single-precision floating-point number that specifies a power.
+ /// The number raised to the power .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Pow(float x, float y)
+ {
+ return (float)Math.Pow(x, y);
+ }
+
+ /// Rounds a single-precision floating-point value to the nearest integral value.
+ /// A single-precision floating-point number to be rounded.
+ ///
+ /// The integer nearest .
+ /// If the fractional component of is halfway between two integers, one of which is even and the other odd, then the even number is returned.
+ /// Note that this method returns a instead of an integral type.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Round(float f)
+ {
+ return (float)Math.Round(f);
+ }
+
+ /// Returns the sine of the specified angle.
+ /// An angle, measured in radians.
+ ///
+ /// The sine of .
+ /// If is equal to , ,
+ /// or , this method returns .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Sin(float f)
+ {
+ return (float)Math.Sin(f);
+ }
+
+ /// Returns the square root of a specified number.
+ /// The number whose square root is to be found.
+ ///
+ /// One of the values in the following table.
+ /// parameter Return value Zero or positive The positive square root of .
+ /// Negative Equals
+ /// Equals
+ ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float Sqrt(float f)
+ {
+ return (float)Math.Sqrt(f);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs
deleted file mode 100644
index 441f6b8ce0..0000000000
--- a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs
+++ /dev/null
@@ -1,143 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp
-{
- using System;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
-
- ///
- /// Provides access to elements in an array from a given position.
- /// This type shares many similarities with corefx System.Span<T> but there are significant differences in it's functionalities and semantics:
- /// - It's not possible to use it with stack objects or pointers to unmanaged memory, only with managed arrays
- /// - It's possible to retrieve a reference to the array () so we can pass it to API-s like
- /// - There is no bounds checking for performance reasons. Therefore we don't need to store length. (However this could be added as DEBUG-only feature.)
- /// This makes an unsafe type!
- /// - Currently the arrays provided to BufferPointer need to be pinned. This behaviour could be changed using C#7 features.
- ///
- /// The type of elements of the array
- internal unsafe struct BufferPointer
- where T : struct
- {
- ///
- /// Initializes a new instance of the struct from a pinned array and an offset.
- ///
- /// The pinned array
- /// Pointer to the beginning of array
- /// The offset inside the array
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public BufferPointer(T[] array, void* pointerToArray, int offset)
- {
- DebugGuard.NotNull(array, nameof(array));
-
- this.Array = array;
- this.Offset = offset;
- this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf() * offset);
- }
-
- ///
- /// Initializes a new instance of the struct from a pinned array.
- ///
- /// The pinned array
- /// Pointer to the start of 'array'
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public BufferPointer(T[] array, void* pointerToArray)
- {
- DebugGuard.NotNull(array, nameof(array));
-
- this.Array = array;
- this.Offset = 0;
- this.PointerAtOffset = (IntPtr)pointerToArray;
- }
-
- ///
- /// Gets the array
- ///
- public T[] Array { get; private set; }
-
- ///
- /// Gets the offset inside
- ///
- public int Offset { get; private set; }
-
- ///
- /// Gets the offset inside in bytes.
- ///
- public int ByteOffset => this.Offset * Unsafe.SizeOf();
-
- ///
- /// Gets the pointer to the offseted array position
- ///
- public IntPtr PointerAtOffset { get; private set; }
-
- ///
- /// Convertes instance to a raw 'void*' pointer
- ///
- /// The to convert
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator void*(BufferPointer bufferPointer)
- {
- return (void*)bufferPointer.PointerAtOffset;
- }
-
- ///
- /// Converts instance to a raw 'byte*' pointer
- ///
- /// The to convert
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator byte*(BufferPointer bufferPointer)
- {
- return (byte*)bufferPointer.PointerAtOffset;
- }
-
- ///
- /// Converts instance to
- /// setting it's and to correct values.
- ///
- /// The to convert
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator BufferPointer(BufferPointer source)
- {
- BufferPointer result = default(BufferPointer);
- result.Array = Unsafe.As(source.Array);
- result.Offset = source.Offset * Unsafe.SizeOf();
- result.PointerAtOffset = source.PointerAtOffset;
- return result;
- }
-
- ///
- /// Forms a slice out of the given BufferPointer, beginning at 'offset'.
- ///
- /// The offset in number of elements
- /// The offseted (sliced) BufferPointer
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public BufferPointer Slice(int offset)
- {
- BufferPointer result = default(BufferPointer);
- result.Array = this.Array;
- result.Offset = this.Offset + offset;
- result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf() * offset);
- return result;
- }
-
- ///
- /// Clears `count` elements beginning from the pointed position.
- ///
- /// The number of elements to clear
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Clear(int count)
- {
- if (count < 256)
- {
- Unsafe.InitBlock((void*)this.PointerAtOffset, 0, BufferPointer.USizeOf(count));
- }
- else
- {
- System.Array.Clear(this.Array, this.Offset, count);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Common/Memory/BufferPointer.cs b/src/ImageSharp/Common/Memory/BufferSpan.cs
similarity index 81%
rename from src/ImageSharp/Common/Memory/BufferPointer.cs
rename to src/ImageSharp/Common/Memory/BufferSpan.cs
index 523889611f..42a6fbc6be 100644
--- a/src/ImageSharp/Common/Memory/BufferPointer.cs
+++ b/src/ImageSharp/Common/Memory/BufferSpan.cs
@@ -1,4 +1,4 @@
-//
+//
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
@@ -11,9 +11,9 @@ namespace ImageSharp
using System.Runtime.InteropServices;
///
- /// Utility methods for
+ /// Utility methods for
///
- internal static class BufferPointer
+ internal static class BufferSpan
{
///
/// It's worth to use Marshal.Copy() or Buffer.BlockCopy() over this size.
@@ -24,11 +24,11 @@ namespace ImageSharp
/// Copy 'count' number of elements of the same type from 'source' to 'dest'
///
/// The element type.
- /// The input
- /// The destination .
+ /// The input
+ /// The destination .
/// The number of elements to copy
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Copy(BufferPointer source, BufferPointer destination, int count)
+ public static void Copy(BufferSpan source, BufferSpan destination, int count)
where T : struct
{
CopyImpl(source, destination, count);
@@ -42,7 +42,7 @@ namespace ImageSharp
/// The destination buffer.
/// The number of elements to copy from 'source'
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void Copy(BufferPointer source, BufferPointer destination, int countInSource)
+ public static void Copy(BufferSpan source, BufferSpan destination, int countInSource)
where T : struct
{
CopyImpl(source, destination, countInSource);
@@ -56,14 +56,14 @@ namespace ImageSharp
/// The destination buffer"/>
/// The number of elements to copy.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static unsafe void Copy(BufferPointer source, BufferPointer destination, int countInDest)
+ public static unsafe void Copy(BufferSpan source, BufferSpan destination, int countInDest)
where T : struct
{
int byteCount = SizeOf(countInDest);
if (byteCount > (int)ByteCountThreshold)
{
- Marshal.Copy(source.Array, source.Offset, destination.PointerAtOffset, byteCount);
+ Marshal.Copy(source.Array, source.Start, destination.PointerAtOffset, byteCount);
}
else
{
@@ -93,7 +93,7 @@ namespace ImageSharp
=> (uint)SizeOf(count);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static unsafe void CopyImpl(BufferPointer source, BufferPointer destination, int count)
+ private static unsafe void CopyImpl(BufferSpan source, BufferSpan destination, int count)
where T : struct
where TDest : struct
{
@@ -103,22 +103,22 @@ namespace ImageSharp
{
if (Unsafe.SizeOf() == sizeof(long))
{
- Marshal.Copy(Unsafe.As(source.Array), source.Offset, destination.PointerAtOffset, count);
+ Marshal.Copy(Unsafe.As(source.Array), source.Start, destination.PointerAtOffset, count);
return;
}
else if (Unsafe.SizeOf() == sizeof(int))
{
- Marshal.Copy(Unsafe.As(source.Array), source.Offset, destination.PointerAtOffset, count);
+ Marshal.Copy(Unsafe.As(source.Array), source.Start, destination.PointerAtOffset, count);
return;
}
else if (Unsafe.SizeOf() == sizeof(short))
{
- Marshal.Copy(Unsafe.As(source.Array), source.Offset, destination.PointerAtOffset, count);
+ Marshal.Copy(Unsafe.As(source.Array), source.Start, destination.PointerAtOffset, count);
return;
}
else if (Unsafe.SizeOf() == sizeof(byte))
{
- Marshal.Copy(Unsafe.As(source.Array), source.Offset, destination.PointerAtOffset, count);
+ Marshal.Copy(Unsafe.As(source.Array), source.Start, destination.PointerAtOffset, count);
return;
}
}
diff --git a/src/ImageSharp/Common/Memory/BufferSpan{T}.cs b/src/ImageSharp/Common/Memory/BufferSpan{T}.cs
new file mode 100644
index 0000000000..8ef88814cd
--- /dev/null
+++ b/src/ImageSharp/Common/Memory/BufferSpan{T}.cs
@@ -0,0 +1,237 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.Diagnostics;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
+
+ ///
+ /// Represents a contiguous region of a pinned managed array.
+ /// The array is usually owned by a instance.
+ ///
+ ///
+ /// is very similar to corefx System.Span<T>, and we try to maintain a compatible API.
+ /// There are several differences though:
+ /// - It's not possible to use it with stack objects or pointers to unmanaged memory, only with managed arrays.
+ /// - It's possible to retrieve a reference to the array () so we can pass it to API-s like
+ /// - It's possible to retrieve the pinned pointer. This enables optimized (unchecked) unsafe operations.
+ /// - There is no bounds checking for performance reasons, only in debug mode. This makes an unsafe type!
+ ///
+ /// The type of elements of the array
+ internal unsafe struct BufferSpan
+ where T : struct
+ {
+ ///
+ /// Initializes a new instance of the struct from a pinned array and an start.
+ ///
+ /// The pinned array
+ /// Pointer to the beginning of the array
+ /// The index at which to begin the span.
+ /// The length
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public BufferSpan(T[] array, void* pointerToArray, int start, int length)
+ {
+ GuardArrayAndPointer(array, pointerToArray);
+
+ DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start));
+ DebugGuard.MustBeLessThanOrEqualTo(length, array.Length - start, nameof(length));
+
+ this.Array = array;
+ this.Length = length;
+ this.Start = start;
+ this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf() * start);
+ }
+
+ ///
+ /// Initializes a new instance of the struct from a pinned array and an start.
+ ///
+ /// The pinned array
+ /// Pointer to the beginning of the array
+ /// The index at which to begin the span.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public BufferSpan(T[] array, void* pointerToArray, int start)
+ {
+ GuardArrayAndPointer(array, pointerToArray);
+ DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start));
+
+ this.Array = array;
+ this.Length = array.Length - start;
+ this.Start = start;
+ this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf() * start);
+ }
+
+ ///
+ /// Initializes a new instance of the struct from a pinned array.
+ ///
+ /// The pinned array
+ /// Pointer to the start of 'array'
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public BufferSpan(T[] array, void* pointerToArray)
+ {
+ GuardArrayAndPointer(array, pointerToArray);
+
+ this.Array = array;
+ this.Start = 0;
+ this.Length = array.Length;
+ this.PointerAtOffset = (IntPtr)pointerToArray;
+ }
+
+ ///
+ /// Gets the backing array
+ ///
+ public T[] Array { get; private set; }
+
+ ///
+ /// Gets the length of the
+ ///
+ public int Length { get; private set; }
+
+ ///
+ /// Gets the start inside
+ ///
+ public int Start { get; private set; }
+
+ ///
+ /// Gets the start inside in bytes.
+ ///
+ public int ByteOffset => this.Start * Unsafe.SizeOf();
+
+ ///
+ /// Gets the pointer to the offseted array position
+ ///
+ public IntPtr PointerAtOffset { get; private set; }
+
+ ///
+ /// Returns a reference to specified element of the span.
+ ///
+ /// The index
+ /// The reference to the specified element
+ public ref T this[int index]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
+
+ byte* ptr = (byte*)this.PointerAtOffset + BufferSpan.SizeOf(index);
+ return ref Unsafe.AsRef(ptr);
+ }
+ }
+
+ ///
+ /// Convertes instance to a raw 'void*' pointer
+ ///
+ /// The to convert
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator void*(BufferSpan bufferSpan)
+ {
+ return (void*)bufferSpan.PointerAtOffset;
+ }
+
+ ///
+ /// Converts instance to a raw 'byte*' pointer
+ ///
+ /// The to convert
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator byte*(BufferSpan bufferSpan)
+ {
+ return (byte*)bufferSpan.PointerAtOffset;
+ }
+
+ ///
+ /// Converts generic to a of bytes
+ /// setting it's and to correct values.
+ ///
+ /// The to convert
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator BufferSpan(BufferSpan source)
+ {
+ BufferSpan result = default(BufferSpan);
+ result.Array = Unsafe.As(source.Array);
+ result.Start = source.Start * Unsafe.SizeOf();
+ result.PointerAtOffset = source.PointerAtOffset;
+ return result;
+ }
+
+ ///
+ /// Forms a slice out of the given BufferSpan, beginning at 'start'.
+ ///
+ /// TThe index at which to begin this slice.
+ /// The offseted (sliced) BufferSpan
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public BufferSpan Slice(int start)
+ {
+ DebugGuard.MustBeLessThan(start, this.Length, nameof(start));
+
+ BufferSpan result = default(BufferSpan);
+ result.Array = this.Array;
+ result.Start = this.Start + start;
+ result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf() * start);
+ result.Length = this.Length - start;
+ return result;
+ }
+
+ ///
+ /// Forms a slice out of the given BufferSpan, beginning at 'start'.
+ ///
+ /// The index at which to begin this slice.
+ /// The desired length for the slice (exclusive).
+ /// The sliced BufferSpan
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public BufferSpan Slice(int start, int length)
+ {
+ DebugGuard.MustBeLessThanOrEqualTo(start, this.Length, nameof(start));
+ DebugGuard.MustBeLessThanOrEqualTo(length, this.Length - start, nameof(length));
+
+ BufferSpan result = default(BufferSpan);
+ result.Array = this.Array;
+ result.Start = this.Start + start;
+ result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf() * start);
+ result.Length = length;
+ return result;
+ }
+
+ ///
+ /// Clears `count` elements from the beginning of the span.
+ ///
+ /// The number of elements to clear
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Clear(int count)
+ {
+ DebugGuard.MustBeLessThanOrEqualTo(count, this.Length, nameof(count));
+
+ if (count < 256)
+ {
+ Unsafe.InitBlock((void*)this.PointerAtOffset, 0, BufferSpan.USizeOf(count));
+ }
+ else
+ {
+ System.Array.Clear(this.Array, this.Start, count);
+ }
+ }
+
+ ///
+ /// Clears the the span
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Clear()
+ {
+ this.Clear(this.Length);
+ }
+
+ [Conditional("DEBUG")]
+ private static void GuardArrayAndPointer(T[] array, void* pointerToArray)
+ {
+ DebugGuard.NotNull(array, nameof(array));
+ DebugGuard.IsFalse(
+ pointerToArray == (void*)0,
+ nameof(pointerToArray),
+ "pointerToArray should not be null pointer!");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Common/Memory/Fast2DArray{T}.cs b/src/ImageSharp/Common/Memory/Fast2DArray{T}.cs
index 3455031fdb..401c83ce61 100644
--- a/src/ImageSharp/Common/Memory/Fast2DArray{T}.cs
+++ b/src/ImageSharp/Common/Memory/Fast2DArray{T}.cs
@@ -13,7 +13,7 @@ namespace ImageSharp
/// Provides fast access to 2D arrays.
///
/// The type of elements in the array.
- public struct Fast2DArray
+ internal struct Fast2DArray
{
///
/// The 1D representation of the 2D array.
diff --git a/src/ImageSharp/Common/Memory/IPinnedImageBuffer{T}.cs b/src/ImageSharp/Common/Memory/IPinnedImageBuffer{T}.cs
new file mode 100644
index 0000000000..374cbed997
--- /dev/null
+++ b/src/ImageSharp/Common/Memory/IPinnedImageBuffer{T}.cs
@@ -0,0 +1,31 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ ///
+ /// An interface that represents a pinned buffer of value type objects
+ /// interpreted as a 2D region of x elements.
+ ///
+ /// The value type.
+ internal interface IPinnedImageBuffer
+ where T : struct
+ {
+ ///
+ /// Gets the width.
+ ///
+ int Width { get; }
+
+ ///
+ /// Gets the height.
+ ///
+ int Height { get; }
+
+ ///
+ /// Gets a to the backing buffer.
+ ///
+ BufferSpan Span { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs
index 2d3d44dda8..611688c995 100644
--- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs
+++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs
@@ -11,7 +11,7 @@ namespace ImageSharp
using System.Runtime.InteropServices;
///
- /// Manages a pinned buffer of value type data 'T' as a Disposable resource.
+ /// Manages a pinned buffer of value type objects as a Disposable resource.
/// The backing array is either pooled or comes from the outside.
///
/// The value type.
@@ -32,11 +32,11 @@ namespace ImageSharp
///
/// Initializes a new instance of the class.
///
- /// The desired count of elements. (Minimum size for )
- public PinnedBuffer(int count)
+ /// The desired count of elements. (Minimum size for )
+ public PinnedBuffer(int length)
{
- this.Count = count;
- this.Array = PixelDataPool.Rent(count);
+ this.Length = length;
+ this.Array = PixelDataPool.Rent(length);
this.isPoolingOwner = true;
this.Pin();
}
@@ -47,7 +47,7 @@ namespace ImageSharp
/// The array to pin.
public PinnedBuffer(T[] array)
{
- this.Count = array.Length;
+ this.Length = array.Length;
this.Array = array;
this.isPoolingOwner = false;
this.Pin();
@@ -56,16 +56,16 @@ namespace ImageSharp
///
/// Initializes a new instance of the class.
///
- /// The count of "relevant" elements in 'array'.
/// The array to pin.
- public PinnedBuffer(int count, T[] array)
+ /// The count of "relevant" elements in 'array'.
+ public PinnedBuffer(T[] array, int length)
{
- if (array.Length < count)
+ if (array.Length < length)
{
throw new ArgumentException("Can't initialize a PinnedBuffer with array.Length < count", nameof(array));
}
- this.Count = count;
+ this.Length = length;
this.Array = array;
this.isPoolingOwner = false;
this.Pin();
@@ -85,9 +85,9 @@ namespace ImageSharp
public bool IsDisposedOrLostArrayOwnership { get; private set; }
///
- /// Gets the count of "relevant" elements. Usually be smaller than 'Array.Length' when is pooled.
+ /// Gets the count of "relevant" elements. It's usually smaller than 'Array.Length' when is pooled.
///
- public int Count { get; private set; }
+ public int Length { get; private set; }
///
/// Gets the backing pinned array.
@@ -100,34 +100,71 @@ namespace ImageSharp
public IntPtr Pointer { get; private set; }
///
- /// Converts to an .
+ /// Gets a to the backing buffer.
+ ///
+ public BufferSpan Span => this;
+
+ ///
+ /// Returns a reference to specified element of the buffer.
+ ///
+ /// The index
+ /// The reference to the specified element
+ public unsafe ref T this[int index]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
+
+ byte* ptr = (byte*)this.Pointer + BufferSpan.SizeOf(index);
+ return ref Unsafe.AsRef(ptr);
+ }
+ }
+
+ ///
+ /// Converts to an .
///
/// The to convert.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator BufferPointer(PinnedBuffer buffer)
+ public static unsafe implicit operator BufferSpan(PinnedBuffer buffer)
+ {
+ return new BufferSpan(buffer.Array, (void*)buffer.Pointer, 0, buffer.Length);
+ }
+
+ ///
+ /// Creates a clean instance of initializing it's elements with 'default(T)'.
+ ///
+ /// The desired count of elements. (Minimum size for )
+ /// The instance
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static PinnedBuffer CreateClean(int count)
{
- return buffer.Slice();
+ PinnedBuffer buffer = new PinnedBuffer(count);
+ buffer.Clear();
+ return buffer;
}
///
- /// Gets a to the beginning of the raw data of the buffer.
+ /// Gets a to an offseted position inside the buffer.
///
- /// The
+ /// The start
+ /// The
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe BufferPointer Slice()
+ public unsafe BufferSpan Slice(int start)
{
- return new BufferPointer(this.Array, (void*)this.Pointer);
+ return new BufferSpan(this.Array, (void*)this.Pointer, start, this.Length - start);
}
///
- /// Gets a to an offseted position inside the buffer.
+ /// Gets a to an offseted position inside the buffer.
///
- /// The offset
- /// The
+ /// The start
+ /// The length of the slice
+ /// The
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe BufferPointer Slice(int offset)
+ public unsafe BufferSpan Slice(int start, int length)
{
- return new BufferPointer(this.Array, (void*)this.Pointer, offset);
+ return new BufferSpan(this.Array, (void*)this.Pointer, start, length);
}
///
@@ -151,7 +188,7 @@ namespace ImageSharp
this.isPoolingOwner = false;
this.Array = null;
- this.Count = 0;
+ this.Length = 0;
GC.SuppressFinalize(this);
}
@@ -178,12 +215,12 @@ namespace ImageSharp
}
///
- /// Clears the buffer, filling elements between 0 and -1 with default(T)
+ /// Clears the buffer, filling elements between 0 and -1 with default(T)
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
- this.Slice().Clear(this.Count);
+ ((BufferSpan)this).Clear();
}
///
diff --git a/src/ImageSharp/Common/Memory/PinnedImageBufferExtensions.cs b/src/ImageSharp/Common/Memory/PinnedImageBufferExtensions.cs
new file mode 100644
index 0000000000..fcd5b3831e
--- /dev/null
+++ b/src/ImageSharp/Common/Memory/PinnedImageBufferExtensions.cs
@@ -0,0 +1,45 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Defines extension methods for .
+ ///
+ internal static class PinnedImageBufferExtensions
+ {
+ ///
+ /// Gets a to the row 'y' beginning from the pixel at 'x'.
+ ///
+ /// The buffer
+ /// The x coordinate (position in the row)
+ /// The y (row) coordinate
+ /// The element type
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static BufferSpan GetRowSpan(this IPinnedImageBuffer buffer, int x, int y)
+ where T : struct
+ {
+ return buffer.Span.Slice((y * buffer.Width) + x, buffer.Width - x);
+ }
+
+ ///
+ /// Gets a to the row 'y' beginning from the pixel at 'x'.
+ ///
+ /// The buffer
+ /// The y (row) coordinate
+ /// The element type
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static BufferSpan GetRowSpan(this IPinnedImageBuffer buffer, int y)
+ where T : struct
+ {
+ return buffer.Span.Slice(y * buffer.Width, buffer.Width);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs
new file mode 100644
index 0000000000..3ff174c5dd
--- /dev/null
+++ b/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs
@@ -0,0 +1,78 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Represents a pinned buffer of value type objects
+ /// interpreted as a 2D region of x elements.
+ ///
+ /// The value type.
+ internal class PinnedImageBuffer : PinnedBuffer, IPinnedImageBuffer
+ where T : struct
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number of elements in a row
+ /// The number of rows
+ public PinnedImageBuffer(int width, int height)
+ : base(width * height)
+ {
+ this.Width = width;
+ this.Height = height;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The array to pin
+ /// The number of elements in a row
+ /// The number of rows
+ public PinnedImageBuffer(T[] array, int width, int height)
+ : base(array, width * height)
+ {
+ this.Width = width;
+ this.Height = height;
+ }
+
+ ///
+ public int Width { get; }
+
+ ///
+ public int Height { get; }
+
+ ///
+ /// Gets a reference to the element at the specified position.
+ ///
+ /// The x coordinate (row)
+ /// The y coordinate (position at row)
+ /// A reference to the element.
+ public ref T this[int x, int y]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return ref this.Array[(this.Width * y) + x];
+ }
+ }
+
+ ///
+ /// Creates a clean instance of initializing it's elements with 'default(T)'.
+ ///
+ /// The number of elements in a row
+ /// The number of rows
+ /// The instance
+ public static PinnedImageBuffer CreateClean(int width, int height)
+ {
+ PinnedImageBuffer buffer = new PinnedImageBuffer(width, height);
+ buffer.Clear();
+ return buffer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs
index dcd031f6e2..f5c7871409 100644
--- a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs
+++ b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs
@@ -12,7 +12,7 @@ namespace ImageSharp
/// Provides a resource pool that enables reusing instances of value type arrays for image data .
///
/// The value type.
- public class PixelDataPool
+ internal class PixelDataPool
where T : struct
{
///
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index e9120aa479..fa983d3557 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -12,6 +12,7 @@ namespace ImageSharp
using System.Threading.Tasks;
using Formats;
+ using ImageSharp.IO;
///
/// Provides initialization code which allows extending the library.
@@ -33,6 +34,25 @@ namespace ImageSharp
///
private readonly List imageFormatsList = new List();
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Configuration()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The inital set of image formats.
+ public Configuration(params IImageFormat[] providers)
+ {
+ foreach (IImageFormat p in providers)
+ {
+ this.AddImageFormat(p);
+ }
+ }
+
///
/// Gets the default instance.
///
@@ -53,6 +73,13 @@ namespace ImageSharp
///
internal int MaxHeaderSize { get; private set; }
+#if !NETSTANDARD1_1
+ ///
+ /// Gets or sets the fielsystem helper for accessing the local file system.
+ ///
+ internal IFileSystem FileSystem { get; set; } = new LocalFileSystem();
+#endif
+
///
/// Adds a new to the collection of supported image formats.
///
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs b/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs
index 20a45d4df6..cde146f1e5 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs
@@ -5,12 +5,11 @@
namespace ImageSharp.Dithering
{
- using System;
using System.Numerics;
using System.Runtime.CompilerServices;
///
- /// The base class for performing effor diffusion based dithering.
+ /// The base class for performing error diffusion based dithering.
///
public abstract class ErrorDiffuser : IErrorDiffuser
{
@@ -34,19 +33,24 @@ namespace ImageSharp.Dithering
///
private readonly int startingOffset;
+ ///
+ /// The diffusion matrix
+ ///
+ private readonly Fast2DArray matrix;
+
///
/// Initializes a new instance of the class.
///
/// The dithering matrix.
/// The divisor.
- protected ErrorDiffuser(Fast2DArray matrix, byte divisor)
+ internal ErrorDiffuser(Fast2DArray matrix, byte divisor)
{
Guard.NotNull(matrix, nameof(matrix));
Guard.MustBeGreaterThan(divisor, 0, nameof(divisor));
- this.Matrix = matrix;
- this.matrixWidth = this.Matrix.Width;
- this.matrixHeight = this.Matrix.Height;
+ this.matrix = matrix;
+ this.matrixWidth = this.matrix.Width;
+ this.matrixHeight = this.matrix.Height;
this.divisorVector = new Vector4(divisor);
this.startingOffset = 0;
@@ -62,9 +66,6 @@ namespace ImageSharp.Dithering
}
}
- ///
- public Fast2DArray Matrix { get; }
-
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dither(PixelAccessor pixels, TColor source, TColor transformed, int x, int y, int width, int height)
@@ -87,9 +88,9 @@ namespace ImageSharp.Dithering
if (matrixX > 0 && matrixX < width && matrixY > 0 && matrixY < height)
{
- float coefficient = this.Matrix[row, col];
+ float coefficient = this.matrix[row, col];
- // Good to disable here as we are not comparing matematical output.
+ // Good to disable here as we are not comparing mathematical output.
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (coefficient == 0)
{
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs b/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs
index 4fb31c13e4..18079b1fb2 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs
@@ -12,11 +12,6 @@ namespace ImageSharp.Dithering
///
public interface IErrorDiffuser
{
- ///
- /// Gets the dithering matrix
- ///
- Fast2DArray Matrix { get; }
-
///
/// Transforms the image applying the dither matrix. This method alters the input pixels array
///
diff --git a/src/ImageSharp/Dithering/Ordered/Bayer.cs b/src/ImageSharp/Dithering/Ordered/Bayer.cs
index 1027e51d94..3792c3c023 100644
--- a/src/ImageSharp/Dithering/Ordered/Bayer.cs
+++ b/src/ImageSharp/Dithering/Ordered/Bayer.cs
@@ -5,13 +5,11 @@
namespace ImageSharp.Dithering.Ordered
{
- using System;
-
///
/// Applies error diffusion based dithering using the 4x4 Bayer dithering matrix.
///
///
- public class Bayer : IOrderedDither
+ public sealed class Bayer : OrderedDither4x4
{
///
/// The threshold matrix.
@@ -26,15 +24,12 @@ namespace ImageSharp.Dithering.Ordered
{ 255, 127, 223, 95 }
};
- ///
- public Fast2DArray Matrix { get; } = ThresholdMatrix;
-
- ///
- public void Dither(PixelAccessor pixels, TColor source, TColor upper, TColor lower, byte[] bytes, int index, int x, int y, int width, int height)
- where TColor : struct, IPixel
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Bayer()
+ : base(ThresholdMatrix)
{
- source.ToXyzwBytes(bytes, 0);
- pixels[x, y] = ThresholdMatrix[y % 3, x % 3] >= bytes[index] ? lower : upper;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs b/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs
index 162cdb6a18..5c98973747 100644
--- a/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs
+++ b/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs
@@ -5,18 +5,11 @@
namespace ImageSharp.Dithering
{
- using System;
-
///
/// Encapsulates properties and methods required to perfom ordered dithering on an image.
///
public interface IOrderedDither
{
- ///
- /// Gets the dithering matrix
- ///
- Fast2DArray Matrix { get; }
-
///
/// Transforms the image applying the dither matrix. This method alters the input pixels array
///
@@ -34,4 +27,4 @@ namespace ImageSharp.Dithering
void Dither(PixelAccessor pixels, TColor source, TColor upper, TColor lower, byte[] bytes, int index, int x, int y, int width, int height)
where TColor : struct, IPixel;
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Dithering/Ordered/Ordered.cs b/src/ImageSharp/Dithering/Ordered/Ordered.cs
index aabca31aad..ae75b87f21 100644
--- a/src/ImageSharp/Dithering/Ordered/Ordered.cs
+++ b/src/ImageSharp/Dithering/Ordered/Ordered.cs
@@ -5,13 +5,11 @@
namespace ImageSharp.Dithering.Ordered
{
- using System;
-
///
/// Applies error diffusion based dithering using the 4x4 ordered dithering matrix.
///
///
- public class Ordered : IOrderedDither
+ public sealed class Ordered : OrderedDither4x4
{
///
/// The threshold matrix.
@@ -26,15 +24,12 @@ namespace ImageSharp.Dithering.Ordered
{ 240, 112, 208, 80 }
};
- ///
- public Fast2DArray Matrix { get; } = ThresholdMatrix;
-
- ///
- public void Dither(PixelAccessor pixels, TColor source, TColor upper, TColor lower, byte[] bytes, int index, int x, int y, int width, int height)
- where TColor : struct, IPixel
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Ordered()
+ : base(ThresholdMatrix)
{
- source.ToXyzwBytes(bytes, 0);
- pixels[x, y] = ThresholdMatrix[y % 3, x % 3] >= bytes[index] ? lower : upper;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs b/src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs
new file mode 100644
index 0000000000..c2b55d98eb
--- /dev/null
+++ b/src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs
@@ -0,0 +1,38 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Dithering.Ordered
+{
+ ///
+ /// The base class for performing ordered ditheroing using a 4x4 matrix.
+ ///
+ public abstract class OrderedDither4x4 : IOrderedDither
+ {
+ ///
+ /// The dithering matrix
+ ///
+ private Fast2DArray matrix;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The thresholding matrix.
+ internal OrderedDither4x4(Fast2DArray matrix)
+ {
+ this.matrix = matrix;
+ }
+
+ ///
+ public void Dither(PixelAccessor pixels, TColor source, TColor upper, TColor lower, byte[] bytes, int index, int x, int y, int width, int height)
+ where TColor : struct, IPixel
+ {
+ // TODO: This doesn't really cut it for me.
+ // I'd rather be using float but we need to add some sort of movalization vector methods to all IPixel implementations
+ // before we can do that as the vectors all cover different ranges.
+ source.ToXyzwBytes(bytes, 0);
+ pixels[x, y] = this.matrix[y % 3, x % 3] >= bytes[index] ? lower : upper;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
index 9f490a3a9b..da5d246372 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
@@ -26,13 +26,13 @@ namespace ImageSharp.Formats
public class BmpDecoder : IImageDecoder
{
///
- public void Decode(Image image, Stream stream, IDecoderOptions options)
+ public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options)
+
where TColor : struct, IPixel
{
- Guard.NotNull(image, "image");
Guard.NotNull(stream, "stream");
- new BmpDecoderCore().Decode(image, stream);
+ return new BmpDecoderCore(configuration).Decode(stream);
}
}
}
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index a75031ea19..18e4e858b8 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -43,21 +43,29 @@ namespace ImageSharp.Formats
///
private BmpInfoHeader infoHeader;
+ private Configuration configuration;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The configuration.
+ public BmpDecoderCore(Configuration configuration)
+ {
+ this.configuration = configuration;
+ }
+
///
/// Decodes the image from the specified this._stream and sets
/// the data to image.
///
/// The pixel format.
- /// The image, where the data should be set to.
- /// Cannot be null (Nothing in Visual Basic).
/// The stream, where the image should be
/// decoded from. Cannot be null (Nothing in Visual Basic).
///
- /// is null.
- /// - or -
/// is null.
///
- public void Decode(Image image, Stream stream)
+ /// The decoded image.
+ public Image Decode(Stream stream)
where TColor : struct, IPixel
{
this.currentStream = stream;
@@ -110,15 +118,14 @@ namespace ImageSharp.Formats
this.currentStream.Read(palette, 0, colorMapSize);
}
- if (this.infoHeader.Width > image.MaxWidth || this.infoHeader.Height > image.MaxHeight)
+ if (this.infoHeader.Width > Image.MaxWidth || this.infoHeader.Height > Image.MaxHeight)
{
throw new ArgumentOutOfRangeException(
$"The input bitmap '{this.infoHeader.Width}x{this.infoHeader.Height}' is "
- + $"bigger then the max allowed size '{image.MaxWidth}x{image.MaxHeight}'");
+ + $"bigger then the max allowed size '{Image.MaxWidth}x{Image.MaxHeight}'");
}
- image.InitPixels(this.infoHeader.Width, this.infoHeader.Height);
-
+ Image image = Image.Create(this.infoHeader.Width, this.infoHeader.Height, this.configuration);
using (PixelAccessor pixels = image.Lock())
{
switch (this.infoHeader.Compression)
@@ -151,6 +158,8 @@ namespace ImageSharp.Formats
throw new NotSupportedException("Does not support this kind of bitmap files.");
}
}
+
+ return image;
}
catch (IndexOutOfRangeException e)
{
diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs
index b1e8ba928d..2eb89de8ff 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoder.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs
@@ -14,25 +14,27 @@ namespace ImageSharp.Formats
public class GifDecoder : IImageDecoder
{
///
- public void Decode(Image image, Stream stream, IDecoderOptions options)
+ public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options)
+
where TColor : struct, IPixel
{
IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options);
- this.Decode(image, stream, gifOptions);
+ return this.Decode(configuration, stream, gifOptions);
}
///
/// Decodes the image from the specified stream to the .
///
/// The pixel format.
- /// The to decode to.
+ /// The configuration.
/// The containing image data.
/// The options for the decoder.
- public void Decode(Image image, Stream stream, IGifDecoderOptions options)
+ /// The image thats been decoded.
+ public Image Decode(Configuration configuration, Stream stream, IGifDecoderOptions options)
where TColor : struct, IPixel
{
- new GifDecoderCore(options).Decode(image, stream);
+ return new GifDecoderCore(options, configuration).Decode(stream);
}
}
}
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index ab1edc2c76..4c119ca737 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -28,9 +28,9 @@ namespace ImageSharp.Formats
private readonly IGifDecoderOptions options;
///
- /// The image to decode the information to.
+ /// The global configuration.
///
- private Image decodedImage;
+ private readonly Configuration configuration;
///
/// The currently loaded stream.
@@ -67,25 +67,37 @@ namespace ImageSharp.Formats
///
private GifGraphicsControlExtension graphicsControlExtension;
+ ///
+ /// The metadata
+ ///
+ private ImageMetaData metaData;
+
+ ///
+ /// The image to decode the information to.
+ ///
+ private Image image;
+
///
/// Initializes a new instance of the class.
///
/// The decoder options.
- public GifDecoderCore(IGifDecoderOptions options)
+ /// The configuration.
+ public GifDecoderCore(IGifDecoderOptions options, Configuration configuration)
{
this.options = options ?? new GifDecoderOptions();
+ this.configuration = configuration ?? Configuration.Default;
}
///
/// Decodes the stream to the image.
///
- /// The image to decode to.
/// The stream containing image data.
- public void Decode(Image image, Stream stream)
+ /// The decoded image
+ public Image Decode(Stream stream)
{
try
{
- this.decodedImage = image;
+ this.metaData = new ImageMetaData();
this.currentStream = stream;
@@ -144,6 +156,8 @@ namespace ImageSharp.Formats
ArrayPool.Shared.Return(this.globalColorTable);
}
}
+
+ return this.image;
}
///
@@ -212,11 +226,13 @@ namespace ImageSharp.Formats
throw new ImageFormatException($"Invalid gif colormap size '{this.logicalScreenDescriptor.GlobalColorTableSize}'");
}
- if (this.logicalScreenDescriptor.Width > this.decodedImage.MaxWidth || this.logicalScreenDescriptor.Height > this.decodedImage.MaxHeight)
+ /* // No point doing this as the max width/height is always int.Max and that always bigger than the max size of a gif which is stored in a short.
+ if (this.logicalScreenDescriptor.Width > Image.MaxWidth || this.logicalScreenDescriptor.Height > Image.MaxHeight)
{
throw new ArgumentOutOfRangeException(
- $"The input gif '{this.logicalScreenDescriptor.Width}x{this.logicalScreenDescriptor.Height}' is bigger then the max allowed size '{this.decodedImage.MaxWidth}x{this.decodedImage.MaxHeight}'");
+ $"The input gif '{this.logicalScreenDescriptor.Width}x{this.logicalScreenDescriptor.Height}' is bigger then the max allowed size '{Image.MaxWidth}x{Image.MaxHeight}'");
}
+ */
}
///
@@ -261,7 +277,7 @@ namespace ImageSharp.Formats
{
this.currentStream.Read(commentsBuffer, 0, length);
string comments = this.options.TextEncoding.GetString(commentsBuffer, 0, length);
- this.decodedImage.MetaData.Properties.Add(new ImageProperty(GifConstants.Comments, comments));
+ this.metaData.Properties.Add(new ImageProperty(GifConstants.Comments, comments));
}
finally
{
@@ -343,14 +359,14 @@ namespace ImageSharp.Formats
if (this.previousFrame == null)
{
- this.decodedImage.MetaData.Quality = colorTableLength / 3;
+ this.metaData.Quality = colorTableLength / 3;
// This initializes the image to become fully transparent because the alpha channel is zero.
- this.decodedImage.InitPixels(imageWidth, imageHeight);
+ this.image = Image.Create(imageWidth, imageHeight, this.metaData, this.configuration);
- this.SetFrameDelay(this.decodedImage.MetaData);
+ this.SetFrameDelay(this.metaData);
- image = this.decodedImage;
+ image = this.image;
}
else
{
@@ -368,7 +384,7 @@ namespace ImageSharp.Formats
this.RestoreToBackground(image);
- this.decodedImage.Frames.Add(currentFrame);
+ this.image.Frames.Add(currentFrame);
}
int i = 0;
@@ -441,7 +457,7 @@ namespace ImageSharp.Formats
return;
}
- this.previousFrame = currentFrame == null ? this.decodedImage.ToFrame() : currentFrame;
+ this.previousFrame = currentFrame == null ? this.image.ToFrame() : currentFrame;
if (this.graphicsControlExtension != null &&
this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
@@ -462,8 +478,8 @@ namespace ImageSharp.Formats
}
// Optimization for when the size of the frame is the same as the image size.
- if (this.restoreArea.Value.Width == this.decodedImage.Width &&
- this.restoreArea.Value.Height == this.decodedImage.Height)
+ if (this.restoreArea.Value.Width == this.image.Width &&
+ this.restoreArea.Value.Height == this.image.Height)
{
using (PixelAccessor pixelAccessor = frame.Lock())
{
diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs
index df98870ddd..c85fbef101 100644
--- a/src/ImageSharp/Formats/IImageDecoder.cs
+++ b/src/ImageSharp/Formats/IImageDecoder.cs
@@ -17,10 +17,11 @@ namespace ImageSharp.Formats
/// Decodes the image from the specified stream to the .
///
/// The pixel format.
- /// The to decode to.
+ /// The configuration for the image.
/// The containing image data.
/// The options for the decoder.
- void Decode(Image image, Stream stream, IDecoderOptions options)
+ /// The decoded image
+ Image Decode(Configuration configuration, Stream stream, IDecoderOptions options)
where TColor : struct, IPixel;
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockProcessor.cs
index 85018a06f1..0acee3a10b 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockProcessor.cs
@@ -71,8 +71,8 @@ namespace ImageSharp.Formats.Jpg
DCT.TransformIDCT(ref *b, ref *this.pointers.Temp1, ref *this.pointers.Temp2);
- var destChannel = decoder.GetDestinationChannel(this.componentIndex);
- var destArea = destChannel.GetOffsetedSubAreaForBlock(decodedBlock.Bx, decodedBlock.By);
+ JpegPixelArea destChannel = decoder.GetDestinationChannel(this.componentIndex);
+ JpegPixelArea destArea = destChannel.GetOffsetedSubAreaForBlock(decodedBlock.Bx, decodedBlock.By);
destArea.LoadColorsFrom(this.pointers.Temp1, this.pointers.Temp2);
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs
index 9fe6fecec9..728da8d02e 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs
@@ -78,7 +78,7 @@ namespace ImageSharp.Formats.Jpg
public static JpegPixelArea CreatePooled(int width, int height)
{
int size = width * height;
- var pixels = BytePool.Rent(size);
+ byte[] pixels = BytePool.Rent(size);
return new JpegPixelArea(pixels, width, 0);
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.cs
index 10f859e420..c6362a8713 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.cs
@@ -305,7 +305,7 @@ namespace ImageSharp.Formats.Jpg
/// The index of the scan
private void DecodeBlock(JpegDecoderCore decoder, int scanIndex)
{
- var b = this.pointers.Block;
+ Block8x8F* b = this.pointers.Block;
int huffmannIdx = (HuffmanTree.AcTableIndex * HuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector;
if (this.ah != 0)
{
@@ -630,7 +630,7 @@ namespace ImageSharp.Formats.Jpg
/// The
private int RefineNonZeroes(ref InputProcessor bp, int zig, int nz, int delta)
{
- var b = this.pointers.Block;
+ Block8x8F* b = this.pointers.Block;
for (; zig <= this.zigEnd; zig++)
{
int u = this.pointers.Unzig[zig];
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
index eeb371d1e7..0aac316035 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
@@ -14,15 +14,14 @@ namespace ImageSharp.Formats
public class JpegDecoder : IImageDecoder
{
///
- public void Decode(Image image, Stream stream, IDecoderOptions options)
+ public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options)
where TColor : struct, IPixel
{
- Guard.NotNull(image, "image");
Guard.NotNull(stream, "stream");
- using (JpegDecoderCore decoder = new JpegDecoderCore(options))
+ using (JpegDecoderCore decoder = new JpegDecoderCore(options, configuration))
{
- decoder.Decode(image, stream, false);
+ return decoder.Decode(stream);
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index f1b85fa0bf..33533aa12b 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -42,6 +42,11 @@ namespace ImageSharp.Formats
///
private readonly IDecoderOptions options;
+ ///
+ /// The global configuration
+ ///
+ private readonly Configuration configuration;
+
///
/// The App14 marker color-space
///
@@ -91,8 +96,10 @@ namespace ImageSharp.Formats
/// Initializes a new instance of the class.
///
/// The decoder options.
- public JpegDecoderCore(IDecoderOptions options)
+ /// The configuration.
+ public JpegDecoderCore(IDecoderOptions options, Configuration configuration)
{
+ this.configuration = configuration ?? Configuration.Default;
this.options = options ?? new DecoderOptions();
this.HuffmanTrees = HuffmanTree.CreateHuffmanTrees();
this.QuantizationTables = new Block8x8F[MaxTq + 1];
@@ -180,18 +187,17 @@ namespace ImageSharp.Formats
/// the data to image.
///
/// The pixel format.
- /// The image, where the data should be set to.
/// The stream, where the image should be.
- /// Whether to decode metadata only.
- public void Decode(Image image, Stream stream, bool metadataOnly)
+ /// The decoded image.
+ public Image Decode(Stream stream)
where TColor : struct, IPixel
{
- this.ProcessStream(image, stream, metadataOnly);
- if (!metadataOnly)
- {
- this.ProcessBlocksIntoJpegImageChannels();
- this.ConvertJpegPixelsToImagePixels(image);
- }
+ ImageMetaData metadata = new ImageMetaData();
+ this.ProcessStream(metadata, stream, false);
+ this.ProcessBlocksIntoJpegImageChannels();
+ Image image = this.ConvertJpegPixelsToImagePixels(metadata);
+
+ return image;
}
///
@@ -276,12 +282,10 @@ namespace ImageSharp.Formats
///
/// Read metadata from stream and read the blocks in the scans into .
///
- /// The pixel type
- /// The
+ /// The metadata
/// The stream
/// Whether to decode metadata only.
- private void ProcessStream(Image image, Stream stream, bool metadataOnly)
- where TColor : struct, IPixel
+ private void ProcessStream(ImageMetaData metadata, Stream stream, bool metadataOnly)
{
this.InputStream = stream;
this.InputProcessor = new InputProcessor(stream, this.Temp);
@@ -429,7 +433,7 @@ namespace ImageSharp.Formats
this.ProcessApplicationHeader(remaining);
break;
case JpegConstants.Markers.APP1:
- this.ProcessApp1Marker(remaining, image);
+ this.ProcessApp1Marker(remaining, metadata);
break;
case JpegConstants.Markers.APP14:
this.ProcessApp14Marker(remaining);
@@ -496,13 +500,17 @@ namespace ImageSharp.Formats
/// Convert the pixel data in and/or into pixels of
///
/// The pixel type
- /// The destination image
- private void ConvertJpegPixelsToImagePixels(Image image)
+ /// The metadata for the image.
+ /// The decoded image.
+ private Image ConvertJpegPixelsToImagePixels(ImageMetaData metadata)
where TColor : struct, IPixel
{
+ Image image = Image.Create(this.ImageWidth, this.ImageHeight, metadata, this.configuration);
+
if (this.grayImage.IsInitialized)
{
- this.ConvertFromGrayScale(this.ImageWidth, this.ImageHeight, image);
+ this.ConvertFromGrayScale(image);
+ return image;
}
else if (this.ycbcrImage != null)
{
@@ -519,27 +527,27 @@ namespace ImageSharp.Formats
// TODO: YCbCrA?
if (this.adobeTransform == JpegConstants.Adobe.ColorTransformYcck)
{
- this.ConvertFromYcck(this.ImageWidth, this.ImageHeight, image);
+ this.ConvertFromYcck(image);
}
else if (this.adobeTransform == JpegConstants.Adobe.ColorTransformUnknown)
{
// Assume CMYK
- this.ConvertFromCmyk(this.ImageWidth, this.ImageHeight, image);
+ this.ConvertFromCmyk(image);
}
- return;
+ return image;
}
if (this.ComponentCount == 3)
{
if (this.IsRGB())
{
- this.ConvertFromRGB(this.ImageWidth, this.ImageHeight, image);
- return;
+ this.ConvertFromRGB(image);
+ return image;
}
- this.ConvertFromYCbCr(this.ImageWidth, this.ImageHeight, image);
- return;
+ this.ConvertFromYCbCr(image);
+ return image;
}
throw new ImageFormatException("JpegDecoder only supports RGB, CMYK and Grayscale color spaces.");
@@ -582,28 +590,24 @@ namespace ImageSharp.Formats
/// Converts the image from the original CMYK image pixels.
///
/// The pixel format.
- /// The image width.
- /// The image height.
/// The image.
- private void ConvertFromCmyk(int width, int height, Image image)
+ private void ConvertFromCmyk(Image image)
where TColor : struct, IPixel
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
- image.InitPixels(width, height);
-
using (PixelAccessor pixels = image.Lock())
{
Parallel.For(
0,
- height,
+ image.Height,
y =>
{
// TODO: Simplify + optimize + share duplicate code across converter methods
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
- for (int x = 0; x < width; x++)
+ for (int x = 0; x < image.Width; x++)
{
byte cyan = this.ycbcrImage.YChannel.Pixels[yo + x];
byte magenta = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
@@ -623,24 +627,20 @@ namespace ImageSharp.Formats
/// Converts the image from the original grayscale image pixels.
///
/// The pixel format.
- /// The image width.
- /// The image height.
/// The image.
- private void ConvertFromGrayScale(int width, int height, Image image)
+ private void ConvertFromGrayScale(Image image)
where TColor : struct, IPixel
{
- image.InitPixels(width, height);
-
using (PixelAccessor pixels = image.Lock())
{
Parallel.For(
0,
- height,
+ image.Height,
image.Configuration.ParallelOptions,
y =>
{
int yoff = this.grayImage.GetRowOffset(y);
- for (int x = 0; x < width; x++)
+ for (int x = 0; x < image.Width; x++)
{
byte rgb = this.grayImage.Pixels[yoff + x];
@@ -658,20 +658,17 @@ namespace ImageSharp.Formats
/// Converts the image from the original RBG image pixels.
///
/// The pixel format.
- /// The image width.
- /// The height.
/// The image.
- private void ConvertFromRGB(int width, int height, Image image)
+ private void ConvertFromRGB(Image image)
where TColor : struct, IPixel
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
- image.InitPixels(width, height);
using (PixelAccessor pixels = image.Lock())
{
Parallel.For(
0,
- height,
+ image.Height,
image.Configuration.ParallelOptions,
y =>
{
@@ -679,7 +676,7 @@ namespace ImageSharp.Formats
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
- for (int x = 0; x < width; x++)
+ for (int x = 0; x < image.Width; x++)
{
byte red = this.ycbcrImage.YChannel.Pixels[yo + x];
byte green = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
@@ -699,20 +696,16 @@ namespace ImageSharp.Formats
/// Converts the image from the original YCbCr image pixels.
///
/// The pixel format.
- /// The image width.
- /// The image height.
/// The image.
- private void ConvertFromYCbCr(int width, int height, Image image)
+ private void ConvertFromYCbCr(Image image)
where TColor : struct, IPixel
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
- image.InitPixels(width, height);
-
using (PixelAccessor pixels = image.Lock())
{
Parallel.For(
0,
- height,
+ image.Height,
image.Configuration.ParallelOptions,
y =>
{
@@ -720,7 +713,7 @@ namespace ImageSharp.Formats
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
- for (int x = 0; x < width; x++)
+ for (int x = 0; x < image.Width; x++)
{
byte yy = this.ycbcrImage.YChannel.Pixels[yo + x];
byte cb = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
@@ -740,28 +733,24 @@ namespace ImageSharp.Formats
/// Converts the image from the original YCCK image pixels.
///
/// The pixel format.
- /// The image width.
- /// The image height.
/// The image.
- private void ConvertFromYcck(int width, int height, Image image)
+ private void ConvertFromYcck(Image image)
where TColor : struct, IPixel
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
- image.InitPixels(width, height);
-
using (PixelAccessor pixels = image.Lock())
{
Parallel.For(
0,
- height,
+ image.Height,
y =>
{
// TODO: Simplify + optimize + share duplicate code across converter methods
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
- for (int x = 0; x < width; x++)
+ for (int x = 0; x < image.Width; x++)
{
byte yy = this.ycbcrImage.YChannel.Pixels[yo + x];
byte cb = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
@@ -959,11 +948,9 @@ namespace ImageSharp.Formats
///
/// Processes the App1 marker retrieving any stored metadata
///
- /// The pixel format.
/// The remaining bytes in the segment block.
- /// The image.
- private void ProcessApp1Marker(int remaining, Image image)
- where TColor : struct, IPixel
+ /// The image.
+ private void ProcessApp1Marker(int remaining, ImageMetaData metadata)
{
if (remaining < 6 || this.options.IgnoreMetadata)
{
@@ -978,7 +965,7 @@ namespace ImageSharp.Formats
&& profile[5] == '\0')
{
this.isExif = true;
- image.MetaData.ExifProfile = new ExifProfile(profile);
+ metadata.ExifProfile = new ExifProfile(profile);
}
}
diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs
index d527e1654d..d0a820c17f 100644
--- a/src/ImageSharp/Formats/Png/PngDecoder.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoder.cs
@@ -31,25 +31,27 @@ namespace ImageSharp.Formats
public class PngDecoder : IImageDecoder
{
///
- public void Decode(Image image, Stream stream, IDecoderOptions options)
+ public Image Decode(Configuration configuration, Stream stream, IDecoderOptions options)
+
where TColor : struct, IPixel
{
IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options);
- this.Decode(image, stream, pngOptions);
+ return this.Decode(configuration, stream, pngOptions);
}
///
/// Decodes the image from the specified stream to the .
///
/// The pixel format.
- /// The to decode to.
+ /// The configuration for the image.
/// The containing image data.
/// The options for the decoder.
- public void Decode(Image image, Stream stream, IPngDecoderOptions options)
+ /// The decoded image.
+ public Image Decode(Configuration configuration, Stream stream, IPngDecoderOptions options)
where TColor : struct, IPixel
{
- new PngDecoderCore(options).Decode(image, stream);
+ return new PngDecoderCore(options, configuration).Decode(stream);
}
}
}
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index fd03ed39b8..d6529940e2 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -74,6 +74,11 @@ namespace ImageSharp.Formats
///
private readonly Crc32 crc = new Crc32();
+ ///
+ /// The global configuration.
+ ///
+ private readonly Configuration configuration;
+
///
/// The stream to decode from.
///
@@ -134,8 +139,10 @@ namespace ImageSharp.Formats
/// Initializes a new instance of the class.
///
/// The decoder options.
- public PngDecoderCore(IPngDecoderOptions options)
+ /// The configuration.
+ public PngDecoderCore(IPngDecoderOptions options, Configuration configuration)
{
+ this.configuration = configuration ?? Configuration.Default;
this.options = options ?? new PngDecoderOptions();
}
@@ -148,7 +155,6 @@ namespace ImageSharp.Formats
/// Decodes the stream to the image.
///
/// The pixel format.
- /// The image to decode to.
/// The stream containing image data.
///
/// Thrown if the stream does not contain and end chunk.
@@ -156,10 +162,11 @@ namespace ImageSharp.Formats
///
/// Thrown if the image is larger than the maximum allowable size.
///
- public void Decode(Image image, Stream stream)
+ /// The decoded image
+ public Image Decode(Stream stream)
where TColor : struct, IPixel
{
- Image currentImage = image;
+ ImageMetaData metadata = new ImageMetaData();
this.currentStream = stream;
this.currentStream.Skip(8);
@@ -177,7 +184,7 @@ namespace ImageSharp.Formats
this.ValidateHeader();
break;
case PngChunkTypes.Physical:
- this.ReadPhysicalChunk(currentImage, currentChunk.Data);
+ this.ReadPhysicalChunk(metadata, currentChunk.Data);
break;
case PngChunkTypes.Data:
dataStream.Write(currentChunk.Data, 0, currentChunk.Length);
@@ -186,7 +193,7 @@ namespace ImageSharp.Formats
byte[] pal = new byte[currentChunk.Length];
Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length);
this.palette = pal;
- image.MetaData.Quality = pal.Length / 3;
+ metadata.Quality = pal.Length / 3;
break;
case PngChunkTypes.PaletteAlpha:
byte[] alpha = new byte[currentChunk.Length];
@@ -194,7 +201,7 @@ namespace ImageSharp.Formats
this.paletteAlpha = alpha;
break;
case PngChunkTypes.Text:
- this.ReadTextChunk(currentImage, currentChunk.Data, currentChunk.Length);
+ this.ReadTextChunk(metadata, currentChunk.Data, currentChunk.Length);
break;
case PngChunkTypes.End:
this.isEndChunkReached = true;
@@ -208,17 +215,19 @@ namespace ImageSharp.Formats
}
}
- if (this.header.Width > image.MaxWidth || this.header.Height > image.MaxHeight)
+ 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}'");
+ 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.InitPixels(this.header.Width, this.header.Height);
+ Image image = Image.Create(this.header.Width, this.header.Height, metadata, this.configuration);
using (PixelAccessor pixels = image.Lock())
{
this.ReadScanlines(dataStream, pixels);
}
+
+ return image;
}
}
@@ -270,18 +279,16 @@ namespace ImageSharp.Formats
///
/// Reads the data chunk containing physical dimension data.
///
- /// The pixel format.
- /// The image to read to.
+ /// The metadata to read to.
/// The data containing physical data.
- private void ReadPhysicalChunk(Image image, byte[] data)
- where TColor : struct, IPixel
+ private void ReadPhysicalChunk(ImageMetaData metadata, byte[] data)
{
data.ReverseBytes(0, 4);
data.ReverseBytes(4, 4);
// 39.3700787 = inches in a meter.
- image.MetaData.HorizontalResolution = BitConverter.ToInt32(data, 0) / 39.3700787d;
- image.MetaData.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d;
+ metadata.HorizontalResolution = BitConverter.ToInt32(data, 0) / 39.3700787d;
+ metadata.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d;
}
///
@@ -768,12 +775,10 @@ namespace ImageSharp.Formats
///
/// Reads a text chunk containing image properties from the data.
///
- /// The pixel format.
- /// The image to decode to.
+ /// The metadata to decode to.
/// The containing data.
/// The maximum length to read.
- private void ReadTextChunk(Image image, byte[] data, int length)
- where TColor : struct, IPixel
+ private void ReadTextChunk(ImageMetaData metadata, byte[] data, int length)
{
if (this.options.IgnoreMetadata)
{
@@ -794,7 +799,7 @@ namespace ImageSharp.Formats
string name = this.options.TextEncoding.GetString(data, 0, zeroIndex);
string value = this.options.TextEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1);
- image.MetaData.Properties.Add(new ImageProperty(name, value));
+ metadata.Properties.Add(new ImageProperty(name, value));
}
///
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 7950d260c7..498ae578c3 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -544,12 +544,11 @@ namespace ImageSharp.Formats
///
/// The pixel format.
/// The containing image data.
- /// The image base.
- private void WritePhysicalChunk(Stream stream, ImageBase imageBase)
+ /// The image.
+ private void WritePhysicalChunk(Stream stream, Image image)
where TColor : struct, IPixel
{
- Image image = imageBase as Image;
- if (image != null && image.MetaData.HorizontalResolution > 0 && image.MetaData.VerticalResolution > 0)
+ if (image.MetaData.HorizontalResolution > 0 && image.MetaData.VerticalResolution > 0)
{
// 39.3700787 = inches in a meter.
int dpmX = (int)Math.Round(image.MetaData.HorizontalResolution * 39.3700787D);
diff --git a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs
index e32e808c1f..ec3b8ebe73 100644
--- a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs
+++ b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs
@@ -13,11 +13,11 @@ namespace ImageSharp.Formats
///
/// Non interlaced
///
- None,
+ None = 0,
///
/// Adam 7 interlacing.
///
- Adam7
+ Adam7 = 1
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/IO/BigEndianBitConverter.cs b/src/ImageSharp/IO/BigEndianBitConverter.cs
index 0841027282..debe1706c9 100644
--- a/src/ImageSharp/IO/BigEndianBitConverter.cs
+++ b/src/ImageSharp/IO/BigEndianBitConverter.cs
@@ -6,43 +6,81 @@
namespace ImageSharp.IO
{
///
- /// Implementation of EndianBitConverter which converts to/from big-endian
- /// byte arrays.
- ///
- /// Adapted from Miscellaneous Utility Library
- /// This product includes software developed by Jon Skeet and Marc Gravell. Contact , or see
- /// .
- ///
+ /// Implementation of EndianBitConverter which converts to/from big-endian byte arrays.
///
internal sealed class BigEndianBitConverter : EndianBitConverter
{
///
- public override Endianness Endianness => Endianness.BigEndian;
+ public override Endianness Endianness
+ {
+ get { return Endianness.BigEndian; }
+ }
///
- public override bool IsLittleEndian() => false;
+ public override bool IsLittleEndian
+ {
+ get { return false; }
+ }
///
- protected internal override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
+ public override void CopyBytes(short value, byte[] buffer, int index)
{
- int endOffset = index + bytes - 1;
- for (int i = 0; i < bytes; i++)
- {
- buffer[endOffset - i] = unchecked((byte)(value & 0xff));
- value = value >> 8;
- }
+ CheckByteArgument(buffer, index, 2);
+
+ buffer[index] = (byte)(value >> 8);
+ buffer[index + 1] = (byte)value;
+ }
+
+ ///
+ public override void CopyBytes(int value, byte[] buffer, int index)
+ {
+ CheckByteArgument(buffer, index, 4);
+
+ buffer[index] = (byte)(value >> 24);
+ buffer[index + 1] = (byte)(value >> 16);
+ buffer[index + 2] = (byte)(value >> 8);
+ buffer[index + 3] = (byte)value;
+ }
+
+ ///
+ public override void CopyBytes(long value, byte[] buffer, int index)
+ {
+ CheckByteArgument(buffer, index, 8);
+
+ buffer[index] = (byte)(value >> 56);
+ buffer[index + 1] = (byte)(value >> 48);
+ buffer[index + 2] = (byte)(value >> 40);
+ buffer[index + 3] = (byte)(value >> 32);
+ buffer[index + 4] = (byte)(value >> 24);
+ buffer[index + 5] = (byte)(value >> 16);
+ buffer[index + 6] = (byte)(value >> 8);
+ buffer[index + 7] = (byte)value;
+ }
+
+ ///
+ public override short ToInt16(byte[] value, int startIndex)
+ {
+ CheckByteArgument(value, startIndex, 2);
+
+ return (short)((value[startIndex] << 8) | value[startIndex + 1]);
+ }
+
+ ///
+ public override int ToInt32(byte[] value, int startIndex)
+ {
+ CheckByteArgument(value, startIndex, 4);
+
+ return (value[startIndex] << 24) | (value[startIndex + 1] << 16) | (value[startIndex + 2] << 8) | value[startIndex + 3];
}
///
- protected internal override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
+ public override long ToInt64(byte[] value, int startIndex)
{
- long ret = 0;
- for (int i = 0; i < bytesToConvert; i++)
- {
- ret = unchecked((ret << 8) | buffer[startIndex + i]);
- }
+ CheckByteArgument(value, startIndex, 8);
- return ret;
+ long p1 = (value[startIndex] << 24) | (value[startIndex + 1] << 16) | (value[startIndex + 2] << 8) | value[startIndex + 3];
+ long p2 = (value[startIndex + 4] << 24) | (value[startIndex + 5] << 16) | (value[startIndex + 6] << 8) | value[startIndex + 7];
+ return p2 | (p1 << 32);
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/IO/EndianBinaryReader.cs b/src/ImageSharp/IO/EndianBinaryReader.cs
index d12d0b9761..e21d3d3db3 100644
--- a/src/ImageSharp/IO/EndianBinaryReader.cs
+++ b/src/ImageSharp/IO/EndianBinaryReader.cs
@@ -68,7 +68,7 @@ namespace ImageSharp.IO
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(encoding, nameof(encoding));
- Guard.IsTrue(stream.CanRead, nameof(stream), "Stream isn't readable.");
+ Guard.IsTrue(stream.CanRead, nameof(stream), "Stream isn't readable");
this.BaseStream = stream;
this.BitConverter = EndianBitConverter.GetConverter(endianness);
@@ -510,7 +510,7 @@ namespace ImageSharp.IO
{
if (this.disposed)
{
- throw new ObjectDisposedException("EndianBinaryReader");
+ throw new ObjectDisposedException(nameof(EndianBinaryReader));
}
}
diff --git a/src/ImageSharp/IO/EndianBinaryWriter.cs b/src/ImageSharp/IO/EndianBinaryWriter.cs
index 027c2b1f06..ef026f00c2 100644
--- a/src/ImageSharp/IO/EndianBinaryWriter.cs
+++ b/src/ImageSharp/IO/EndianBinaryWriter.cs
@@ -52,31 +52,12 @@ namespace ImageSharp.IO
///
public EndianBinaryWriter(Endianness endianness, Stream stream, Encoding encoding)
{
- var bitConverter = EndianBitConverter.GetConverter(endianness);
-
- // TODO: Use Guard
- if (bitConverter == null)
- {
- throw new ArgumentNullException("bitConverter");
- }
-
- if (stream == null)
- {
- throw new ArgumentNullException("stream");
- }
-
- if (encoding == null)
- {
- throw new ArgumentNullException("encoding");
- }
-
- if (!stream.CanWrite)
- {
- throw new ArgumentException("Stream isn't writable", "stream");
- }
+ Guard.NotNull(stream, nameof(stream));
+ Guard.NotNull(stream, nameof(encoding));
+ Guard.IsTrue(stream.CanWrite, nameof(stream), "Stream isn't writable");
this.BaseStream = stream;
- this.BitConverter = bitConverter;
+ this.BitConverter = EndianBitConverter.GetConverter(endianness);
this.Encoding = encoding;
}
@@ -256,13 +237,10 @@ namespace ImageSharp.IO
/// Writes an array of bytes to the stream.
///
/// The values to write
+ /// value is null
public void Write(byte[] value)
{
- if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
-
+ Guard.NotNull(value, nameof(value));
this.WriteInternal(value, value.Length);
}
@@ -272,6 +250,7 @@ namespace ImageSharp.IO
/// An array containing the bytes to write
/// The index of the first byte to write within the array
/// The number of bytes to write
+ /// value is null
public void Write(byte[] value, int offset, int count)
{
this.CheckDisposed();
@@ -292,12 +271,10 @@ namespace ImageSharp.IO
/// Writes an array of characters to the stream, using the encoding for this writer.
///
/// An array containing the characters to write
+ /// value is null
public void Write(char[] value)
{
- if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
+ Guard.NotNull(value, nameof(value));
this.CheckDisposed();
byte[] data = this.Encoding.GetBytes(value, 0, value.Length);
@@ -305,16 +282,13 @@ namespace ImageSharp.IO
}
///
- /// Writes a string to the stream, using the encoding for this writer.
+ /// Writes a length-prefixed string to the stream, using the encoding for this writer.
///
/// The value to write. Must not be null.
- /// value is null
+ /// value is null
public void Write(string value)
{
- if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
+ Guard.NotNull(value, nameof(value));
this.CheckDisposed();
byte[] data = this.Encoding.GetBytes(value);
@@ -368,7 +342,7 @@ namespace ImageSharp.IO
{
if (this.disposed)
{
- throw new ObjectDisposedException("EndianBinaryWriter");
+ throw new ObjectDisposedException(nameof(EndianBinaryWriter));
}
}
diff --git a/src/ImageSharp/IO/EndianBitConverter.Conversion.cs b/src/ImageSharp/IO/EndianBitConverter.Conversion.cs
new file mode 100644
index 0000000000..0858acfedc
--- /dev/null
+++ b/src/ImageSharp/IO/EndianBitConverter.Conversion.cs
@@ -0,0 +1,63 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.IO
+{
+ using System;
+
+ ///
+ /// Equivalent of , but with either endianness.
+ ///
+ internal abstract partial class EndianBitConverter
+ {
+ ///
+ /// Converts the specified double-precision floating point number to a
+ /// 64-bit signed integer. Note: the endianness of this converter does not
+ /// affect the returned value.
+ ///
+ /// The number to convert.
+ /// A 64-bit signed integer whose value is equivalent to value.
+ public unsafe long DoubleToInt64Bits(double value)
+ {
+ return *((long*)&value);
+ }
+
+ ///
+ /// Converts the specified 64-bit signed integer to a double-precision
+ /// floating point number. Note: the endianness of this converter does not
+ /// affect the returned value.
+ ///
+ /// The number to convert.
+ /// A double-precision floating point number whose value is equivalent to value.
+ public unsafe double Int64BitsToDouble(long value)
+ {
+ return *((double*)&value);
+ }
+
+ ///
+ /// Converts the specified single-precision floating point number to a
+ /// 32-bit signed integer. Note: the endianness of this converter does not
+ /// affect the returned value.
+ ///
+ /// The number to convert.
+ /// A 32-bit signed integer whose value is equivalent to value.
+ public unsafe int SingleToInt32Bits(float value)
+ {
+ return *((int*)&value);
+ }
+
+ ///
+ /// Converts the specified 32-bit signed integer to a single-precision floating point
+ /// number. Note: the endianness of this converter does not
+ /// affect the returned value.
+ ///
+ /// The number to convert.
+ /// A single-precision floating point number whose value is equivalent to value.
+ public unsafe float Int32BitsToSingle(int value)
+ {
+ return *((float*)&value);
+ }
+ }
+}
diff --git a/src/ImageSharp/IO/EndianBitConverter.CopyBytes.cs b/src/ImageSharp/IO/EndianBitConverter.CopyBytes.cs
new file mode 100644
index 0000000000..b46a453a4f
--- /dev/null
+++ b/src/ImageSharp/IO/EndianBitConverter.CopyBytes.cs
@@ -0,0 +1,145 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.IO
+{
+ using System;
+
+ ///
+ /// Equivalent of , but with either endianness.
+ ///
+ internal abstract partial class EndianBitConverter
+ {
+ ///
+ /// Copies the specified 16-bit signed integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public abstract void CopyBytes(short value, byte[] buffer, int index);
+
+ ///
+ /// Copies the specified 32-bit signed integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public abstract void CopyBytes(int value, byte[] buffer, int index);
+
+ ///
+ /// Copies the specified 64-bit signed integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public abstract void CopyBytes(long value, byte[] buffer, int index);
+
+ ///
+ /// Copies the specified 16-bit unsigned integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(ushort value, byte[] buffer, int index)
+ {
+ this.CopyBytes(unchecked((short)value), buffer, index);
+ }
+
+ ///
+ /// Copies the specified 32-bit unsigned integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(uint value, byte[] buffer, int index)
+ {
+ this.CopyBytes(unchecked((int)value), buffer, index);
+ }
+
+ ///
+ /// Copies the specified 64-bit unsigned integer value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(ulong value, byte[] buffer, int index)
+ {
+ this.CopyBytes(unchecked((long)value), buffer, index);
+ }
+
+ ///
+ /// Copies the specified Boolean value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// A Boolean value.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(bool value, byte[] buffer, int index)
+ {
+ CheckByteArgument(buffer, index, 1);
+ buffer[index] = value ? (byte)1 : (byte)0;
+ }
+
+ ///
+ /// Copies the specified Unicode character value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// A character to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public void CopyBytes(char value, byte[] buffer, int index)
+ {
+ this.CopyBytes(unchecked((short)value), buffer, index);
+ }
+
+ ///
+ /// Copies the specified double-precision floating point value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public unsafe void CopyBytes(double value, byte[] buffer, int index)
+ {
+ this.CopyBytes(*((long*)&value), buffer, index);
+ }
+
+ ///
+ /// Copies the specified single-precision floating point value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// The number to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public unsafe void CopyBytes(float value, byte[] buffer, int index)
+ {
+ this.CopyBytes(*((int*)&value), buffer, index);
+ }
+
+ ///
+ /// Copies the specified decimal value into the specified byte array,
+ /// beginning at the specified index.
+ ///
+ /// A character to convert.
+ /// The byte array to copy the bytes into
+ /// The first index into the array to copy the bytes into
+ public unsafe void CopyBytes(decimal value, byte[] buffer, int index)
+ {
+ CheckByteArgument(buffer, index, 16);
+
+ int* pvalue = (int*)&value;
+ this.CopyBytes(pvalue[0], buffer, index);
+ this.CopyBytes(pvalue[1], buffer, index + 4);
+ this.CopyBytes(pvalue[2], buffer, index + 8);
+ this.CopyBytes(pvalue[3], buffer, index + 12);
+ }
+ }
+}
diff --git a/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs b/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs
new file mode 100644
index 0000000000..b3e0133e43
--- /dev/null
+++ b/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs
@@ -0,0 +1,139 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.IO
+{
+ using System;
+
+ ///
+ /// Equivalent of , but with either endianness.
+ ///
+ internal abstract partial class EndianBitConverter
+ {
+ ///
+ /// Returns the specified 16-bit signed integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 2.
+ public byte[] GetBytes(short value)
+ {
+ byte[] result = new byte[2];
+ this.CopyBytes(value, result, 0);
+ return result;
+ }
+
+ ///
+ /// Returns the specified 32-bit signed integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 4.
+ public byte[] GetBytes(int value)
+ {
+ byte[] result = new byte[4];
+ this.CopyBytes(value, result, 0);
+ return result;
+ }
+
+ ///
+ /// Returns the specified 64-bit signed integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 8.
+ public byte[] GetBytes(long value)
+ {
+ byte[] result = new byte[8];
+ this.CopyBytes(value, result, 0);
+ return result;
+ }
+
+ ///
+ /// Returns the specified 16-bit unsigned integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 2.
+ public byte[] GetBytes(ushort value)
+ {
+ return this.GetBytes(unchecked((short)value));
+ }
+
+ ///
+ /// Returns the specified 32-bit unsigned integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 4.
+ public byte[] GetBytes(uint value)
+ {
+ return this.GetBytes(unchecked((int)value));
+ }
+
+ ///
+ /// Returns the specified 64-bit unsigned integer value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 8.
+ public byte[] GetBytes(ulong value)
+ {
+ return this.GetBytes(unchecked((long)value));
+ }
+
+ ///
+ /// Returns the specified Boolean value as an array of bytes.
+ ///
+ /// A Boolean value.
+ /// An array of bytes with length 1.
+ ///
+ /// The .
+ ///
+ public byte[] GetBytes(bool value)
+ {
+ return new byte[1] { value ? (byte)1 : (byte)0 };
+ }
+
+ ///
+ /// Returns the specified Unicode character value as an array of bytes.
+ ///
+ /// A character to convert.
+ /// An array of bytes with length 2.
+ ///
+ /// The .
+ ///
+ public byte[] GetBytes(char value)
+ {
+ return this.GetBytes((short)value);
+ }
+
+ ///
+ /// Returns the specified double-precision floating point value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 8.
+ public unsafe byte[] GetBytes(double value)
+ {
+ return this.GetBytes(*((long*)&value));
+ }
+
+ ///
+ /// Returns the specified single-precision floating point value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 4.
+ public unsafe byte[] GetBytes(float value)
+ {
+ return this.GetBytes(*((int*)&value));
+ }
+
+ ///
+ /// Returns the specified decimal value as an array of bytes.
+ ///
+ /// The number to convert.
+ /// An array of bytes with length 16.
+ public byte[] GetBytes(decimal value)
+ {
+ byte[] result = new byte[16];
+ this.CopyBytes(value, result, 0);
+ return result;
+ }
+ }
+}
diff --git a/src/ImageSharp/IO/EndianBitConverter.ToType.cs b/src/ImageSharp/IO/EndianBitConverter.ToType.cs
new file mode 100644
index 0000000000..93b49558ad
--- /dev/null
+++ b/src/ImageSharp/IO/EndianBitConverter.ToType.cs
@@ -0,0 +1,141 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.IO
+{
+ using System;
+
+ ///
+ /// Equivalent of , but with either endianness.
+ ///
+ internal abstract partial class EndianBitConverter
+ {
+ ///
+ /// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 16-bit signed integer formed by two bytes beginning at startIndex.
+ public abstract short ToInt16(byte[] value, int startIndex);
+
+ ///
+ /// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 32-bit signed integer formed by four bytes beginning at startIndex.
+ public abstract int ToInt32(byte[] value, int startIndex);
+
+ ///
+ /// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 64-bit signed integer formed by eight bytes beginning at startIndex.
+ public abstract long ToInt64(byte[] value, int startIndex);
+
+ ///
+ /// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 16-bit unsigned integer formed by two bytes beginning at startIndex.
+ public ushort ToUInt16(byte[] value, int startIndex)
+ {
+ return unchecked((ushort)this.ToInt16(value, startIndex));
+ }
+
+ ///
+ /// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 32-bit unsigned integer formed by four bytes beginning at startIndex.
+ public uint ToUInt32(byte[] value, int startIndex)
+ {
+ return unchecked((uint)this.ToInt32(value, startIndex));
+ }
+
+ ///
+ /// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A 64-bit unsigned integer formed by eight bytes beginning at startIndex.
+ public ulong ToUInt64(byte[] value, int startIndex)
+ {
+ return unchecked((ulong)this.ToInt64(value, startIndex));
+ }
+
+ ///
+ /// Returns a Boolean value converted from one byte at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// true if the byte at startIndex in value is nonzero; otherwise, false.
+ public bool ToBoolean(byte[] value, int startIndex)
+ {
+ CheckByteArgument(value, startIndex, 1);
+ return value[startIndex] != 0;
+ }
+
+ ///
+ /// Returns a Unicode character converted from two bytes at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A character formed by two bytes beginning at startIndex.
+ public char ToChar(byte[] value, int startIndex)
+ {
+ return unchecked((char)this.ToInt16(value, startIndex));
+ }
+
+ ///
+ /// Returns a double-precision floating point number converted from eight bytes
+ /// at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A double precision floating point number formed by eight bytes beginning at startIndex.
+ public unsafe double ToDouble(byte[] value, int startIndex)
+ {
+ long intValue = this.ToInt64(value, startIndex);
+ return *((double*)&intValue);
+ }
+
+ ///
+ /// Returns a single-precision floating point number converted from four bytes
+ /// at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A single precision floating point number formed by four bytes beginning at startIndex.
+ public unsafe float ToSingle(byte[] value, int startIndex)
+ {
+ int intValue = this.ToInt32(value, startIndex);
+ return *((float*)&intValue);
+ }
+
+ ///
+ /// Returns a decimal value converted from sixteen bytes
+ /// at a specified position in a byte array.
+ ///
+ /// An array of bytes.
+ /// The starting position within value.
+ /// A decimal formed by sixteen bytes beginning at startIndex.
+ public unsafe decimal ToDecimal(byte[] value, int startIndex)
+ {
+ CheckByteArgument(value, startIndex, 16);
+
+ decimal result = 0m;
+ int* presult = (int*)&result;
+ presult[0] = this.ToInt32(value, startIndex);
+ presult[1] = this.ToInt32(value, startIndex + 4);
+ presult[2] = this.ToInt32(value, startIndex + 8);
+ presult[3] = this.ToInt32(value, startIndex + 12);
+ return result;
+ }
+ }
+}
diff --git a/src/ImageSharp/IO/EndianBitConverter.cs b/src/ImageSharp/IO/EndianBitConverter.cs
index 812823e7a2..06b88dbc90 100644
--- a/src/ImageSharp/IO/EndianBitConverter.cs
+++ b/src/ImageSharp/IO/EndianBitConverter.cs
@@ -6,291 +6,56 @@
namespace ImageSharp.IO
{
using System;
- using System.Diagnostics.CodeAnalysis;
- using System.Runtime.InteropServices;
+ using System.Runtime.CompilerServices;
///
- /// Equivalent of , but with either endianness.
- ///
- /// Adapted from Miscellaneous Utility Library
- /// This product includes software developed by Jon Skeet and Marc Gravell. Contact , or see
- /// .
- ///
+ /// Equivalent of , but with either endianness.
///
- [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:ElementsMustAppearInTheCorrectOrder", Justification = "Reviewed. Suppression is OK here. Better readability.")]
- [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "Reviewed. Suppression is OK here. Better readability.")]
- [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "Reviewed. Suppression is OK here. Better readability.")]
- [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1124:DoNotUseRegions", Justification = "Reviewed. Suppression is OK here. Better readability.")]
- internal abstract class EndianBitConverter
+ internal abstract partial class EndianBitConverter
{
- #region Endianness of this converter
-
///
- /// Indicates the byte order ("endianness") in which data is converted using this class.
+ /// The little-endian bit converter.
///
- ///
- /// Different computer architectures store data using different byte orders. "Big-endian"
- /// means the most significant byte is on the left end of a word. "Little-endian" means the
- /// most significant byte is on the right end of a word.
- ///
- /// true if this converter is little-endian, false otherwise.
- public abstract bool IsLittleEndian();
+ public static readonly LittleEndianBitConverter LittleEndianConverter = new LittleEndianBitConverter();
///
- /// Gets the byte order ("endianness") in which data is converted using this class.
+ /// The big-endian bit converter.
///
- public abstract Endianness Endianness { get; }
- #endregion
-
- #region Factory properties
+ public static readonly BigEndianBitConverter BigEndianConverter = new BigEndianBitConverter();
///
- /// The little-endian bit converter.
+ /// Gets the byte order ("endianness") in which data is converted using this class.
///
- private static readonly LittleEndianBitConverter LittleConverter = new LittleEndianBitConverter();
+ public abstract Endianness Endianness { get; }
///
- /// The big-endian bit converter.
+ /// Gets a value indicating whether the byte order ("endianness") in which data is converted is little endian.
///
- private static readonly BigEndianBitConverter BigConverter = new BigEndianBitConverter();
+ ///
+ /// Different computer architectures store data using different byte orders. "Big-endian"
+ /// means the most significant byte is on the left end of a word. "Little-endian" means the
+ /// most significant byte is on the right end of a word.
+ ///
+ public abstract bool IsLittleEndian { get; }
///
/// Gets the converter.
///
/// The endianness.
/// an
- /// Not a valid form of Endianness - endianness
- internal static EndianBitConverter GetConverter(Endianness endianness)
+ /// Not a valid form of Endianness - endianness
+ public static EndianBitConverter GetConverter(Endianness endianness)
{
switch (endianness)
{
case Endianness.LittleEndian:
- return LittleConverter;
+ return LittleEndianConverter;
case Endianness.BigEndian:
- return BigConverter;
+ return BigEndianConverter;
default:
throw new ArgumentException("Not a valid form of Endianness", nameof(endianness));
}
}
- #endregion
-
- #region Double/primitive conversions
-
- ///
- /// Converts the specified double-precision floating point number to a
- /// 64-bit signed integer. Note: the endianness of this converter does not
- /// affect the returned value.
- ///
- /// The number to convert.
- /// A 64-bit signed integer whose value is equivalent to value.
- public long DoubleToInt64Bits(double value)
- {
- return BitConverter.DoubleToInt64Bits(value);
- }
-
- ///
- /// Converts the specified 64-bit signed integer to a double-precision
- /// floating point number. Note: the endianness of this converter does not
- /// affect the returned value.
- ///
- /// The number to convert.
- /// A double-precision floating point number whose value is equivalent to value.
- public double Int64BitsToDouble(long value)
- {
- return BitConverter.Int64BitsToDouble(value);
- }
-
- ///
- /// Converts the specified single-precision floating point number to a
- /// 32-bit signed integer. Note: the endianness of this converter does not
- /// affect the returned value.
- ///
- /// The number to convert.
- /// A 32-bit signed integer whose value is equivalent to value.
- public int SingleToInt32Bits(float value)
- {
- return new Int32SingleUnion(value).AsInt32;
- }
-
- ///
- /// Converts the specified 32-bit signed integer to a single-precision floating point
- /// number. Note: the endianness of this converter does not
- /// affect the returned value.
- ///
- /// The number to convert.
- /// A single-precision floating point number whose value is equivalent to value.
- public float Int32BitsToSingle(int value)
- {
- return new Int32SingleUnion(value).AsSingle;
- }
- #endregion
-
- #region To(PrimitiveType) conversions
-
- ///
- /// Returns a Boolean value converted from one byte at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// true if the byte at startIndex in value is nonzero; otherwise, false.
- public bool ToBoolean(byte[] value, int startIndex)
- {
- CheckByteArgument(value, startIndex, 1);
- return BitConverter.ToBoolean(value, startIndex);
- }
-
- ///
- /// Returns a Unicode character converted from two bytes at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A character formed by two bytes beginning at startIndex.
- public char ToChar(byte[] value, int startIndex)
- {
- return unchecked((char)this.CheckedFromBytes(value, startIndex, 2));
- }
-
- ///
- /// Returns a double-precision floating point number converted from eight bytes
- /// at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A double precision floating point number formed by eight bytes beginning at startIndex.
- public double ToDouble(byte[] value, int startIndex)
- {
- return this.Int64BitsToDouble(this.ToInt64(value, startIndex));
- }
-
- ///
- /// Returns a single-precision floating point number converted from four bytes
- /// at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A single precision floating point number formed by four bytes beginning at startIndex.
- public float ToSingle(byte[] value, int startIndex)
- {
- return this.Int32BitsToSingle(this.ToInt32(value, startIndex));
- }
-
- ///
- /// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A 16-bit signed integer formed by two bytes beginning at startIndex.
- public short ToInt16(byte[] value, int startIndex)
- {
- return unchecked((short)this.CheckedFromBytes(value, startIndex, 2));
- }
-
- ///
- /// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A 32-bit signed integer formed by four bytes beginning at startIndex.
- public int ToInt32(byte[] value, int startIndex)
- {
- return unchecked((int)this.CheckedFromBytes(value, startIndex, 4));
- }
-
- ///
- /// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A 64-bit signed integer formed by eight bytes beginning at startIndex.
- public long ToInt64(byte[] value, int startIndex)
- {
- return this.CheckedFromBytes(value, startIndex, 8);
- }
-
- ///
- /// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A 16-bit unsigned integer formed by two bytes beginning at startIndex.
- public ushort ToUInt16(byte[] value, int startIndex)
- {
- return unchecked((ushort)this.CheckedFromBytes(value, startIndex, 2));
- }
-
- ///
- /// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A 32-bit unsigned integer formed by four bytes beginning at startIndex.
- public uint ToUInt32(byte[] value, int startIndex)
- {
- return unchecked((uint)this.CheckedFromBytes(value, startIndex, 4));
- }
-
- ///
- /// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A 64-bit unsigned integer formed by eight bytes beginning at startIndex.
- public ulong ToUInt64(byte[] value, int startIndex)
- {
- return unchecked((ulong)this.CheckedFromBytes(value, startIndex, 8));
- }
-
- ///
- /// Convert the given number of bytes from the given array, from the given start
- /// position, into a long, using the bytes as the least significant part of the long.
- /// By the time this is called, the arguments have been checked for validity.
- ///
- /// The bytes to convert
- /// The index of the first byte to convert
- /// The number of bytes to use in the conversion
- /// The converted number
- protected internal abstract long FromBytes(byte[] value, int startIndex, int bytesToConvert);
-
- ///
- /// Checks the given argument for validity.
- ///
- /// The byte array passed in
- /// The start index passed in
- /// The number of bytes required
- /// value is a null reference
- ///
- /// startIndex is less than zero or greater than the length of value minus bytesRequired.
- ///
- [SuppressMessage("ReSharper", "UnusedParameter.Local", Justification = "Keeps code DRY")]
- private static void CheckByteArgument(byte[] value, int startIndex, int bytesRequired)
- {
- if (value == null)
- {
- throw new ArgumentNullException(nameof(value));
- }
-
- if (startIndex < 0 || startIndex > value.Length - bytesRequired)
- {
- throw new ArgumentOutOfRangeException(nameof(startIndex));
- }
- }
-
- ///
- /// Checks the arguments for validity before calling FromBytes
- /// (which can therefore assume the arguments are valid).
- ///
- /// The bytes to convert after checking
- /// The index of the first byte to convert
- /// The number of bytes to convert
- /// The
- private long CheckedFromBytes(byte[] value, int startIndex, int bytesToConvert)
- {
- CheckByteArgument(value, startIndex, bytesToConvert);
- return this.FromBytes(value, startIndex, bytesToConvert);
- }
- #endregion
-
- #region ToString conversions
///
/// Returns a String converted from the elements of a byte array.
@@ -336,406 +101,29 @@ namespace ImageSharp.IO
{
return BitConverter.ToString(value, startIndex, length);
}
- #endregion
-
- #region Decimal conversions
///
- /// Returns a decimal value converted from sixteen bytes
- /// at a specified position in a byte array.
- ///
- /// An array of bytes.
- /// The starting position within value.
- /// A decimal formed by sixteen bytes beginning at startIndex.
- public decimal ToDecimal(byte[] value, int startIndex)
- {
- // HACK: This always assumes four parts, each in their own endianness,
- // starting with the first part at the start of the byte array.
- // On the other hand, there's no real format specified...
- int[] parts = new int[4];
- for (int i = 0; i < 4; i++)
- {
- parts[i] = this.ToInt32(value, startIndex + (i * 4));
- }
-
- return new decimal(parts);
- }
-
- ///
- /// Returns the specified decimal value as an array of bytes.
- ///
- /// The number to convert.
- /// An array of bytes with length 16.
- public byte[] GetBytes(decimal value)
- {
- byte[] bytes = new byte[16];
- int[] parts = decimal.GetBits(value);
- for (int i = 0; i < 4; i++)
- {
- this.CopyBytesImpl(parts[i], 4, bytes, i * 4);
- }
-
- return bytes;
- }
-
- ///
- /// Copies the specified decimal value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// A character to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(decimal value, byte[] buffer, int index)
- {
- int[] parts = decimal.GetBits(value);
- for (int i = 0; i < 4; i++)
- {
- this.CopyBytesImpl(parts[i], 4, buffer, (i * 4) + index);
- }
- }
- #endregion
-
- #region GetBytes conversions
-
- ///
- /// Returns an array with the given number of bytes formed
- /// from the least significant bytes of the specified value.
- /// This is used to implement the other GetBytes methods.
- ///
- /// The value to get bytes for
- /// The number of significant bytes to return
- ///
- /// The .
- ///
- private byte[] GetBytes(long value, int bytes)
- {
- byte[] buffer = new byte[bytes];
- this.CopyBytes(value, bytes, buffer, 0);
- return buffer;
- }
-
- ///
- /// Returns the specified Boolean value as an array of bytes.
- ///
- /// A Boolean value.
- /// An array of bytes with length 1.
- ///
- /// The .
- ///
- public byte[] GetBytes(bool value)
- {
- return BitConverter.GetBytes(value);
- }
-
- ///
- /// Returns the specified Unicode character value as an array of bytes.
- ///
- /// A character to convert.
- /// An array of bytes with length 2.
- ///
- /// The .
- ///
- public byte[] GetBytes(char value)
- {
- return this.GetBytes(value, 2);
- }
-
- ///
- /// Returns the specified double-precision floating point value as an array of bytes.
- ///
- /// The number to convert.
- /// An array of bytes with length 8.
- public byte[] GetBytes(double value)
- {
- return this.GetBytes(this.DoubleToInt64Bits(value), 8);
- }
-
- ///
- /// Returns the specified 16-bit signed integer value as an array of bytes.
- ///
- /// The number to convert.
- /// An array of bytes with length 2.
- public byte[] GetBytes(short value)
- {
- return this.GetBytes(value, 2);
- }
-
- ///
- /// Returns the specified 32-bit signed integer value as an array of bytes.
- ///
- /// The number to convert.
- /// An array of bytes with length 4.
- public byte[] GetBytes(int value)
- {
- return this.GetBytes(value, 4);
- }
-
- ///
- /// Returns the specified 64-bit signed integer value as an array of bytes.
- ///
- /// The number to convert.
- /// An array of bytes with length 8.
- public byte[] GetBytes(long value)
- {
- return this.GetBytes(value, 8);
- }
-
- ///
- /// Returns the specified single-precision floating point value as an array of bytes.
- ///
- /// The number to convert.
- /// An array of bytes with length 4.
- public byte[] GetBytes(float value)
- {
- return this.GetBytes(this.SingleToInt32Bits(value), 4);
- }
-
- ///
- /// Returns the specified 16-bit unsigned integer value as an array of bytes.
- ///
- /// The number to convert.
- /// An array of bytes with length 2.
- public byte[] GetBytes(ushort value)
- {
- return this.GetBytes(value, 2);
- }
-
- ///
- /// Returns the specified 32-bit unsigned integer value as an array of bytes.
- ///
- /// The number to convert.
- /// An array of bytes with length 4.
- public byte[] GetBytes(uint value)
- {
- return this.GetBytes(value, 4);
- }
-
- ///
- /// Returns the specified 64-bit unsigned integer value as an array of bytes.
- ///
- /// The number to convert.
- /// An array of bytes with length 8.
- public byte[] GetBytes(ulong value)
- {
- return this.GetBytes(unchecked((long)value), 8);
- }
-
- #endregion
-
- #region CopyBytes conversions
-
- ///
- /// Copies the given number of bytes from the least-specific
- /// end of the specified value into the specified byte array, beginning
- /// at the specified index.
- /// This is used to implement the other CopyBytes methods.
- ///
- /// The value to copy bytes for
- /// The number of significant bytes to copy
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- private void CopyBytes(long value, int bytes, byte[] buffer, int index)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer), "Byte array must not be null");
- }
-
- if (buffer.Length < index + bytes)
- {
- throw new ArgumentOutOfRangeException(nameof(buffer), "Buffer not big enough for value");
- }
-
- this.CopyBytesImpl(value, bytes, buffer, index);
- }
-
- ///
- /// Copies the given number of bytes from the least-specific
- /// end of the specified value into the specified byte array, beginning
- /// at the specified index.
- /// This must be implemented in concrete derived classes, but the implementation
- /// may assume that the value will fit into the buffer.
- ///
- /// The value to copy bytes for
- /// The number of significant bytes to copy
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- protected internal abstract void CopyBytesImpl(long value, int bytes, byte[] buffer, int index);
-
- ///
- /// Copies the specified Boolean value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// A Boolean value.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(bool value, byte[] buffer, int index)
- {
- this.CopyBytes(value ? 1 : 0, 1, buffer, index);
- }
-
- ///
- /// Copies the specified Unicode character value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// A character to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(char value, byte[] buffer, int index)
- {
- this.CopyBytes(value, 2, buffer, index);
- }
-
- ///
- /// Copies the specified double-precision floating point value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// The number to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(double value, byte[] buffer, int index)
- {
- this.CopyBytes(this.DoubleToInt64Bits(value), 8, buffer, index);
- }
-
- ///
- /// Copies the specified 16-bit signed integer value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// The number to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(short value, byte[] buffer, int index)
- {
- this.CopyBytes(value, 2, buffer, index);
- }
-
- ///
- /// Copies the specified 32-bit signed integer value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// The number to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(int value, byte[] buffer, int index)
- {
- this.CopyBytes(value, 4, buffer, index);
- }
-
- ///
- /// Copies the specified 64-bit signed integer value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// The number to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(long value, byte[] buffer, int index)
- {
- this.CopyBytes(value, 8, buffer, index);
- }
-
- ///
- /// Copies the specified single-precision floating point value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// The number to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(float value, byte[] buffer, int index)
- {
- this.CopyBytes(this.SingleToInt32Bits(value), 4, buffer, index);
- }
-
- ///
- /// Copies the specified 16-bit unsigned integer value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// The number to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(ushort value, byte[] buffer, int index)
- {
- this.CopyBytes(value, 2, buffer, index);
- }
-
- ///
- /// Copies the specified 32-bit unsigned integer value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// The number to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(uint value, byte[] buffer, int index)
- {
- this.CopyBytes(value, 4, buffer, index);
- }
-
- ///
- /// Copies the specified 64-bit unsigned integer value into the specified byte array,
- /// beginning at the specified index.
- ///
- /// The number to convert.
- /// The byte array to copy the bytes into
- /// The first index into the array to copy the bytes into
- public void CopyBytes(ulong value, byte[] buffer, int index)
- {
- this.CopyBytes(unchecked((long)value), 8, buffer, index);
- }
-
- #endregion
-
- #region Private struct used for Single/Int32 conversions
-
- ///
- /// Union used solely for the equivalent of DoubleToInt64Bits and vice versa.
+ /// Checks the given argument for validity.
///
- [StructLayout(LayoutKind.Explicit)]
- private struct Int32SingleUnion
+ /// The byte array passed in
+ /// The start index passed in
+ /// The number of bytes required
+ /// value is a null reference
+ ///
+ /// startIndex is less than zero or greater than the length of value minus bytesRequired.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected static void CheckByteArgument(byte[] value, int startIndex, int bytesRequired)
{
- ///
- /// Int32 version of the value.
- ///
- [FieldOffset(0)]
- private readonly int i;
-
- ///
- /// Single version of the value.
- ///
- [FieldOffset(0)]
- private readonly float f;
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The integer value of the new instance.
- internal Int32SingleUnion(int i)
+ if (value == null)
{
- this.f = 0; // Just to keep the compiler happy
- this.i = i;
+ throw new ArgumentNullException(nameof(value));
}
- ///
- /// Initializes a new instance of the struct.
- ///
- ///
- /// The floating point value of the new instance.
- ///
- internal Int32SingleUnion(float f)
+ if (startIndex < 0 || startIndex > value.Length - bytesRequired)
{
- this.i = 0; // Just to keep the compiler happy
- this.f = f;
+ throw new ArgumentOutOfRangeException(nameof(startIndex));
}
-
- ///
- /// Gets the value of the instance as an integer.
- ///
- internal int AsInt32 => this.i;
-
- ///
- /// Gets the value of the instance as a floating point number.
- ///
- internal float AsSingle => this.f;
}
- #endregion
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/IO/IFileSystem.cs b/src/ImageSharp/IO/IFileSystem.cs
new file mode 100644
index 0000000000..ee1ef84d7b
--- /dev/null
+++ b/src/ImageSharp/IO/IFileSystem.cs
@@ -0,0 +1,31 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.IO
+{
+ using System.IO;
+
+ #if !NETSTANDARD1_1
+ ///
+ /// A simple interface representing the filesystem.
+ ///
+ public interface IFileSystem
+ {
+ ///
+ /// Returns a readable stream as defined by the path.
+ ///
+ /// Path to the file to open.
+ /// A stream representing the file to open.
+ Stream OpenRead(string path);
+
+ ///
+ /// Creates or opens a file and returns it as a writeable stream as defined by the path.
+ ///
+ /// Path to the file to open.
+ /// A stream representing the file to open.
+ Stream Create(string path);
+ }
+#endif
+}
diff --git a/src/ImageSharp/IO/LittleEndianBitConverter.cs b/src/ImageSharp/IO/LittleEndianBitConverter.cs
index 63ebe18a33..81ed8d55c2 100644
--- a/src/ImageSharp/IO/LittleEndianBitConverter.cs
+++ b/src/ImageSharp/IO/LittleEndianBitConverter.cs
@@ -6,42 +6,78 @@
namespace ImageSharp.IO
{
///
- /// Implementation of EndianBitConverter which converts to/from little-endian
- /// byte arrays.
- ///
- /// Adapted from Miscellaneous Utility Library
- /// This product includes software developed by Jon Skeet and Marc Gravell. Contact , or see
- /// .
- ///
+ /// Implementation of EndianBitConverter which converts to/from little-endian byte arrays.
///
internal sealed class LittleEndianBitConverter : EndianBitConverter
{
///
- public override Endianness Endianness => Endianness.LittleEndian;
+ public override Endianness Endianness
+ {
+ get { return Endianness.LittleEndian; }
+ }
+
+ ///
+ public override bool IsLittleEndian
+ {
+ get { return true; }
+ }
+
+ ///
+ public override void CopyBytes(short value, byte[] buffer, int index)
+ {
+ CheckByteArgument(buffer, index, 2);
+
+ buffer[index + 1] = (byte)(value >> 8);
+ buffer[index] = (byte)value;
+ }
///
- public override bool IsLittleEndian() => true;
+ public override void CopyBytes(int value, byte[] buffer, int index)
+ {
+ CheckByteArgument(buffer, index, 4);
+
+ buffer[index + 3] = (byte)(value >> 24);
+ buffer[index + 2] = (byte)(value >> 16);
+ buffer[index + 1] = (byte)(value >> 8);
+ buffer[index] = (byte)value;
+ }
///
- protected internal override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
+ public override void CopyBytes(long value, byte[] buffer, int index)
{
- for (int i = 0; i < bytes; i++)
- {
- buffer[i + index] = unchecked((byte)(value & 0xff));
- value = value >> 8;
- }
+ CheckByteArgument(buffer, index, 8);
+
+ buffer[index + 7] = (byte)(value >> 56);
+ buffer[index + 6] = (byte)(value >> 48);
+ buffer[index + 5] = (byte)(value >> 40);
+ buffer[index + 4] = (byte)(value >> 32);
+ buffer[index + 3] = (byte)(value >> 24);
+ buffer[index + 2] = (byte)(value >> 16);
+ buffer[index + 1] = (byte)(value >> 8);
+ buffer[index] = (byte)value;
}
///
- protected internal override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
+ public unsafe override short ToInt16(byte[] value, int startIndex)
{
- long ret = 0;
- for (int i = 0; i < bytesToConvert; i++)
- {
- ret = unchecked((ret << 8) | buffer[startIndex + bytesToConvert - 1 - i]);
- }
+ CheckByteArgument(value, startIndex, 2);
+ return (short)((value[startIndex + 1] << 8) | value[startIndex]);
+ }
- return ret;
+ ///
+ public unsafe override int ToInt32(byte[] value, int startIndex)
+ {
+ CheckByteArgument(value, startIndex, 4);
+ return (value[startIndex + 3] << 24) | (value[startIndex + 2] << 16) | (value[startIndex + 1] << 8) | value[startIndex];
+ }
+
+ ///
+ public unsafe override long ToInt64(byte[] value, int startIndex)
+ {
+ CheckByteArgument(value, startIndex, 8);
+ long p1 = (value[startIndex + 7] << 24) | (value[startIndex + 6] << 16) | (value[startIndex + 5] << 8) | value[startIndex + 4];
+ long p2 = (value[startIndex + 3] << 24) | (value[startIndex + 2] << 16) | (value[startIndex + 1] << 8) | value[startIndex];
+ return p2 | (p1 << 32);
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/IO/LocalFileSystem.cs b/src/ImageSharp/IO/LocalFileSystem.cs
new file mode 100644
index 0000000000..02a9914ead
--- /dev/null
+++ b/src/ImageSharp/IO/LocalFileSystem.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.IO
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text;
+
+ #if !NETSTANDARD1_1
+ ///
+ /// A wrapper around the local File apis.
+ ///
+ public class LocalFileSystem : IFileSystem
+ {
+ ///
+ public Stream OpenRead(string path)
+ {
+ return File.OpenRead(path);
+ }
+
+ ///
+ public Stream Create(string path)
+ {
+ return File.Create(path);
+ }
+ }
+#endif
+}
diff --git a/src/ImageSharp/Image.Create.cs b/src/ImageSharp/Image.Create.cs
new file mode 100644
index 0000000000..fcecefd7b7
--- /dev/null
+++ b/src/ImageSharp/Image.Create.cs
@@ -0,0 +1,66 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.Diagnostics;
+ using System.IO;
+
+ using Formats;
+
+ ///
+ /// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
+ /// packed into a single unsigned integer value.
+ ///
+ public sealed partial class Image
+ {
+ ///
+ /// Create a new instance of the class
+ /// with the height and the width of the image.
+ ///
+ /// The pixel format.
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
+ /// The images matadata to preload.
+ ///
+ /// The configuration providing initialization code which allows extending the library.
+ ///
+ ///
+ /// A new unless is in which case it returns
+ ///
+ internal static Image Create(int width, int height, ImageMetaData metadata, Configuration configuration)
+ where TColor : struct, IPixel
+ {
+ if (typeof(TColor) == typeof(Color))
+ {
+ return new Image(width, height, metadata, configuration) as Image;
+ }
+ else
+ {
+ return new Image(width, height, metadata, configuration);
+ }
+ }
+
+ ///
+ /// Create a new instance of the class
+ /// with the height and the width of the image.
+ ///
+ /// The pixel format.
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
+ ///
+ /// The configuration providing initialization code which allows extending the library.
+ ///
+ ///
+ /// A new unless is in which case it returns
+ ///
+ internal static Image Create(int width, int height, Configuration configuration)
+ where TColor : struct, IPixel
+ {
+ return Image.Create(width, height, null, configuration);
+ }
+ }
+}
diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs
new file mode 100644
index 0000000000..c1c1371220
--- /dev/null
+++ b/src/ImageSharp/Image.Decode.cs
@@ -0,0 +1,75 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System.Buffers;
+ using System.IO;
+ using System.Linq;
+ using Formats;
+
+ ///
+ /// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
+ /// packed into a single unsigned integer value.
+ ///
+ public sealed partial class Image
+ {
+ ///
+ /// By reading the header on the provided stream this calculates the images format.
+ ///
+ /// 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)
+ {
+ // This is probably a candidate for making into a public API in the future!
+ int maxHeaderSize = config.MaxHeaderSize;
+ if (maxHeaderSize <= 0)
+ {
+ return null;
+ }
+
+ IImageFormat format;
+ byte[] header = ArrayPool.Shared.Rent(maxHeaderSize);
+ try
+ {
+ long startPosition = stream.Position;
+ stream.Read(header, 0, maxHeaderSize);
+ stream.Position = startPosition;
+ format = config.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header));
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(header);
+ }
+
+ return format;
+ }
+
+ ///
+ /// Decodes the image stream to the current image.
+ ///
+ /// The pixel format.
+ /// The stream.
+ /// The options for the decoder.
+ /// the configuration.
+ ///
+ /// The decoded image
+ ///
+ private static Image Decode(Stream stream, IDecoderOptions options, Configuration config)
+ where TColor : struct, IPixel
+ {
+ IImageFormat format = DiscoverFormat(stream, config);
+ if (format == null)
+ {
+ return null;
+ }
+
+ Image img = format.Decoder.Decode(config, stream, options);
+ img.CurrentImageFormat = format;
+ return img;
+ }
+ }
+}
diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs
new file mode 100644
index 0000000000..b2f9854f22
--- /dev/null
+++ b/src/ImageSharp/Image.FromBytes.cs
@@ -0,0 +1,212 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.IO;
+ using Formats;
+
+ ///
+ /// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
+ /// packed into a single unsigned integer value.
+ ///
+ public sealed partial class Image
+ {
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The byte array containing image data.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data)
+ {
+ return Load(null, data, null);
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The byte array containing image data.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IDecoderOptions options)
+ {
+ return Load(null, data, options);
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The config for the decoder.
+ /// The byte array containing image data.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, byte[] data)
+ {
+ return Load(config, data, null);
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The byte array containing image data.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IImageDecoder decoder)
+ {
+ return Load(data, decoder, null);
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The configuration options.
+ /// The byte array containing image data.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, byte[] data, IDecoderOptions options)
+ {
+ using (MemoryStream ms = new MemoryStream(data))
+ {
+ return Load(config, ms, options);
+ }
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The byte array containing image data.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options)
+ {
+ using (MemoryStream ms = new MemoryStream(data))
+ {
+ return Load(ms, decoder, options);
+ }
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The pixel format.
+ /// The byte array containing image data.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data)
+ where TColor : struct, IPixel
+ {
+ return Load(null, data, null);
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The pixel format.
+ /// The byte array containing image data.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ return Load(null, data, options);
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The pixel format.
+ /// The config for the decoder.
+ /// The byte array containing image data.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, byte[] data)
+ where TColor : struct, IPixel
+ {
+ return Load(config, data, null);
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The pixel format.
+ /// The byte array containing image data.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IImageDecoder decoder)
+ where TColor : struct, IPixel
+ {
+ return Load(data, decoder, null);
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The pixel format.
+ /// The configuration options.
+ /// The byte array containing image data.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, byte[] data, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ using (MemoryStream ms = new MemoryStream(data))
+ {
+ return Load(config, ms, options);
+ }
+ }
+
+ ///
+ /// Loads the image from the given byte array.
+ ///
+ /// The pixel format.
+ /// The byte array containing image data.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ using (MemoryStream ms = new MemoryStream(data))
+ {
+ return Load(ms, decoder, options);
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs
new file mode 100644
index 0000000000..40cdfe3eff
--- /dev/null
+++ b/src/ImageSharp/Image.FromFile.cs
@@ -0,0 +1,214 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+#if !NETSTANDARD1_1
+ using System;
+ using System.IO;
+ using Formats;
+
+ ///
+ /// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
+ /// packed into a single unsigned integer value.
+ ///
+ public sealed partial class Image
+ {
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The file path to the image.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path)
+ {
+ return Load(null, path, null);
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The file path to the image.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path, IDecoderOptions options)
+ {
+ return Load(null, path, options);
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The config for the decoder.
+ /// The file path to the image.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, string path)
+ {
+ return Load(config, path, null);
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The file path to the image.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path, IImageDecoder decoder)
+ {
+ return Load(path, decoder, null);
+ }
+
+ ///
+ /// Loads the image 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.
+ ///
+ /// The image
+ public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options)
+ {
+ return new Image(Load(path, decoder, options));
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The configuration options.
+ /// The file path to the image.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, string path, IDecoderOptions options)
+ {
+ config = config ?? Configuration.Default;
+ using (Stream s = config.FileSystem.OpenRead(path))
+ {
+ return Load(config, s, options);
+ }
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The pixel format.
+ /// The file path to the image.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path)
+ where TColor : struct, IPixel
+ {
+ return Load(null, path, null);
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The pixel format.
+ /// The file path to the image.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ return Load(null, path, options);
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The pixel format.
+ /// The config for the decoder.
+ /// The file path to the image.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, string path)
+ where TColor : struct, IPixel
+ {
+ return Load(config, path, null);
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The pixel format.
+ /// The file path to the image.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path, IImageDecoder decoder)
+ where TColor : struct, IPixel
+ {
+ return Load(path, decoder, null);
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The pixel format.
+ /// The configuration options.
+ /// The file path to the image.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, string path, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ config = config ?? Configuration.Default;
+ using (Stream s = config.FileSystem.OpenRead(path))
+ {
+ return Load(config, s, options);
+ }
+ }
+
+ ///
+ /// Loads the image from the given file.
+ ///
+ /// The pixel format.
+ /// The file path to the image.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ Configuration config = Configuration.Default;
+ using (Stream s = config.FileSystem.OpenRead(path))
+ {
+ return Load(s, decoder, options);
+ }
+ }
+ }
+#endif
+}
diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs
new file mode 100644
index 0000000000..41ac7757e7
--- /dev/null
+++ b/src/ImageSharp/Image.FromStream.cs
@@ -0,0 +1,246 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.IO;
+ using System.Text;
+ using Formats;
+
+ ///
+ /// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
+ /// packed into a single unsigned integer value.
+ ///
+ public sealed partial class Image
+ {
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The stream containing image information.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream)
+ {
+ return Load(null, stream, null);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The stream containing image information.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IDecoderOptions options)
+ {
+ return Load(null, stream, options);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The config for the decoder.
+ /// The stream containing image information.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, Stream stream)
+ {
+ return Load(config, stream, null);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The stream containing image information.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IImageDecoder decoder)
+ {
+ return Load(stream, decoder, null);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The configuration options.
+ /// The stream containing image information.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, Stream stream, IDecoderOptions options)
+ {
+ Image image = Load(config, stream, options);
+
+ return image as Image ?? new Image(image);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The stream containing image information.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options)
+ {
+ Image image = new Image(Load(stream, decoder, options));
+
+ return image as Image ?? new Image(image);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The pixel format.
+ /// The stream containing image information.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream)
+ where TColor : struct, IPixel
+ {
+ return Load(null, stream, null);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The pixel format.
+ /// The stream containing image information.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ return Load(null, stream, options);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The pixel format.
+ /// The config for the decoder.
+ /// The stream containing image information.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, Stream stream)
+ where TColor : struct, IPixel
+ {
+ return Load(config, stream, null);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The pixel format.
+ /// The stream containing image information.
+ /// The decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IImageDecoder decoder)
+ where TColor : struct, IPixel
+ {
+ return Load(stream, decoder, null);
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The pixel format.
+ /// The stream containing image information.
+ /// The decoder.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ return WithSeekableStream(stream, s => decoder.Decode(Configuration.Default, s, options));
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The pixel format.
+ /// The configuration options.
+ /// The stream containing image information.
+ /// The options for the decoder.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ /// The image
+ public static Image Load(Configuration config, Stream stream, IDecoderOptions options)
+ where TColor : struct, IPixel
+ {
+ config = config ?? Configuration.Default;
+
+ Image img = WithSeekableStream(stream, s => Decode(stream, options, config));
+
+ if (img != null)
+ {
+ return img;
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.AppendLine("Image cannot be loaded. Available formats:");
+
+ foreach (IImageFormat format in config.ImageFormats)
+ {
+ stringBuilder.AppendLine("-" + format);
+ }
+
+ throw new NotSupportedException(stringBuilder.ToString());
+ }
+
+ private static T WithSeekableStream(Stream stream, Func action)
+ {
+ if (!stream.CanRead)
+ {
+ throw new NotSupportedException("Cannot read from the stream.");
+ }
+
+ if (stream.CanSeek)
+ {
+ return action(stream);
+ }
+ else
+ {
+ // We want to be able to load images from things like HttpContext.Request.Body
+ using (MemoryStream ms = new MemoryStream())
+ {
+ stream.CopyTo(ms);
+ ms.Position = 0;
+
+ return action(stream);
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs
index 8bfd8ee1a3..00688afc96 100644
--- a/src/ImageSharp/Image.cs
+++ b/src/ImageSharp/Image.cs
@@ -5,6 +5,7 @@
namespace ImageSharp
{
+ using System;
using System.Diagnostics;
using System.IO;
@@ -15,7 +16,7 @@ namespace ImageSharp
/// packed into a single unsigned integer value.
///
[DebuggerDisplay("Image: {Width}x{Height}")]
- public sealed class Image : Image
+ public sealed partial class Image : Image
{
///
/// Initializes a new instance of the class
@@ -26,201 +27,45 @@ namespace ImageSharp
///
/// The configuration providing initialization code which allows extending the library.
///
- public Image(int width, int height, Configuration configuration = null)
+ public Image(int width, int height, Configuration configuration)
: base(width, height, configuration)
{
}
///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The stream containing image information.
- ///
- /// Thrown if the is null.
- public Image(Stream stream)
- : base(stream, null, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The stream containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
- /// Thrown if the is null.
- public Image(Stream stream, IDecoderOptions options)
- : base(stream, options, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The stream containing image information.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(Stream stream, Configuration configuration)
- : base(stream, null, configuration)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The stream containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(Stream stream, IDecoderOptions options, Configuration configuration)
- : base(stream, options, configuration)
- {
- }
-
-#if !NETSTANDARD1_1
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// A file path to read image information.
- ///
- /// Thrown if the is null.
- public Image(string filePath)
- : base(filePath, null, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// A file path to read image information.
- ///
- ///
- /// The options for the decoder.
- ///
- /// Thrown if the is null.
- public Image(string filePath, IDecoderOptions options)
- : base(filePath, options, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// A file path to read image information.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(string filePath, Configuration configuration)
- : base(filePath, null, configuration)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// A file path to read image information.
- ///
- ///
- /// The options for the decoder.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(string filePath, IDecoderOptions options, Configuration configuration)
- : base(filePath, options, configuration)
- {
- }
-#endif
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The byte array containing image information.
- ///
- /// Thrown if the is null.
- public Image(byte[] bytes)
- : base(bytes, null, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class
+ /// with the height and the width of the image.
///
- ///
- /// The byte array containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
- /// Thrown if the is null.
- public Image(byte[] bytes, IDecoderOptions options)
- : base(bytes, options, null)
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
+ public Image(int width, int height)
+ : this(width, height, null)
{
}
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class
+ /// by making a copy from another image.
///
- ///
- /// The byte array containing image information.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(byte[] bytes, Configuration configuration)
- : base(bytes, null, configuration)
+ /// The other image, where the clone should be made from.
+ /// is null.
+ public Image(Image other)
+ : base(other)
{
}
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class
+ /// with the height and the width of the image.
///
- ///
- /// The byte array containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
+ /// The metadata.
///
/// The configuration providing initialization code which allows extending the library.
///
- /// Thrown if the is null.
- public Image(byte[] bytes, IDecoderOptions options, Configuration configuration)
- : base(bytes, options, configuration)
- {
- }
-
- ///
- /// Initializes a new instance of the class
- /// by making a copy from another image.
- ///
- /// The other image, where the clone should be made from.
- /// is null.
- public Image(Image other)
- : base(other)
+ internal Image(int width, int height, ImageMetaData metadata, Configuration configuration)
+ : base(width, height, metadata, configuration)
{
}
}
diff --git a/src/ImageSharp/Image/IImageBase.cs b/src/ImageSharp/Image/IImageBase.cs
index 707fea235d..393d83077a 100644
--- a/src/ImageSharp/Image/IImageBase.cs
+++ b/src/ImageSharp/Image/IImageBase.cs
@@ -15,16 +15,6 @@ namespace ImageSharp
///
Rectangle Bounds { get; }
- ///
- /// Gets or sets the maximum allowable width in pixels.
- ///
- int MaxWidth { get; set; }
-
- ///
- /// Gets or sets the maximum allowable height in pixels.
- ///
- int MaxHeight { get; set; }
-
///
/// Gets the width in pixels.
///
diff --git a/src/ImageSharp/Image/IImageBase{TColor}.cs b/src/ImageSharp/Image/IImageBase{TColor}.cs
index e894fba4a8..14bdffc672 100644
--- a/src/ImageSharp/Image/IImageBase{TColor}.cs
+++ b/src/ImageSharp/Image/IImageBase{TColor}.cs
@@ -21,16 +21,6 @@ namespace ImageSharp
///
TColor[] Pixels { get; }
- ///
- /// Sets the size of the pixel array of the image to the given width and height.
- ///
- /// The new width of the image. Must be greater than zero.
- /// The new height of the image. Must be greater than zero.
- ///
- /// Thrown if either or are less than or equal to 0.
- ///
- void InitPixels(int width, int height);
-
///
/// Locks the image providing access to the pixels.
///
diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs
index 878ba09b39..cfce7184b6 100644
--- a/src/ImageSharp/Image/ImageBase{TColor}.cs
+++ b/src/ImageSharp/Image/ImageBase{TColor}.cs
@@ -18,6 +18,16 @@ namespace ImageSharp
public abstract class ImageBase : IImageBase
where TColor : struct, IPixel
{
+ ///
+ /// Gets or sets the maximum allowable width in pixels.
+ ///
+ public const int MaxWidth = int.MaxValue;
+
+ ///
+ /// Gets or sets the maximum allowable height in pixels.
+ ///
+ public const int MaxHeight = int.MaxValue;
+
///
/// The image pixels
///
@@ -40,7 +50,7 @@ namespace ImageSharp
///
/// The configuration providing initialization code which allows extending the library.
///
- protected ImageBase(Configuration configuration = null)
+ protected ImageBase(Configuration configuration)
{
this.Configuration = configuration ?? Configuration.Default;
}
@@ -56,10 +66,15 @@ namespace ImageSharp
///
/// Thrown if either or are less than or equal to 0.
///
- protected ImageBase(int width, int height, Configuration configuration = null)
+ protected ImageBase(int width, int height, Configuration configuration)
+ : this(configuration)
{
- this.Configuration = configuration ?? Configuration.Default;
- this.InitPixels(width, height);
+ Guard.MustBeGreaterThan(width, 0, nameof(width));
+ Guard.MustBeGreaterThan(height, 0, nameof(height));
+
+ this.Width = width;
+ this.Height = height;
+ this.RentPixels();
this.ClearPixels();
}
@@ -73,6 +88,7 @@ namespace ImageSharp
/// Thrown if the given is null.
///
protected ImageBase(ImageBase other)
+ : this(other.Configuration)
{
Guard.NotNull(other, nameof(other), "Other image cannot be null.");
@@ -90,12 +106,6 @@ namespace ImageSharp
}
}
- ///
- public int MaxWidth { get; set; } = int.MaxValue;
-
- ///
- public int MaxHeight { get; set; } = int.MaxValue;
-
///
public TColor[] Pixels => this.pixelBuffer;
@@ -139,17 +149,6 @@ namespace ImageSharp
GC.SuppressFinalize(this);
}
- ///
- public void InitPixels(int width, int height)
- {
- Guard.MustBeGreaterThan(width, 0, nameof(width));
- Guard.MustBeGreaterThan(height, 0, nameof(height));
-
- this.Width = width;
- this.Height = height;
- this.RentPixels();
- }
-
///
public PixelAccessor Lock()
{
diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs
index 27dee54342..d063c3ff16 100644
--- a/src/ImageSharp/Image/Image{TColor}.cs
+++ b/src/ImageSharp/Image/Image{TColor}.cs
@@ -35,210 +35,20 @@ namespace ImageSharp
///
/// The configuration providing initialization code which allows extending the library.
///
- public Image(int width, int height, Configuration configuration = null)
- : base(width, height, configuration)
- {
- if (!this.Configuration.ImageFormats.Any())
- {
- throw new InvalidOperationException("No image formats have been configured.");
- }
-
- this.CurrentImageFormat = this.Configuration.ImageFormats.First();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The stream containing image information.
- ///
- /// Thrown if the is null.
- public Image(Stream stream)
- : this(stream, null, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The stream containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
- /// Thrown if the is null.
- public Image(Stream stream, IDecoderOptions options)
- : this(stream, options, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The stream containing image information.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(Stream stream, Configuration configuration)
- : this(stream, null, configuration)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The stream containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(Stream stream, IDecoderOptions options, Configuration configuration)
- : base(configuration)
- {
- Guard.NotNull(stream, nameof(stream));
- this.Load(stream, options);
- }
-
-#if !NETSTANDARD1_1
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The file containing image information.
- ///
- /// Thrown if the is null.
- public Image(string filePath)
- : this(filePath, null, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The file containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
- /// Thrown if the is null.
- public Image(string filePath, IDecoderOptions options)
- : this(filePath, options, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The file containing image information.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(string filePath, Configuration configuration)
- : this(filePath, null, configuration)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The file containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(string filePath, IDecoderOptions options, Configuration configuration)
- : base(configuration)
- {
- Guard.NotNull(filePath, nameof(filePath));
- using (var fs = File.OpenRead(filePath))
- {
- this.Load(fs, options);
- }
- }
-#endif
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The byte array containing image information.
- ///
- /// Thrown if the is null.
- public Image(byte[] bytes)
- : this(bytes, null, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The byte array containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
- /// Thrown if the is null.
- public Image(byte[] bytes, IDecoderOptions options)
- : this(bytes, options, null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The byte array containing image information.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(byte[] bytes, Configuration configuration)
- : this(bytes, null, configuration)
+ public Image(int width, int height, Configuration configuration)
+ : this(width, height, new ImageMetaData(), configuration)
{
}
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class
+ /// with the height and the width of the image.
///
- ///
- /// The byte array containing image information.
- ///
- ///
- /// The options for the decoder.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// Thrown if the is null.
- public Image(byte[] bytes, IDecoderOptions options, Configuration configuration)
- : base(configuration)
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
+ public Image(int width, int height)
+ : this(width, height, null)
{
- Guard.NotNull(bytes, nameof(bytes));
-
- using (MemoryStream stream = new MemoryStream(bytes, false))
- {
- this.Load(stream, options);
- }
}
///
@@ -270,13 +80,35 @@ namespace ImageSharp
public Image(ImageBase other)
: base(other)
{
- this.CopyProperties(other);
+ this.MetaData = new ImageMetaData();
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with the height and the width of the image.
+ ///
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
+ /// The images metadata.
+ ///
+ /// The configuration providing initialization code which allows extending the library.
+ ///
+ internal Image(int width, int height, ImageMetaData metadata, Configuration configuration)
+ : base(width, height, configuration)
+ {
+ 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();
}
///
/// Gets the meta data of the image.
///
- public ImageMetaData MetaData { get; private set; } = new ImageMetaData();
+ public ImageMetaData MetaData { get; private set; }
///
/// Gets the width of the image in inches. It is calculated as the width of the image
@@ -348,9 +180,7 @@ namespace ImageSharp
/// The
public Image Save(Stream stream, IEncoderOptions options)
{
- Guard.NotNull(stream, nameof(stream));
- this.CurrentImageFormat.Encoder.Encode(this, stream, options);
- return this;
+ return this.Save(stream, this.CurrentImageFormat?.Encoder, options);
}
///
@@ -373,10 +203,9 @@ namespace ImageSharp
/// The
public Image Save(Stream stream, IImageFormat format, IEncoderOptions options)
{
- Guard.NotNull(stream, nameof(stream));
Guard.NotNull(format, nameof(format));
- format.Encoder.Encode(this, stream, options);
- return this;
+
+ return this.Save(stream, format.Encoder, options);
}
///
@@ -407,13 +236,8 @@ namespace ImageSharp
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(encoder, nameof(encoder));
- encoder.Encode(this, stream, options);
- // Reset to the start of the stream.
- if (stream.CanSeek)
- {
- stream.Position = 0;
- }
+ encoder.Encode(this, stream, options);
return this;
}
@@ -446,7 +270,7 @@ namespace ImageSharp
throw new InvalidOperationException($"No image formats have been registered for the file extension '{ext}'.");
}
- return this.Save(filePath, format);
+ return this.Save(filePath, format, options);
}
///
@@ -472,10 +296,7 @@ namespace ImageSharp
public Image Save(string filePath, IImageFormat format, IEncoderOptions options)
{
Guard.NotNull(format, nameof(format));
- using (FileStream fs = File.Create(filePath))
- {
- return this.Save(fs, format);
- }
+ return this.Save(filePath, format.Encoder, options);
}
///
@@ -501,9 +322,9 @@ namespace ImageSharp
public Image Save(string filePath, IImageEncoder encoder, IEncoderOptions options)
{
Guard.NotNull(encoder, nameof(encoder));
- using (FileStream fs = File.Create(filePath))
+ using (Stream fs = this.Configuration.FileSystem.Create(filePath))
{
- return this.Save(fs, encoder);
+ return this.Save(fs, encoder, options);
}
}
#endif
@@ -598,103 +419,8 @@ namespace ImageSharp
///
private void CopyProperties(IImage other)
{
- base.CopyProperties(other);
-
this.CurrentImageFormat = other.CurrentImageFormat;
this.MetaData = new ImageMetaData(other.MetaData);
}
-
- ///
- /// Loads the image from the given stream.
- ///
- /// The stream containing image information.
- /// The options for the decoder.
- ///
- /// Thrown if the stream is not readable nor seekable.
- ///
- private void Load(Stream stream, IDecoderOptions options)
- {
- if (!this.Configuration.ImageFormats.Any())
- {
- throw new InvalidOperationException("No image formats have been configured.");
- }
-
- if (!stream.CanRead)
- {
- throw new NotSupportedException("Cannot read from the stream.");
- }
-
- if (stream.CanSeek)
- {
- if (this.Decode(stream, options))
- {
- return;
- }
- }
- else
- {
- // We want to be able to load images from things like HttpContext.Request.Body
- using (MemoryStream ms = new MemoryStream())
- {
- stream.CopyTo(ms);
- ms.Position = 0;
-
- if (this.Decode(ms, options))
- {
- return;
- }
- }
- }
-
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.AppendLine("Image cannot be loaded. Available formats:");
-
- foreach (IImageFormat format in this.Configuration.ImageFormats)
- {
- stringBuilder.AppendLine("-" + format);
- }
-
- throw new NotSupportedException(stringBuilder.ToString());
- }
-
- ///
- /// Decodes the image stream to the current image.
- ///
- /// The stream.
- /// The options for the decoder.
- ///
- /// The .
- ///
- private bool Decode(Stream stream, IDecoderOptions options)
- {
- int maxHeaderSize = this.Configuration.MaxHeaderSize;
- if (maxHeaderSize <= 0)
- {
- return false;
- }
-
- IImageFormat format;
- byte[] header = ArrayPool.Shared.Rent(maxHeaderSize);
- try
- {
- long startPosition = stream.Position;
- stream.Read(header, 0, maxHeaderSize);
- stream.Position = startPosition;
- format = this.Configuration.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header));
- }
- finally
- {
- ArrayPool.Shared.Return(header);
- }
-
- if (format == null)
- {
- return false;
- }
-
- format.Decoder.Decode(this, stream, options);
- this.CurrentImageFormat = format;
- return true;
- }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs
index a106765652..f5393cfb38 100644
--- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs
+++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs
@@ -15,7 +15,7 @@ namespace ImageSharp
/// Provides per-pixel access to generic pixels.
///
/// The pixel format.
- public sealed unsafe class PixelAccessor : IDisposable
+ public sealed unsafe class PixelAccessor : IDisposable, IPinnedImageBuffer
where TColor : struct, IPixel
{
///
@@ -37,7 +37,7 @@ namespace ImageSharp
///
/// The containing the pixel data.
///
- private PinnedBuffer pixelBuffer;
+ private PinnedImageBuffer pixelBuffer;
///
/// Initializes a new instance of the class.
@@ -59,7 +59,7 @@ namespace ImageSharp
/// The width of the image represented by the pixel buffer.
/// The height of the image represented by the pixel buffer.
public PixelAccessor(int width, int height)
- : this(width, height, new PinnedBuffer(width * height))
+ : this(width, height, PinnedImageBuffer.CreateClean(width, height))
{
}
@@ -69,7 +69,7 @@ namespace ImageSharp
/// The width of the image represented by the pixel buffer.
/// The height of the image represented by the pixel buffer.
/// The pixel buffer.
- private PixelAccessor(int width, int height, PinnedBuffer pixels)
+ private PixelAccessor(int width, int height, PinnedImageBuffer pixels)
{
Guard.NotNull(pixels, nameof(pixels));
Guard.MustBeGreaterThan(width, 0, nameof(width));
@@ -123,6 +123,9 @@ namespace ImageSharp
///
public ParallelOptions ParallelOptions { get; }
+ ///
+ BufferSpan IPinnedImageBuffer.Span => this.pixelBuffer;
+
private static BulkPixelOperations Operations => BulkPixelOperations.Instance;
///
@@ -148,6 +151,37 @@ namespace ImageSharp
}
}
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ if (this.isDisposed)
+ {
+ return;
+ }
+
+ // Note disposing is done.
+ this.isDisposed = true;
+
+ this.pixelBuffer.Dispose();
+
+ // This object will be cleaned up by the Dispose method.
+ // Therefore, you should call GC.SuppressFinalize to
+ // take this object off the finalization queue
+ // and prevent finalization code for this object
+ // from executing a second time.
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Resets all the pixels to it's initial value.
+ ///
+ public void Reset()
+ {
+ Unsafe.InitBlock(this.pixelsBase, 0, (uint)(this.RowStride * this.Height));
+ }
+
///
/// Copy an area of pixels to the image.
///
@@ -157,7 +191,7 @@ namespace ImageSharp
///
/// Thrown when an unsupported component order value is passed.
///
- public void CopyFrom(PixelArea area, int targetY, int targetX = 0)
+ internal void CopyFrom(PixelArea area, int targetY, int targetX = 0)
{
this.CheckCoordinates(area, targetX, targetY);
@@ -173,7 +207,7 @@ namespace ImageSharp
///
/// Thrown when an unsupported component order value is passed.
///
- public void CopyTo(PixelArea area, int sourceY, int sourceX = 0)
+ internal void CopyTo(PixelArea area, int sourceY, int sourceX = 0)
{
this.CheckCoordinates(area, sourceX, sourceY);
@@ -190,7 +224,7 @@ namespace ImageSharp
///
/// Thrown when an unsupported component order value is passed.
///
- public void SafeCopyTo(PixelArea area, int sourceY, int sourceX = 0)
+ internal void SafeCopyTo(PixelArea area, int sourceY, int sourceX = 0)
{
int width = Math.Min(area.Width, this.Width - sourceX);
if (width < 1)
@@ -207,48 +241,6 @@ namespace ImageSharp
this.CopyTo(area, sourceX, sourceY, width, height);
}
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- ///
- public void Dispose()
- {
- if (this.isDisposed)
- {
- return;
- }
-
- // Note disposing is done.
- this.isDisposed = true;
-
- this.pixelBuffer.Dispose();
-
- // This object will be cleaned up by the Dispose method.
- // Therefore, you should call GC.SuppressFinalize to
- // take this object off the finalization queue
- // and prevent finalization code for this object
- // from executing a second time.
- GC.SuppressFinalize(this);
- }
-
- ///
- /// Resets all the pixels to it's initial value.
- ///
- public void Reset()
- {
- Unsafe.InitBlock(this.pixelsBase, 0, (uint)(this.RowStride * this.Height));
- }
-
- ///
- /// Gets a to the row 'y' beginning from the pixel at 'x'.
- ///
- /// The x coordinate
- /// The y coordinate
- /// The
- internal BufferPointer GetRowPointer(int x, int y)
- {
- return this.pixelBuffer.Slice((y * this.Width) + x);
- }
-
///
/// Sets the pixel buffer in an unsafe manner. This should not be used unless you know what its doing!!!
///
@@ -288,8 +280,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
- BufferPointer source = area.GetRowPointer(y);
- BufferPointer destination = this.GetRowPointer(targetX, targetY + y);
+ BufferSpan source = area.GetRowSpan(y);
+ BufferSpan destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromZyxBytes(source, destination, width);
}
@@ -308,8 +300,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
- BufferPointer source = area.GetRowPointer(y);
- BufferPointer destination = this.GetRowPointer(targetX, targetY + y);
+ BufferSpan source = area.GetRowSpan(y);
+ BufferSpan destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromZyxwBytes(source, destination, width);
}
@@ -328,8 +320,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
- BufferPointer source = area.GetRowPointer(y);
- BufferPointer destination = this.GetRowPointer(targetX, targetY + y);
+ BufferSpan source = area.GetRowSpan(y);
+ BufferSpan destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromXyzBytes(source, destination, width);
}
@@ -348,8 +340,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
- BufferPointer source = area.GetRowPointer(y);
- BufferPointer destination = this.GetRowPointer(targetX, targetY + y);
+ BufferSpan source = area.GetRowSpan(y);
+ BufferSpan destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromXyzwBytes(source, destination, width);
}
}
@@ -367,8 +359,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
- BufferPointer source = this.GetRowPointer(sourceX, sourceY + y);
- BufferPointer destination = area.GetRowPointer(y);
+ BufferSpan source = this.GetRowSpan(sourceX, sourceY + y);
+ BufferSpan destination = area.GetRowSpan(y);
Operations.ToZyxBytes(source, destination, width);
}
}
@@ -386,8 +378,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
- BufferPointer source = this.GetRowPointer(sourceX, sourceY + y);
- BufferPointer destination = area.GetRowPointer(y);
+ BufferSpan source = this.GetRowSpan(sourceX, sourceY + y);
+ BufferSpan destination = area.GetRowSpan(y);
Operations.ToZyxwBytes(source, destination, width);
}
}
@@ -405,8 +397,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
- BufferPointer source = this.GetRowPointer(sourceX, sourceY + y);
- BufferPointer destination = area.GetRowPointer(y);
+ BufferSpan source = this.GetRowSpan(sourceX, sourceY + y);
+ BufferSpan destination = area.GetRowSpan(y);
Operations.ToXyzBytes(source, destination, width);
}
}
@@ -424,15 +416,15 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
- BufferPointer source = this.GetRowPointer(sourceX, sourceY + y);
- BufferPointer destination = area.GetRowPointer(y);
+ BufferSpan source = this.GetRowSpan(sourceX, sourceY + y);
+ BufferSpan destination = area.GetRowSpan(y);
Operations.ToXyzwBytes(source, destination, width);
}
}
private void SetPixelBufferUnsafe(int width, int height, TColor[] pixels)
{
- this.SetPixelBufferUnsafe(width, height, new PinnedBuffer(width * height, pixels));
+ this.SetPixelBufferUnsafe(width, height, new PinnedImageBuffer(pixels, width, height));
}
///
@@ -441,7 +433,7 @@ namespace ImageSharp
/// The width.
/// The height.
/// The pixel buffer
- private void SetPixelBufferUnsafe(int width, int height, PinnedBuffer pixels)
+ private void SetPixelBufferUnsafe(int width, int height, PinnedImageBuffer pixels)
{
this.pixelBuffer = pixels;
this.pixelsBase = (byte*)pixels.Pointer;
diff --git a/src/ImageSharp/Image/PixelArea{TColor}.cs b/src/ImageSharp/Image/PixelArea{TColor}.cs
index be6debba2f..bd10c9b6b0 100644
--- a/src/ImageSharp/Image/PixelArea{TColor}.cs
+++ b/src/ImageSharp/Image/PixelArea{TColor}.cs
@@ -5,17 +5,15 @@
namespace ImageSharp
{
using System;
- using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
///
/// Represents an area of generic pixels.
///
/// The pixel format.
- public sealed unsafe class PixelArea : IDisposable
+ internal sealed unsafe class PixelArea : IDisposable
where TColor : struct, IPixel
{
///
@@ -204,11 +202,11 @@ namespace ImageSharp
}
///
- /// Gets a to the row y.
+ /// Gets a to the row y.
///
/// The y coordinate
- /// The
- internal BufferPointer GetRowPointer(int y)
+ /// The
+ internal BufferSpan GetRowSpan(int y)
{
return this.byteBuffer.Slice(y * this.RowStride);
}
diff --git a/src/ImageSharp/ImageProcessor.cs b/src/ImageSharp/ImageProcessor.cs
index a0766d1edf..79525a8e83 100644
--- a/src/ImageSharp/ImageProcessor.cs
+++ b/src/ImageSharp/ImageProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing
/// Allows the application of processors to images.
///
/// The pixel format.
- public abstract class ImageProcessor : IImageProcessor
+ internal abstract class ImageProcessor : IImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index de3e764734..c51c0833a0 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -2,7 +2,7 @@
A cross-platform library for the processing of image files; written in C#ImageSharp
- 1.0.0-alpha3
+ 1.0.0-alpha5James Jackson-South and contributorsnetstandard1.3;netstandard1.1true
diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs
index de1e424769..aed6efa2cb 100644
--- a/src/ImageSharp/MetaData/ImageMetaData.cs
+++ b/src/ImageSharp/MetaData/ImageMetaData.cs
@@ -5,6 +5,7 @@
namespace ImageSharp
{
+ using System;
using System.Collections.Generic;
///
@@ -55,12 +56,16 @@ namespace ImageSharp
foreach (ImageProperty property in other.Properties)
{
- this.Properties.Add(new ImageProperty(property));
+ this.Properties.Add(new ImageProperty(property));
}
if (other.ExifProfile != null)
{
- this.ExifProfile = new ExifProfile(other.ExifProfile);
+ this.ExifProfile = new ExifProfile(other.ExifProfile);
+ }
+ else
+ {
+ this.ExifProfile = null;
}
}
diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs
index b363286b00..c4a94c5ff1 100644
--- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs
+++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs
@@ -137,7 +137,7 @@ namespace ImageSharp
using (MemoryStream memStream = new MemoryStream(this.data, this.thumbnailOffset, this.thumbnailLength))
{
- return new Image(memStream);
+ return Image.Load(memStream);
}
}
diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
index 2d57957d3f..5555463418 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// . The image will be converted to grayscale before thresholding occurs.
///
/// The pixel format.
- public class BinaryThresholdProcessor : ImageProcessor
+ internal class BinaryThresholdProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs
index ce03c58a8a..50f042bd69 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// An that dithers an image using error diffusion.
///
/// The pixel format.
- public class ErrorDiffusionDitherProcessor : ImageProcessor
+ internal class ErrorDiffusionDitherProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs
index 4126419f25..c7f4d20ace 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
/// An that dithers an image using error diffusion.
///
/// The pixel format.
- public class OrderedDitherProcessor : ImageProcessor
+ internal class OrderedDitherProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/BlackWhiteProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/BlackWhiteProcessor.cs
index 0ea821bef6..0214af72de 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/BlackWhiteProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/BlackWhiteProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image to their black and white equivalent.
///
/// The pixel format.
- public class BlackWhiteProcessor : ColorMatrixFilter
+ internal class BlackWhiteProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs
index 15e7c78da1..d1e986a9df 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating Achromatomaly (Color desensitivity) color blindness.
///
/// The pixel format.
- public class AchromatomalyProcessor : ColorMatrixFilter
+ internal class AchromatomalyProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs
index adca0fe985..d17e28dcaf 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating Achromatopsia (Monochrome) color blindness.
///
/// The pixel format.
- public class AchromatopsiaProcessor : ColorMatrixFilter
+ internal class AchromatopsiaProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs
index 6de54beeae..7f4529ba47 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating Deuteranomaly (Green-Weak) color blindness.
///
/// The pixel format.
- public class DeuteranomalyProcessor : ColorMatrixFilter
+ internal class DeuteranomalyProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs
index 4729ccc616..493ed2caed 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating Deuteranopia (Green-Blind) color blindness.
///
/// The pixel format.
- public class DeuteranopiaProcessor : ColorMatrixFilter
+ internal class DeuteranopiaProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs
index 200fff24d8..ddea24be01 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating Protanopia (Red-Weak) color blindness.
///
/// The pixel format.
- public class ProtanomalyProcessor : ColorMatrixFilter
+ internal class ProtanomalyProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs
index 7c0f03543f..c5446dbe1a 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating Protanopia (Red-Blind) color blindness.
///
/// The pixel format.
- public class ProtanopiaProcessor : ColorMatrixFilter
+ internal class ProtanopiaProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs
index 63f1fd9eb1..846e9c61a7 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating Tritanomaly (Blue-Weak) color blindness.
///
/// The pixel format.
- public class TritanomalyProcessor : ColorMatrixFilter
+ internal class TritanomalyProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs
index 2200414fee..a0094f71f0 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating Tritanopia (Blue-Blind) color blindness.
///
/// The pixel format.
- public class TritanopiaProcessor : ColorMatrixFilter
+ internal class TritanopiaProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixFilter.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs
similarity index 96%
rename from src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixFilter.cs
rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs
index a37228a9ba..c75da00037 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixFilter.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// The color matrix filter. Inherit from this class to perform operation involving color matrices.
///
/// The pixel format.
- public abstract class ColorMatrixFilter : ImageProcessor, IColorMatrixFilter
+ internal abstract class ColorMatrixProcessor : ImageProcessor, IColorMatrixFilter
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt601Processor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt601Processor.cs
index bd14da59e5..1f5a0fa7e9 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt601Processor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt601Processor.cs
@@ -9,11 +9,11 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
///
- /// Converts the colors of the image to Grayscale applying the formula as specified by
- /// ITU-R Recommendation BT.601 .
+ /// Converts the colors of the image to Grayscale applying the formula as specified by ITU-R Recommendation BT.601
+ /// .
///
/// The pixel format.
- public class GrayscaleBt601Processor : ColorMatrixFilter
+ internal class GrayscaleBt601Processor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt709Processor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt709Processor.cs
index 925a36c754..048462696a 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt709Processor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt709Processor.cs
@@ -9,11 +9,11 @@ namespace ImageSharp.Processing.Processors
using System.Numerics;
///
- /// Converts the colors of the image to Grayscale applying the formula as specified by
- /// ITU-R Recommendation BT.709 .
+ /// Converts the colors of the image to Grayscale applying the formula as specified by ITU-R Recommendation BT.709
+ /// .
///
/// The pixel format.
- public class GrayscaleBt709Processor : ColorMatrixFilter
+ internal class GrayscaleBt709Processor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/HueProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/HueProcessor.cs
index fdf5ffdb44..0d06c58682 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/HueProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/HueProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// An to change the hue of an .
///
/// The pixel format.
- public class HueProcessor : ColorMatrixFilter
+ internal class HueProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/IColorMatrixFilter.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/IColorMatrixFilter.cs
index faee890eb6..57296a0c3b 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/IColorMatrixFilter.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/IColorMatrixFilter.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// alter the image pixels.
///
/// The pixel format.
- public interface IColorMatrixFilter : IImageProcessor
+ internal interface IColorMatrixFilter : IImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/KodachromeProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/KodachromeProcessor.cs
index fee1684985..8df8efcd19 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/KodachromeProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/KodachromeProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating an old Kodachrome camera effect.
///
/// The pixel format.
- public class KodachromeProcessor : ColorMatrixFilter
+ internal class KodachromeProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs
index 0e614afe8a..b89caec863 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating an old Lomograph effect.
///
/// The pixel format.
- public class LomographProcessor : ColorMatrixFilter
+ internal class LomographProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
private static readonly TColor VeryDarkGreen = ColorBuilder.FromRGBA(0, 10, 0, 255);
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs
index 666fe5bc0c..b5a23f8557 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Converts the colors of the image recreating an old Polaroid effect.
///
/// The pixel format.
- public class PolaroidProcessor : ColorMatrixFilter
+ internal class PolaroidProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
private static TColor veryDarkOrange = ColorBuilder.FromRGB(102, 34, 0);
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/SaturationProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/SaturationProcessor.cs
index d63326385c..371294dd56 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/SaturationProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/SaturationProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// An to change the saturation of an .
///
/// The pixel format.
- public class SaturationProcessor : ColorMatrixFilter
+ internal class SaturationProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/SepiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/SepiaProcessor.cs
index d8fdc6cd1a..49a071bd98 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/SepiaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/SepiaProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// The formula used matches the svg specification.
///
/// The pixel format.
- public class SepiaProcessor : ColorMatrixFilter
+ internal class SepiaProcessor : ColorMatrixProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
index 3597ba7de7..7ffca534cd 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
@@ -11,7 +11,7 @@ namespace ImageSharp.Processing.Processors
/// Applies a Box blur sampler to the image.
///
/// The pixel format.
- public class BoxBlurProcessor : ImageProcessor
+ internal class BoxBlurProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
index d104f5d351..fa06a863ec 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// Defines a sampler that uses two one-dimensional matrices to perform convolution against an image.
///
/// The pixel format.
- public class Convolution2DProcessor : ImageProcessor
+ internal class Convolution2DProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
@@ -108,9 +108,9 @@ namespace ImageSharp.Processing.Processors
}
}
- float red = (float)Math.Sqrt((rX * rX) + (rY * rY));
- float green = (float)Math.Sqrt((gX * gX) + (gY * gY));
- float blue = (float)Math.Sqrt((bX * bX) + (bY * bY));
+ float red = MathF.Sqrt((rX * rX) + (rY * rY));
+ float green = MathF.Sqrt((gX * gX) + (gY * gY));
+ float blue = MathF.Sqrt((bX * bX) + (bY * bY));
TColor packed = default(TColor);
packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
index 1d118443c3..45906a46fc 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// Defines a sampler that uses two one-dimensional matrices to perform two-pass convolution against an image.
///
/// The pixel format.
- public class Convolution2PassProcessor : ImageProcessor
+ internal class Convolution2PassProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
index 6b5b6d3fe4..3ab95c4ce9 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// Defines a sampler that uses a 2 dimensional matrix to perform convolution against an image.
///
/// The pixel format.
- public class ConvolutionProcessor : ImageProcessor
+ internal class ConvolutionProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs
index a8c786f712..b5c6816569 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs
@@ -11,7 +11,7 @@ namespace ImageSharp.Processing.Processors
/// Defines a sampler that detects edges within an image using two one-dimensional matrices.
///
/// The pixel format.
- public abstract class EdgeDetector2DProcessor : ImageProcessor, IEdgeDetectorProcessor
+ internal abstract class EdgeDetector2DProcessor : ImageProcessor, IEdgeDetectorProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
index eb8491d4cd..e92c2d1093 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// Defines a sampler that detects edges within an image using a eight two dimensional matrices.
///
/// The pixel format.
- public abstract class EdgeDetectorCompassProcessor : ImageProcessor, IEdgeDetectorProcessor
+ internal abstract class EdgeDetectorCompassProcessor : ImageProcessor, IEdgeDetectorProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs
index a963bb5780..d8b491faf5 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs
@@ -11,7 +11,7 @@ namespace ImageSharp.Processing.Processors
/// Defines a sampler that detects edges within an image using a single two dimensional matrix.
///
/// The pixel format.
- public abstract class EdgeDetectorProcessor : ImageProcessor, IEdgeDetectorProcessor
+ internal abstract class EdgeDetectorProcessor : ImageProcessor, IEdgeDetectorProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
index 6456cc073c..20e7b1b176 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class KayyaliProcessor : EdgeDetector2DProcessor
+ internal class KayyaliProcessor : EdgeDetector2DProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs
index 90b3fc4b4c..1b88a2200e 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class KirschProcessor : EdgeDetectorCompassProcessor
+ internal class KirschProcessor : EdgeDetectorCompassProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
index c8823efee8..ec6963b1ea 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class Laplacian3X3Processor : EdgeDetectorProcessor
+ internal class Laplacian3X3Processor : EdgeDetectorProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
index 3aad6d1ef0..cc68c4fb71 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class Laplacian5X5Processor : EdgeDetectorProcessor
+ internal class Laplacian5X5Processor : EdgeDetectorProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
index a7da76e136..f0944e6818 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class LaplacianOfGaussianProcessor : EdgeDetectorProcessor
+ internal class LaplacianOfGaussianProcessor : EdgeDetectorProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
index fea9844183..fdb63d837e 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class PrewittProcessor : EdgeDetector2DProcessor
+ internal class PrewittProcessor : EdgeDetector2DProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
index 329a995c09..d9c5f5d213 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class RobertsCrossProcessor : EdgeDetector2DProcessor
+ internal class RobertsCrossProcessor : EdgeDetector2DProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs
index 60726deab5..681d983c45 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class RobinsonProcessor : EdgeDetectorCompassProcessor
+ internal class RobinsonProcessor : EdgeDetectorCompassProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
index ed45ba0acf..c1e83b7f97 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class ScharrProcessor : EdgeDetector2DProcessor
+ internal class ScharrProcessor : EdgeDetector2DProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs
index 3d2c583a7a..0c13fa3d24 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
[SuppressMessage("ReSharper", "StaticMemberInGenericType", Justification = "We want to use only one instance of each array field for each generic type.")]
- public class SobelProcessor : EdgeDetector2DProcessor
+ internal class SobelProcessor : EdgeDetector2DProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs
index ddaffc9b48..65a137e359 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs
@@ -11,7 +11,7 @@ namespace ImageSharp.Processing.Processors
/// Applies a Gaussian blur sampler to the image.
///
/// The pixel format.
- public class GaussianBlurProcessor : ImageProcessor
+ internal class GaussianBlurProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs
index 6541b73800..bb3dc6f999 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs
@@ -11,7 +11,7 @@ namespace ImageSharp.Processing.Processors
/// Applies a Gaussian sharpening sampler to the image.
///
/// The pixel format.
- public class GaussianSharpenProcessor : ImageProcessor
+ internal class GaussianSharpenProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs
index 11af92ea75..ce48aea1ad 100644
--- a/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// An to change the alpha component of an .
///
/// The pixel format.
- public class AlphaProcessor : ImageProcessor
+ internal class AlphaProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs
index d6d209dc7e..d928eb1a47 100644
--- a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// Sets the background color of the image.
///
/// The pixel format.
- public class BackgroundColorProcessor : ImageProcessor
+ internal class BackgroundColorProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
@@ -77,7 +77,7 @@ namespace ImageSharp.Processing.Processors
color = Vector4BlendTransforms.PremultipliedLerp(backgroundColor, color, .5F);
}
- if (Math.Abs(a) < Constants.Epsilon)
+ if (MathF.Abs(a) < Constants.Epsilon)
{
color = backgroundColor;
}
diff --git a/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs
index 566f2c6d74..84df5e89e8 100644
--- a/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// An to change the brightness of an .
///
/// The pixel format.
- public class BrightnessProcessor : ImageProcessor
+ internal class BrightnessProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs
index f4acc42bfc..042e396996 100644
--- a/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// An to change the contrast of an .
///
/// The pixel format.
- public class ContrastProcessor : ImageProcessor
+ internal class ContrastProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs
index 641cd1b47d..4358e89460 100644
--- a/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// An to invert the colors of an .
///
/// The pixel format.
- public class InvertProcessor : ImageProcessor
+ internal class InvertProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs
index 6b9558ad2c..957955c6c4 100644
--- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs
@@ -14,7 +14,7 @@ namespace ImageSharp.Processing.Processors
///
/// Adapted from by Dewald Esterhuizen.
/// The pixel format.
- public class OilPaintingProcessor : ImageProcessor
+ internal class OilPaintingProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
@@ -139,9 +139,9 @@ namespace ImageSharp.Processing.Processors
}
}
- float red = Math.Abs(redBin[maxIndex] / maxIntensity);
- float green = Math.Abs(greenBin[maxIndex] / maxIntensity);
- float blue = Math.Abs(blueBin[maxIndex] / maxIntensity);
+ float red = MathF.Abs(redBin[maxIndex] / maxIntensity);
+ float green = MathF.Abs(greenBin[maxIndex] / maxIntensity);
+ float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity);
TColor packed = default(TColor);
packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs
index d9d78dfa8c..818b1f5137 100644
--- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// An to pixelate the colors of an .
///
/// The pixel format.
- public class PixelateProcessor : ImageProcessor
+ internal class PixelateProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
index 9043b66cb8..6eeb7398aa 100644
--- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// An that applies a radial glow effect an .
///
/// The pixel format.
- public class GlowProcessor : ImageProcessor
+ internal class GlowProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
@@ -44,7 +44,7 @@ namespace ImageSharp.Processing.Processors
int endX = sourceRectangle.Right;
TColor glowColor = this.GlowColor;
Vector2 centre = Rectangle.Center(sourceRectangle).ToVector2();
- float maxDistance = this.Radius > 0 ? Math.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
+ float maxDistance = this.Radius > 0 ? MathF.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
// Align start/end positions.
int minX = Math.Max(0, startX);
diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
index f1872d0b81..40d6d94ac9 100644
--- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
@@ -13,7 +13,7 @@ namespace ImageSharp.Processing.Processors
/// An that applies a radial vignette effect to an .
///
/// The pixel format.
- public class VignetteProcessor : ImageProcessor
+ internal class VignetteProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
@@ -49,9 +49,9 @@ namespace ImageSharp.Processing.Processors
int endX = sourceRectangle.Right;
TColor vignetteColor = this.VignetteColor;
Vector2 centre = Rectangle.Center(sourceRectangle).ToVector2();
- float rX = this.RadiusX > 0 ? Math.Min(this.RadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
- float rY = this.RadiusY > 0 ? Math.Min(this.RadiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F;
- float maxDistance = (float)Math.Sqrt((rX * rX) + (rY * rY));
+ float rX = this.RadiusX > 0 ? MathF.Min(this.RadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
+ float rY = this.RadiusY > 0 ? MathF.Min(this.RadiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F;
+ float maxDistance = MathF.Sqrt((rX * rX) + (rY * rY));
// Align start/end positions.
int minX = Math.Max(0, startX);
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs
deleted file mode 100644
index 2190254f0d..0000000000
--- a/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs
+++ /dev/null
@@ -1,171 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Processing.Processors
-{
- using System;
- using System.Numerics;
- using System.Threading.Tasks;
-
- ///
- /// Provides methods that allow the resizing of images using various algorithms.
- /// This version will expand and compress the image to and from a linear color space during processing.
- ///
- /// The pixel format.
- public class CompandingResizeProcessor : ResamplingWeightedProcessor
- where TColor : struct, IPixel
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The sampler to perform the resize operation.
- /// The target width.
- /// The target height.
- public CompandingResizeProcessor(IResampler sampler, int width, int height)
- : base(sampler, width, height, new Rectangle(0, 0, width, height))
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The sampler to perform the resize operation.
- /// The target width.
- /// The target height.
- ///
- /// The structure that specifies the portion of the target image object to draw to.
- ///
- public CompandingResizeProcessor(IResampler sampler, int width, int height, Rectangle resizeRectangle)
- : base(sampler, width, height, resizeRectangle)
- {
- }
-
- ///
- public override bool Compand { get; set; } = true;
-
- ///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
- {
- // Jump out, we'll deal with that later.
- if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle)
- {
- return;
- }
-
- int width = this.Width;
- int height = this.Height;
- int sourceX = sourceRectangle.X;
- int sourceY = sourceRectangle.Y;
- int startY = this.ResizeRectangle.Y;
- int endY = this.ResizeRectangle.Bottom;
- int startX = this.ResizeRectangle.X;
- int endX = this.ResizeRectangle.Right;
-
- int minX = Math.Max(0, startX);
- int maxX = Math.Min(width, endX);
- int minY = Math.Max(0, startY);
- int maxY = Math.Min(height, endY);
-
- if (this.Sampler is NearestNeighborResampler)
- {
- // Scaling factors
- float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
- float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;
-
- using (PixelAccessor targetPixels = new PixelAccessor(width, height))
- {
- using (PixelAccessor sourcePixels = source.Lock())
- {
- Parallel.For(
- minY,
- maxY,
- this.ParallelOptions,
- y =>
- {
- // Y coordinates of source points
- int originY = (int)(((y - startY) * heightFactor) + sourceY);
-
- for (int x = minX; x < maxX; x++)
- {
- // X coordinates of source points
- targetPixels[x, y] = sourcePixels[(int)(((x - startX) * widthFactor) + sourceX), originY];
- }
- });
- }
-
- // Break out now.
- source.SwapPixelsBuffers(targetPixels);
- return;
- }
- }
-
- // Interpolate the image using the calculated weights.
- // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
- // First process the columns. Since we are not using multiple threads startY and endY
- // are the upper and lower bounds of the source rectangle.
- using (PixelAccessor targetPixels = new PixelAccessor(width, height))
- {
- using (PixelAccessor sourcePixels = source.Lock())
- using (PixelAccessor firstPassPixels = new PixelAccessor(width, source.Height))
- {
- Parallel.For(
- 0,
- sourceRectangle.Bottom,
- this.ParallelOptions,
- y =>
- {
- for (int x = minX; x < maxX; x++)
- {
- // Ensure offsets are normalised for cropping and padding.
- Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
-
- // Destination color components
- Vector4 destination = Vector4.Zero;
-
- for (int i = 0; i < horizontalValues.Length; i++)
- {
- Weight xw = horizontalValues[i];
- destination += sourcePixels[xw.Index + sourceX, y].ToVector4().Expand() * xw.Value;
- }
-
- TColor d = default(TColor);
- d.PackFromVector4(destination.Compress());
- firstPassPixels[x, y] = d;
- }
- });
-
- // Now process the rows.
- Parallel.For(
- minY,
- maxY,
- this.ParallelOptions,
- y =>
- {
- // Ensure offsets are normalised for cropping and padding.
- Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
-
- for (int x = 0; x < width; x++)
- {
- // Destination color components
- Vector4 destination = Vector4.Zero;
-
- for (int i = 0; i < verticalValues.Length; i++)
- {
- Weight yw = verticalValues[i];
- destination += firstPassPixels[x, yw.Index + sourceY].ToVector4().Expand() * yw.Value;
- }
-
- TColor d = default(TColor);
- d.PackFromVector4(destination.Compress());
- targetPixels[x, y] = d;
- }
- });
- }
-
- source.SwapPixelsBuffers(targetPixels);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs
index 88f23a7fd6..7d473c55ed 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Provides methods to allow the cropping of an image.
///
/// The pixel format.
- public class CropProcessor : ImageProcessor
+ internal class CropProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs
index d150c59d49..049fbf2de0 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// entropy.
///
/// The pixel format.
- public class EntropyCropProcessor : ImageProcessor
+ internal class EntropyCropProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs
index da4f2b3a80..290d81799a 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Provides methods that allow the flipping of an image around its center point.
///
/// The pixel format.
- public class FlipProcessor : ImageProcessor
+ internal class FlipProcessor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs b/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs
index 7e87576870..0c290a9b62 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs
@@ -12,7 +12,7 @@ namespace ImageSharp.Processing.Processors
/// Provides methods to transform an image using a .
///
/// The pixel format.
- public abstract class Matrix3x2Processor : ImageProcessor
+ internal abstract class Matrix3x2Processor : ImageProcessor
where TColor : struct, IPixel
{
///
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
new file mode 100644
index 0000000000..99b143de67
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
@@ -0,0 +1,176 @@
+namespace ImageSharp.Processing.Processors
+{
+ using System;
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Conains the definition of and .
+ ///
+ internal abstract partial class ResamplingWeightedProcessor
+ {
+ ///
+ /// Points to a collection of of weights allocated in .
+ ///
+ internal unsafe struct WeightsWindow
+ {
+ ///
+ /// The local left index position
+ ///
+ public int Left;
+
+ ///
+ /// The span of weights pointing to .
+ ///
+ // TODO: In the case of switching to official System.Memory and System.Buffers.Primitives this should be System.Buffers.Buffer (formerly Memory), because Span is stack-only!
+ // see: https://github.com/dotnet/corefxlab/blob/873d35ebed7264e2f9adb556f3b61bebc12395d6/docs/specs/memory.md
+ public BufferSpan Span;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The local left index
+ /// The span
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal WeightsWindow(int left, BufferSpan span)
+ {
+ this.Left = left;
+ this.Span = span;
+ }
+
+ ///
+ /// Gets an unsafe float* pointer to the beginning of .
+ ///
+ public float* Ptr => (float*)this.Span.PointerAtOffset;
+
+ ///
+ /// Gets the lenghth of the weights window
+ ///
+ public int Length => this.Span.Length;
+
+ ///
+ /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance.
+ ///
+ /// The input span of vectors
+ /// The weighted sum
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector4 ComputeWeightedRowSum(BufferSpan rowSpan)
+ {
+ float* horizontalValues = this.Ptr;
+ int left = this.Left;
+ Vector4* vecPtr = (Vector4*)rowSpan.PointerAtOffset;
+ vecPtr += left;
+
+ // Destination color components
+ Vector4 result = Vector4.Zero;
+
+ for (int i = 0; i < this.Length; i++)
+ {
+ float weight = horizontalValues[i];
+ result += (*vecPtr) * weight;
+ vecPtr++;
+ }
+
+ return result;
+ }
+
+ ///
+ /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance.
+ /// Applies to all input vectors.
+ ///
+ /// The input span of vectors
+ /// The weighted sum
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector4 ComputeExpandedWeightedRowSum(BufferSpan rowSpan)
+ {
+ float* horizontalValues = this.Ptr;
+ int left = this.Left;
+ Vector4* vecPtr = (Vector4*)rowSpan.PointerAtOffset;
+ vecPtr += left;
+
+ // Destination color components
+ Vector4 result = Vector4.Zero;
+
+ for (int i = 0; i < this.Length; i++)
+ {
+ float weight = horizontalValues[i];
+ result += (*vecPtr).Expand() * weight;
+ vecPtr++;
+ }
+
+ return result;
+ }
+
+ ///
+ /// Computes the sum of vectors in 'firstPassPixels' at a column pointed by 'x',
+ /// weighted by weight values, pointed by this instance.
+ ///
+ /// The buffer of input vectors in row first order
+ /// The column position
+ /// The weighted sum
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector4 ComputeWeightedColumnSum(PinnedImageBuffer firstPassPixels, int x)
+ {
+ float* verticalValues = this.Ptr;
+ int left = this.Left;
+
+ // Destination color components
+ Vector4 result = Vector4.Zero;
+
+ for (int i = 0; i < this.Length; i++)
+ {
+ float yw = verticalValues[i];
+ int index = left + i;
+ result += firstPassPixels[x, index] * yw;
+ }
+
+ return result;
+ }
+ }
+
+ ///
+ /// Holds the values in an optimized contigous memory region.
+ ///
+ internal class WeightsBuffer : IDisposable
+ {
+ private PinnedImageBuffer dataBuffer;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The size of the source window
+ /// The size of the destination window
+ public WeightsBuffer(int sourceSize, int destinationSize)
+ {
+ this.dataBuffer = PinnedImageBuffer.CreateClean(sourceSize, destinationSize);
+ this.Weights = new WeightsWindow[destinationSize];
+ }
+
+ ///
+ /// Gets the calculated values.
+ ///
+ public WeightsWindow[] Weights { get; }
+
+ ///
+ /// Disposes instance releasing it's backing buffer.
+ ///
+ public void Dispose()
+ {
+ this.dataBuffer.Dispose();
+ }
+
+ ///
+ /// Slices a weights value at the given positions.
+ ///
+ /// The index in destination buffer
+ /// The local left index value
+ /// The local right index value
+ /// The weights
+ public WeightsWindow GetWeightsWindow(int destIdx, int leftIdx, int rightIdx)
+ {
+ BufferSpan span = this.dataBuffer.GetRowSpan(destIdx).Slice(leftIdx, rightIdx - leftIdx + 1);
+ return new WeightsWindow(leftIdx, span);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
index 25a7a4efd6..1374e58156 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
@@ -6,13 +6,15 @@
namespace ImageSharp.Processing.Processors
{
using System;
+ using System.Buffers;
+ using System.Runtime.InteropServices;
///
/// Provides methods that allow the resizing of images using various algorithms.
/// Adapted from
///
/// The pixel format.
- public abstract class ResamplingWeightedProcessor : ImageProcessor
+ internal abstract partial class ResamplingWeightedProcessor : ImageProcessor
where TColor : struct, IPixel
{
///