diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index a1a55a389a..4a7b35ac2c 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -16,7 +16,7 @@
{
"taskName": "build benchmark",
"suppressTaskName": true,
- "args": [ "build", "tests/ImageSharp.Benchmarks/project.json", "-f", "netcoreapp1.1", "-c", "Release" ],
+ "args": [ "build", "tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj", "-f", "netcoreapp1.1", "-c", "Release" ],
"showOutput": "always",
"problemMatcher": "$msCompile"
},
diff --git a/src/ImageSharp.Drawing/Drawable.cs b/src/ImageSharp.Drawing/Drawable.cs
deleted file mode 100644
index 62f5e62c14..0000000000
--- a/src/ImageSharp.Drawing/Drawable.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Drawing
-{
- ///
- /// Represents a path or set of paths that can be drawn as an outline.
- ///
- public abstract class Drawable
- {
- ///
- /// Gets the maximum number of intersections to could be returned.
- ///
- public abstract int MaxIntersections { get; }
-
- ///
- /// Gets the bounds.
- ///
- public abstract Rectangle Bounds { get; }
-
- ///
- /// Gets the point information for the specified x and y location.
- ///
- /// The x.
- /// The y.
- /// Information about the point in relation to a drawable edge
- public abstract PointInfo GetPointInfo(int x, int y);
-
- ///
- /// Scans the X axis for intersections.
- ///
- /// The x.
- /// 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.
- ///
- /// 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);
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
index a3552a09cc..13500b65af 100644
--- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
+++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
@@ -36,11 +36,10 @@
+
All
-
-
..\..\ImageSharp.ruleset
diff --git a/src/ImageSharp.Drawing/Paths/DrawPath.cs b/src/ImageSharp.Drawing/Paths/DrawPath.cs
index 176539663c..1fba06370d 100644
--- a/src/ImageSharp.Drawing/Paths/DrawPath.cs
+++ b/src/ImageSharp.Drawing/Paths/DrawPath.cs
@@ -28,7 +28,7 @@ namespace ImageSharp
public static Image Draw(this Image source, IPen pen, IPath path, GraphicsOptions options)
where TPixel : struct, IPixel
{
- return source.Draw(pen, new ShapePath(path), options);
+ return source.Fill(pen.StrokeFill, new ShapePath(path, pen), options);
}
///
diff --git a/src/ImageSharp.Drawing/DrawPath.cs b/src/ImageSharp.Drawing/Paths/DrawPathCollection.cs
similarity index 79%
rename from src/ImageSharp.Drawing/DrawPath.cs
rename to src/ImageSharp.Drawing/Paths/DrawPathCollection.cs
index 09d3dbb028..877737653d 100644
--- a/src/ImageSharp.Drawing/DrawPath.cs
+++ b/src/ImageSharp.Drawing/Paths/DrawPathCollection.cs
@@ -8,8 +8,8 @@ namespace ImageSharp
using Drawing;
using Drawing.Brushes;
using Drawing.Pens;
- using Drawing.Processors;
using ImageSharp.PixelFormats;
+ using SixLabors.Shapes;
///
/// Extension methods for the type.
@@ -17,18 +17,23 @@ namespace ImageSharp
public static partial class ImageExtensions
{
///
- /// Draws the outline of the region with the provided pen.
+ /// Draws the outline of the polygon with the provided pen.
///
/// The type of the color.
/// The image this method extends.
/// The pen.
- /// The path.
+ /// The paths.
/// The options.
/// The .
- public static Image Draw(this Image source, IPen pen, Drawable path, GraphicsOptions options)
+ public static Image Draw(this Image source, IPen pen, IPathCollection paths, GraphicsOptions options)
where TPixel : struct, IPixel
{
- return source.Apply(new DrawPathProcessor(pen, path, options));
+ foreach (IPath path in paths)
+ {
+ source.Draw(pen, path, options);
+ }
+
+ return source;
}
///
@@ -37,12 +42,12 @@ namespace ImageSharp
/// The type of the color.
/// The image this method extends.
/// The pen.
- /// The path.
+ /// The paths.
/// The .
- public static Image Draw(this Image source, IPen pen, Drawable path)
+ public static Image Draw(this Image source, IPen pen, IPathCollection paths)
where TPixel : struct, IPixel
{
- return source.Draw(pen, path, GraphicsOptions.Default);
+ return source.Draw(pen, paths, GraphicsOptions.Default);
}
///
@@ -52,13 +57,13 @@ namespace ImageSharp
/// The image this method extends.
/// The brush.
/// The thickness.
- /// The path.
+ /// The shapes.
/// The options.
/// The .
- public static Image Draw(this Image source, IBrush brush, float thickness, Drawable path, GraphicsOptions options)
+ public static Image Draw(this Image source, IBrush brush, float thickness, IPathCollection paths, GraphicsOptions options)
where TPixel : struct, IPixel
{
- return source.Draw(new Pen(brush, thickness), path, options);
+ return source.Draw(new Pen(brush, thickness), paths, options);
}
///
@@ -68,12 +73,12 @@ namespace ImageSharp
/// The image this method extends.
/// The brush.
/// The thickness.
- /// The path.
+ /// The paths.
/// The .
- public static Image Draw(this Image source, IBrush brush, float thickness, Drawable path)
+ public static Image Draw(this Image source, IBrush brush, float thickness, IPathCollection paths)
where TPixel : struct, IPixel
{
- return source.Draw(new Pen(brush, thickness), path);
+ return source.Draw(new Pen(brush, thickness), paths);
}
///
@@ -83,13 +88,13 @@ namespace ImageSharp
/// The image this method extends.
/// The color.
/// The thickness.
- /// The path.
+ /// The paths.
/// The options.
/// The .
- public static Image Draw(this Image source, TPixel color, float thickness, Drawable path, GraphicsOptions options)
+ public static Image Draw(this Image source, TPixel color, float thickness, IPathCollection paths, GraphicsOptions options)
where TPixel : struct, IPixel
{
- return source.Draw(new SolidBrush(color), thickness, path, options);
+ return source.Draw(new SolidBrush(color), thickness, paths, options);
}
///
@@ -99,12 +104,12 @@ namespace ImageSharp
/// The image this method extends.
/// The color.
/// The thickness.
- /// The path.
+ /// The paths.
/// The .
- public static Image Draw(this Image source, TPixel color, float thickness, Drawable path)
+ public static Image Draw(this Image source, TPixel color, float thickness, IPathCollection paths)
where TPixel : struct, IPixel
{
- return source.Draw(new SolidBrush(color), thickness, path);
+ return source.Draw(new SolidBrush(color), thickness, paths);
}
}
}
diff --git a/src/ImageSharp.Drawing/Paths/FillPathCollection.cs b/src/ImageSharp.Drawing/Paths/FillPathCollection.cs
new file mode 100644
index 0000000000..3ea9fb94b8
--- /dev/null
+++ b/src/ImageSharp.Drawing/Paths/FillPathCollection.cs
@@ -0,0 +1,81 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using Drawing;
+ using Drawing.Brushes;
+ using ImageSharp.PixelFormats;
+ using SixLabors.Shapes;
+
+ ///
+ /// Extension methods for the type.
+ ///
+ public static partial class ImageExtensions
+ {
+ ///
+ /// Flood fills the image in the shape of the provided polygon with the specified brush..
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The brush.
+ /// The shapes.
+ /// The graphics options.
+ /// The .
+ public static Image Fill(this Image source, IBrush brush, IPathCollection paths, GraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ foreach (IPath s in paths)
+ {
+ source.Fill(brush, s, options);
+ }
+
+ return source;
+ }
+
+ ///
+ /// Flood fills the image in the shape of the provided polygon with the specified brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The brush.
+ /// The paths.
+ /// The .
+ public static Image Fill(this Image source, IBrush brush, IPathCollection paths)
+ where TPixel : struct, IPixel
+ {
+ return source.Fill(brush, paths, GraphicsOptions.Default);
+ }
+
+ ///
+ /// Flood fills the image in the shape of the provided polygon with the specified brush..
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The color.
+ /// The paths.
+ /// The options.
+ /// The .
+ public static Image Fill(this Image source, TPixel color, IPathCollection paths, GraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.Fill(new SolidBrush(color), paths, options);
+ }
+
+ ///
+ /// Flood fills the image in the shape of the provided polygon with the specified brush..
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The color.
+ /// The paths.
+ /// The .
+ public static Image Fill(this Image source, TPixel color, IPathCollection paths)
+ where TPixel : struct, IPixel
+ {
+ return source.Fill(new SolidBrush(color), paths);
+ }
+ }
+}
diff --git a/src/ImageSharp.Drawing/Paths/ShapePath.cs b/src/ImageSharp.Drawing/Paths/ShapePath.cs
index d0376ccc1e..63c814f2d5 100644
--- a/src/ImageSharp.Drawing/Paths/ShapePath.cs
+++ b/src/ImageSharp.Drawing/Paths/ShapePath.cs
@@ -1,12 +1,12 @@
-//
+//
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
namespace ImageSharp.Drawing
{
+ using System;
using System.Buffers;
- using System.Collections.Immutable;
using System.Numerics;
using SixLabors.Shapes;
@@ -14,91 +14,19 @@ namespace ImageSharp.Drawing
using Rectangle = ImageSharp.Rectangle;
///
- /// A drawable mapping between a and a drawable region.
+ /// A mapping between a and a region.
///
- internal class ShapePath : Drawable
+ internal class ShapePath : ShapeRegion
{
///
/// Initializes a new instance of the class.
///
- /// The path.
- public ShapePath(IPath path)
+ /// The shape.
+ /// The pen to apply to the shape.
+ // SixLabors.shape willbe moving to a Span/ReadOnlySpan based API shortly use ToArray for now.
+ public ShapePath(IPath shape, Pens.IPen pen)
+ : base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern.ToArray()))
{
- this.Path = path;
- this.Bounds = path.Bounds.Convert();
- }
-
- ///
- /// Gets the fillable shape
- ///
- public IPath Path { get; }
-
- ///
- public override int MaxIntersections => this.Path.MaxIntersections;
-
- ///
- 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.Path.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)
- {
- Vector2 start = new Vector2(this.Bounds.Left - 1, y);
- Vector2 end = new Vector2(this.Bounds.Right + 1, y);
- Vector2[] innerbuffer = ArrayPool.Shared.Rent(length);
- try
- {
- int count = this.Path.FindIntersections(start, end, innerbuffer, length, 0);
-
- for (int i = 0; i < count; i++)
- {
- buffer[i + offset] = innerbuffer[i].X;
- }
-
- return count;
- }
- finally
- {
- ArrayPool.Shared.Return(innerbuffer);
- }
- }
-
- ///
- public override PointInfo GetPointInfo(int x, int y)
- {
- Vector2 point = new Vector2(x, y);
- SixLabors.Shapes.PointInfo dist = this.Path.Distance(point);
-
- return new PointInfo
- {
- DistanceAlongPath = dist.DistanceAlongPath,
- DistanceFromPath =
- dist.DistanceFromPath < 0
- ? -dist.DistanceFromPath
- : dist.DistanceFromPath
- };
}
}
}
diff --git a/src/ImageSharp.Drawing/Paths/ShapeRegion.cs b/src/ImageSharp.Drawing/Paths/ShapeRegion.cs
index 0868945318..9dbf52285b 100644
--- a/src/ImageSharp.Drawing/Paths/ShapeRegion.cs
+++ b/src/ImageSharp.Drawing/Paths/ShapeRegion.cs
@@ -40,18 +40,18 @@ namespace ImageSharp.Drawing
public override Rectangle Bounds { get; }
///
- public override int Scan(float y, float[] buffer, int length, int offset)
+ public override int Scan(float y, Span buffer)
{
Vector2 start = new Vector2(this.Bounds.Left - 1, y);
Vector2 end = new Vector2(this.Bounds.Right + 1, y);
- Vector2[] innerbuffer = ArrayPool.Shared.Rent(length);
+ Vector2[] innerbuffer = ArrayPool.Shared.Rent(buffer.Length);
try
{
- int count = this.Shape.FindIntersections(start, end, innerbuffer, length, 0);
+ int count = this.Shape.FindIntersections(start, end, innerbuffer, buffer.Length, 0);
for (int i = 0; i < count; i++)
{
- buffer[i + offset] = innerbuffer[i].X;
+ buffer[i] = innerbuffer[i].X;
}
return count;
diff --git a/src/ImageSharp.Drawing/Pens/IPen.cs b/src/ImageSharp.Drawing/Pens/IPen.cs
index 81d273091e..20ac53dafc 100644
--- a/src/ImageSharp.Drawing/Pens/IPen.cs
+++ b/src/ImageSharp.Drawing/Pens/IPen.cs
@@ -12,21 +12,28 @@ namespace ImageSharp.Drawing.Pens
/// Interface representing a Pen
///
/// The type of the color.
- public interface IPen
+ public interface IPen : IPen
where TPixel : struct, IPixel
{
///
- /// Creates the applicator for applying this pen to an Image
+ /// Gets the stroke fill.
///
- /// The source image.
- /// The region the pen will be applied to.
- /// The currently active graphic options.
- ///
- /// Returns a the applicator for the pen.
- ///
- ///
- /// The when being applied to things like shapes would usually be the bounding box of the shape not necessarily the shape of the whole image.
- ///
- PenApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options);
+ IBrush StrokeFill { get; }
+ }
+
+ ///
+ /// Iterface represting the pattern and size of the stroke to apply with a Pen.
+ ///
+ public interface IPen
+ {
+ ///
+ /// Gets the width to apply to the stroke
+ ///
+ float StrokeWidth { get; }
+
+ ///
+ /// Gets the stoke pattern.
+ ///
+ System.ReadOnlySpan StrokePattern { get; }
}
}
diff --git a/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs b/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs
index 53a3c8c995..37cfff9e93 100644
--- a/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs
@@ -5,6 +5,7 @@
namespace ImageSharp.Drawing.Pens
{
+ using System;
using System.Numerics;
using ImageSharp.Drawing.Brushes;
@@ -48,8 +49,8 @@ namespace ImageSharp.Drawing.Pens
/// The pattern.
public Pen(IBrush brush, float width, float[] pattern)
{
- this.Brush = brush;
- this.Width = width;
+ this.StrokeFill = brush;
+ this.StrokeWidth = width;
this.pattern = pattern;
}
@@ -73,195 +74,13 @@ namespace ImageSharp.Drawing.Pens
{
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The pen.
- internal Pen(Pen pen)
- : this(pen.Brush, pen.Width, pen.pattern)
- {
- }
-
- ///
- /// Gets the brush.
- ///
- ///
- /// The brush.
- ///
- public IBrush Brush { get; }
-
- ///
- /// Gets the width.
- ///
- ///
- /// The width.
- ///
- public float Width { get; }
-
- ///
- /// Creates the applicator for applying this pen to an Image
- ///
- /// The source image.
- /// The region the pen will be applied to.
- /// The Graphics options
- ///
- /// Returns a the applicator for the pen.
- ///
- ///
- /// The when being applied to things like shapes would ussually be the
- /// bounding box of the shape not necorserrally the shape of the whole image
- ///
- public PenApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options)
- {
- if (this.pattern == null || this.pattern.Length < 2)
- {
- // if there is only one item in the pattern then 100% of it will
- // be solid so use the quicker applicator
- return new SolidPenApplicator(source, this.Brush, region, this.Width, options);
- }
-
- return new PatternPenApplicator(source, this.Brush, region, this.Width, this.pattern, options);
- }
-
- private class SolidPenApplicator : PenApplicator
- {
- private readonly BrushApplicator brush;
- private readonly float halfWidth;
-
- public SolidPenApplicator(ImageBase sourcePixels, IBrush brush, RectangleF region, float width, GraphicsOptions options)
- {
- this.brush = brush.CreateApplicator(sourcePixels, region, options);
- this.halfWidth = width / 2;
- this.RequiredRegion = RectangleF.Outset(region, width);
- }
-
- public override RectangleF RequiredRegion
- {
- get;
- }
-
- public override void Dispose()
- {
- this.brush.Dispose();
- }
+ ///
+ public IBrush StrokeFill { get; }
- public override ColoredPointInfo GetColor(int x, int y, PointInfo info)
- {
- var result = default(ColoredPointInfo);
- result.Color = this.brush[x, y];
+ ///
+ public float StrokeWidth { get; }
- if (info.DistanceFromPath < this.halfWidth)
- {
- // inside strip
- result.DistanceFromElement = 0;
- }
- else
- {
- result.DistanceFromElement = info.DistanceFromPath - this.halfWidth;
- }
-
- return result;
- }
- }
-
- private class PatternPenApplicator : PenApplicator
- {
- private readonly BrushApplicator brush;
- private readonly float halfWidth;
- private readonly float[] pattern;
- private readonly float totalLength;
-
- public PatternPenApplicator(ImageBase source, IBrush brush, RectangleF region, float width, float[] pattern, GraphicsOptions options)
- {
- this.brush = brush.CreateApplicator(source, region, options);
- this.halfWidth = width / 2;
- this.totalLength = 0;
-
- this.pattern = new float[pattern.Length + 1];
- this.pattern[0] = 0;
- for (int i = 0; i < pattern.Length; i++)
- {
- this.totalLength += pattern[i] * width;
- this.pattern[i + 1] = this.totalLength;
- }
-
- this.RequiredRegion = RectangleF.Outset(region, width);
- }
-
- public override RectangleF RequiredRegion
- {
- get;
- }
-
- public override void Dispose()
- {
- this.brush.Dispose();
- }
-
- public override ColoredPointInfo GetColor(int x, int y, PointInfo info)
- {
- var infoResult = default(ColoredPointInfo);
- infoResult.DistanceFromElement = float.MaxValue; // is really outside the element
-
- 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
- // and set them on the ColoredPointInfo along with the color.
- infoResult.Color = this.brush[x, y];
-
- float distanceWAway = 0;
-
- if (info.DistanceFromPath < this.halfWidth)
- {
- // inside strip
- distanceWAway = 0;
- }
- else
- {
- distanceWAway = info.DistanceFromPath - this.halfWidth;
- }
-
- for (int i = 0; i < this.pattern.Length - 1; i++)
- {
- float start = this.pattern[i];
- float end = this.pattern[i + 1];
-
- if (length >= start && length < end)
- {
- // in section
- if (i % 2 == 0)
- {
- // solid part return the maxDistance
- infoResult.DistanceFromElement = distanceWAway;
- return infoResult;
- }
- else
- {
- // this is a none solid part
- float distanceFromStart = length - start;
- float distanceFromEnd = end - length;
-
- float closestEdge = MathF.Min(distanceFromStart, distanceFromEnd);
-
- float distanceAcross = closestEdge;
-
- if (distanceWAway > 0)
- {
- infoResult.DistanceFromElement = new Vector2(distanceAcross, distanceWAway).Length();
- }
- else
- {
- infoResult.DistanceFromElement = closestEdge;
- }
-
- return infoResult;
- }
- }
- }
-
- return infoResult;
- }
- }
+ ///
+ public ReadOnlySpan StrokePattern => this.pattern;
}
}
diff --git a/src/ImageSharp.Drawing/Pens/Processors/ColoredPointInfo.cs b/src/ImageSharp.Drawing/Pens/Processors/ColoredPointInfo.cs
deleted file mode 100644
index 65a8a61319..0000000000
--- a/src/ImageSharp.Drawing/Pens/Processors/ColoredPointInfo.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Drawing.Processors
-{
- using ImageSharp.PixelFormats;
-
- ///
- /// Returns details about how far away from the inside of a shape and the color the pixel could be.
- ///
- /// The type of the color.
- public struct ColoredPointInfo
- where TPixel : struct, IPixel
- {
- ///
- /// The color
- ///
- public TPixel Color;
-
- ///
- /// The distance from element
- ///
- public float DistanceFromElement;
- }
-}
diff --git a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs
deleted file mode 100644
index ac18890685..0000000000
--- a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Drawing.Processors
-{
- using System;
- using ImageSharp.PixelFormats;
-
- ///
- /// primitive that converts a into a color and a distance away from the drawable part of the path.
- ///
- /// The type of the color.
- public abstract class PenApplicator : IDisposable
- where TPixel : struct, IPixel
- {
- ///
- /// Gets the required region.
- ///
- ///
- /// The required region.
- ///
- public abstract RectangleF RequiredRegion { get; }
-
- ///
- public abstract void Dispose();
-
- ///
- /// Gets a from a point represented by a .
- ///
- /// The x.
- /// The y.
- /// The information to extract color details about.
- ///
- /// Returns the color details and distance from a solid bit of the line.
- ///
- public abstract ColoredPointInfo GetColor(int x, int y, PointInfo info);
- }
-}
diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
deleted file mode 100644
index 860c4c4f06..0000000000
--- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Drawing.Processors
-{
- using System;
- using System.Numerics;
- using System.Threading.Tasks;
-
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
- using ImageSharp.Processing;
- using Pens;
-
- ///
- /// Draws a path using the processor pipeline
- ///
- /// The type of the color.
- ///
- internal class DrawPathProcessor : ImageProcessor
- where TPixel : struct, IPixel
- {
- private const float AntialiasFactor = 1f;
- private const int PaddingFactor = 1; // needs to been the same or greater than AntialiasFactor
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The details how to draw the outline/path.
- /// The details of the paths and outlines to draw.
- /// The drawing configuration options.
- public DrawPathProcessor(IPen pen, Drawable drawable, GraphicsOptions options)
- {
- this.Path = drawable;
- this.Pen = pen;
- this.Options = options;
- }
-
- ///
- /// Gets the graphics options.
- ///
- public GraphicsOptions Options { get; }
-
- ///
- /// Gets the pen.
- ///
- public IPen Pen { get; }
-
- ///
- /// Gets the path.
- ///
- public Drawable Path { get; }
-
- ///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
- {
- using (PenApplicator applicator = this.Pen.CreateApplicator(source, this.Path.Bounds, this.Options))
- {
- Rectangle rect = RectangleF.Ceiling(applicator.RequiredRegion);
-
- int polyStartY = rect.Y - PaddingFactor;
- int polyEndY = rect.Bottom + PaddingFactor;
- int startX = rect.X - PaddingFactor;
- int endX = rect.Right + PaddingFactor;
-
- int minX = Math.Max(sourceRectangle.Left, startX);
- int maxX = Math.Min(sourceRectangle.Right, endX);
- int minY = Math.Max(sourceRectangle.Top, polyStartY);
- int maxY = Math.Min(sourceRectangle.Bottom, polyEndY);
-
- // 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);
-
- // Reset offset if necessary.
- if (minX > 0)
- {
- startX = 0;
- }
-
- if (minY > 0)
- {
- polyStartY = 0;
- }
-
- int width = maxX - minX;
- PixelBlender blender = PixelOperations.Instance.GetPixelBlender(this.Options.BlenderMode);
-
- Parallel.For(
- minY,
- maxY,
- this.ParallelOptions,
- y =>
- {
- int offsetY = y - polyStartY;
-
- using (var amount = new Buffer(width))
- using (var colors = new Buffer(width))
- {
- for (int i = 0; i < width; i++)
- {
- int x = i + minX;
- int offsetX = x - startX;
- PointInfo info = this.Path.GetPointInfo(offsetX, offsetY);
- ColoredPointInfo color = applicator.GetColor(offsetX, offsetY, info);
- amount[i] = (this.Opacity(color.DistanceFromElement) * this.Options.BlendPercentage).Clamp(0, 1);
- colors[i] = color.Color;
- }
-
- Span destination = source.GetRowSpan(offsetY).Slice(minX - startX, width);
- blender.Blend(destination, destination, colors, amount);
- }
- });
- }
- }
-
- ///
- /// Returns the correct opacity for the given distance.
- ///
- /// Thw distance from the central point.
- /// The
- private float Opacity(float distance)
- {
- if (distance <= 0)
- {
- return 1;
- }
-
- if (this.Options.Antialias && distance < AntialiasFactor)
- {
- return 1 - (distance / AntialiasFactor);
- }
-
- return 0;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
index ae828e112c..f2e09d2897 100644
--- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
@@ -93,6 +93,7 @@ namespace ImageSharp.Drawing.Processors
using (BrushApplicator applicator = this.Brush.CreateApplicator(source, rect, this.Options))
{
float[] buffer = arrayPool.Rent(maxIntersections);
+ Span bufferSpan = buffer.AsSpan().Slice(0, maxIntersections);
int scanlineWidth = maxX - minX;
using (var scanline = new Buffer(scanlineWidth))
{
@@ -116,14 +117,14 @@ namespace ImageSharp.Drawing.Processors
float subpixelFractionPoint = subpixelFraction / subpixelCount;
for (float subPixel = (float)y; subPixel < y + 1; subPixel += subpixelFraction)
{
- int pointsFound = region.Scan(subPixel, buffer, maxIntersections, 0);
+ int pointsFound = region.Scan(subPixel, bufferSpan);
if (pointsFound == 0)
{
// nothing on this line skip
continue;
}
- QuickSort(buffer, pointsFound);
+ QuickSort(bufferSpan.Slice(0, pointsFound));
for (int point = 0; point < pointsFound; point += 2)
{
@@ -153,13 +154,11 @@ namespace ImageSharp.Drawing.Processors
int nextX = startX + 1;
endX = Math.Min(endX, scanline.Length); // reduce to end to the right edge
- if (nextX >= 0)
+ nextX = Math.Max(nextX, 0);
+ for (int x = nextX; x < endX; x++)
{
- for (int x = nextX; x < endX; x++)
- {
- scanline[x] += subpixelFraction;
- scanlineDirty = true;
- }
+ scanline[x] += subpixelFraction;
+ scanlineDirty = true;
}
}
}
@@ -194,20 +193,20 @@ namespace ImageSharp.Drawing.Processors
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void Swap(float[] data, int left, int right)
+ private static void Swap(Span data, int left, int right)
{
float tmp = data[left];
data[left] = data[right];
data[right] = tmp;
}
- private static void QuickSort(float[] data, int size)
+ private static void QuickSort(Span data)
{
- int hi = Math.Min(data.Length - 1, size - 1);
+ int hi = Math.Min(data.Length - 1, data.Length - 1);
QuickSort(data, 0, hi);
}
- private static void QuickSort(float[] data, int lo, int hi)
+ private static void QuickSort(Span data, int lo, int hi)
{
if (lo < hi)
{
@@ -217,7 +216,7 @@ namespace ImageSharp.Drawing.Processors
}
}
- private static int Partition(float[] data, int lo, int hi)
+ private static int Partition(Span data, int lo, int hi)
{
float pivot = data[lo];
int i = lo - 1;
diff --git a/src/ImageSharp.Drawing/Region.cs b/src/ImageSharp.Drawing/Region.cs
index 8cab885021..687ee23fdd 100644
--- a/src/ImageSharp.Drawing/Region.cs
+++ b/src/ImageSharp.Drawing/Region.cs
@@ -5,6 +5,8 @@
namespace ImageSharp.Drawing
{
+ using System;
+
///
/// Represents a region of an image.
///
@@ -19,7 +21,7 @@ namespace ImageSharp.Drawing
/// Gets the bounding box that entirely surrounds this region.
///
///
- /// This should always contains all possible points returned from .
+ /// This should always contains all possible points returned from .
///
public abstract Rectangle Bounds { get; }
@@ -28,9 +30,7 @@ namespace ImageSharp.Drawing
///
/// The position along the y axis to find intersections.
/// The buffer.
- /// The length.
- /// The offset.
/// The number of intersections found.
- public abstract int Scan(float y, float[] buffer, int length, int offset);
+ public abstract int Scan(float y, Span buffer);
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Text/DrawText.Path.cs b/src/ImageSharp.Drawing/Text/DrawText.Path.cs
new file mode 100644
index 0000000000..2bc23b64bc
--- /dev/null
+++ b/src/ImageSharp.Drawing/Text/DrawText.Path.cs
@@ -0,0 +1,200 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System.Numerics;
+
+ using Drawing;
+ using Drawing.Brushes;
+ using Drawing.Pens;
+ using ImageSharp.PixelFormats;
+ using SixLabors.Fonts;
+ using SixLabors.Shapes;
+
+ ///
+ /// Extension methods for the type.
+ ///
+ public static partial class ImageExtensions
+ {
+ ///
+ /// Draws the text onto the the image filled via the brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The color.
+ /// The path.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, TPixel color, IPath path)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, color, path, TextGraphicsOptions.Default);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The color.
+ /// The path.
+ /// The options.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, TPixel color, IPath path, TextGraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, Brushes.Solid(color), null, path, options);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The brush.
+ /// The location.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPath path)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, brush, path, TextGraphicsOptions.Default);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The brush.
+ /// The path.
+ /// The options.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPath path, TextGraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, brush, null, path, options);
+ }
+
+ ///
+ /// Draws the text onto the the image outlined via the pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The pen.
+ /// The path.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IPen pen, IPath path)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, pen, path, TextGraphicsOptions.Default);
+ }
+
+ ///
+ /// Draws the text onto the the image outlined via the pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The pen.
+ /// The path.
+ /// The options.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IPen pen, IPath path, TextGraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, null, pen, path, options);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush then outlined via the pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The brush.
+ /// The pen.
+ /// The path.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, IPath path)
+ where TPixel : struct, IPixel
+ {
+ return source.DrawText(text, font, brush, pen, path, TextGraphicsOptions.Default);
+ }
+
+ ///
+ /// Draws the text onto the the image filled via the brush then outlined via the pen.
+ ///
+ /// The type of the color.
+ /// The image this method extends.
+ /// The text.
+ /// The font.
+ /// The brush.
+ /// The pen.
+ /// The path.
+ /// The options.
+ ///
+ /// The .
+ ///
+ public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, IPath path, TextGraphicsOptions options)
+ where TPixel : struct, IPixel
+ {
+ Vector2 dpi = DefaultTextDpi;
+ if (options.UseImageResolution)
+ {
+ dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution);
+ }
+
+ var style = new FontSpan(font, dpi)
+ {
+ ApplyKerning = options.ApplyKerning,
+ TabWidth = options.TabWidth,
+ WrappingWidth = options.WrapTextWidth,
+ HorizontalAlignment = options.HorizontalAlignment,
+ VerticalAlignment = options.VerticalAlignment
+ };
+
+ IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, path, style);
+
+ var pathOptions = (GraphicsOptions)options;
+ if (brush != null)
+ {
+ source.Fill(brush, glyphs, pathOptions);
+ }
+
+ if (pen != null)
+ {
+ source.Draw(pen, glyphs, pathOptions);
+ }
+
+ return source;
+ }
+ }
+}
diff --git a/src/ImageSharp.Drawing/Text/DrawText.cs b/src/ImageSharp.Drawing/Text/DrawText.cs
index bd33289fa6..3b0d3db411 100644
--- a/src/ImageSharp.Drawing/Text/DrawText.cs
+++ b/src/ImageSharp.Drawing/Text/DrawText.cs
@@ -12,6 +12,7 @@ namespace ImageSharp
using Drawing.Pens;
using ImageSharp.PixelFormats;
using SixLabors.Fonts;
+ using SixLabors.Shapes;
///
/// Extension methods for the type.
@@ -167,43 +168,32 @@ namespace ImageSharp
public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, Vector2 location, TextGraphicsOptions options)
where TPixel : struct, IPixel
{
- GlyphBuilder glyphBuilder = new GlyphBuilder(location);
-
- TextRenderer renderer = new TextRenderer(glyphBuilder);
-
Vector2 dpi = DefaultTextDpi;
if (options.UseImageResolution)
{
dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution);
}
- FontSpan style = new FontSpan(font, dpi)
+ var style = new FontSpan(font, dpi)
{
ApplyKerning = options.ApplyKerning,
TabWidth = options.TabWidth,
WrappingWidth = options.WrapTextWidth,
- Alignment = options.TextAlignment
+ HorizontalAlignment = options.HorizontalAlignment,
+ VerticalAlignment = options.VerticalAlignment
};
- renderer.RenderText(text, style);
-
- System.Collections.Generic.IEnumerable shapesToDraw = glyphBuilder.Paths;
+ IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, location, style);
- GraphicsOptions pathOptions = (GraphicsOptions)options;
+ var pathOptions = (GraphicsOptions)options;
if (brush != null)
{
- foreach (SixLabors.Shapes.IPath s in shapesToDraw)
- {
- source.Fill(brush, s, pathOptions);
- }
+ source.Fill(brush, glyphs, pathOptions);
}
if (pen != null)
{
- foreach (SixLabors.Shapes.IPath s in shapesToDraw)
- {
- source.Draw(pen, s, pathOptions);
- }
+ source.Draw(pen, glyphs, pathOptions);
}
return source;
diff --git a/src/ImageSharp.Drawing/Text/GlyphBuilder.cs b/src/ImageSharp.Drawing/Text/GlyphBuilder.cs
deleted file mode 100644
index 0033a608c3..0000000000
--- a/src/ImageSharp.Drawing/Text/GlyphBuilder.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Drawing
-{
- using System.Collections.Generic;
- using System.Numerics;
-
- using SixLabors.Fonts;
- using SixLabors.Shapes;
-
- ///
- /// rendering surface that Fonts can use to generate Shapes.
- ///
- internal class GlyphBuilder : IGlyphRenderer
- {
- private readonly PathBuilder builder = new PathBuilder();
- private readonly List paths = new List();
- private Vector2 currentPoint = default(Vector2);
-
- ///
- /// Initializes a new instance of the class.
- ///
- public GlyphBuilder()
- : this(Vector2.Zero)
- {
- // glyphs are renderd realative to bottom left so invert the Y axis to allow it to render on top left origin surface
- this.builder = new PathBuilder();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The origin.
- public GlyphBuilder(Vector2 origin)
- {
- this.builder = new PathBuilder();
- this.builder.SetOrigin(origin);
- }
-
- ///
- /// Gets the paths that have been rendered by this.
- ///
- public IEnumerable Paths => this.paths;
-
- ///
- /// Begins the glyph.
- ///
- /// The offset that the glyph will be rendered at.
- void IGlyphRenderer.BeginGlyph(Vector2 location)
- {
- this.builder.Clear();
- }
-
- ///
- /// Begins the figure.
- ///
- void IGlyphRenderer.BeginFigure()
- {
- this.builder.StartFigure();
- }
-
- ///
- /// Draws a cubic bezier from the current point to the
- ///
- /// The second control point.
- /// The third control point.
- /// The point.
- void IGlyphRenderer.CubicBezierTo(Vector2 secondControlPoint, Vector2 thirdControlPoint, Vector2 point)
- {
- this.builder.AddBezier(this.currentPoint, secondControlPoint, thirdControlPoint, point);
- this.currentPoint = point;
- }
-
- ///
- /// Ends the glyph.
- ///
- void IGlyphRenderer.EndGlyph()
- {
- this.paths.Add(this.builder.Build());
- }
-
- ///
- /// Ends the figure.
- ///
- void IGlyphRenderer.EndFigure()
- {
- this.builder.CloseFigure();
- }
-
- ///
- /// Draws a line from the current point to the .
- ///
- /// The point.
- void IGlyphRenderer.LineTo(Vector2 point)
- {
- this.builder.AddLine(this.currentPoint, point);
- this.currentPoint = point;
- }
-
- ///
- /// Moves to current point to the supplied vector.
- ///
- /// The point.
- void IGlyphRenderer.MoveTo(Vector2 point)
- {
- this.builder.StartFigure();
- this.currentPoint = point;
- }
-
- ///
- /// Draws a quadratics bezier from the current point to the
- ///
- /// The second control point.
- /// The point.
- void IGlyphRenderer.QuadraticBezierTo(Vector2 secondControlPoint, Vector2 point)
- {
- Vector2 c1 = (((secondControlPoint - this.currentPoint) * 2) / 3) + this.currentPoint;
- Vector2 c2 = (((secondControlPoint - point) * 2) / 3) + point;
-
- this.builder.AddBezier(this.currentPoint, c1, c2, point);
- this.currentPoint = point;
- }
- }
-}
diff --git a/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
index 388b39bcc5..593ac36d4f 100644
--- a/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
+++ b/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
@@ -33,7 +33,8 @@ namespace ImageSharp.Drawing
private float wrapTextWidth;
- private SixLabors.Fonts.TextAlignment? textAlignment;
+ private SixLabors.Fonts.HorizontalAlignment? horizontalAlignment;
+ private SixLabors.Fonts.VerticalAlignment? verticalAlignment;
///
/// Initializes a new instance of the struct.
@@ -45,7 +46,8 @@ namespace ImageSharp.Drawing
this.tabWidth = 4;
this.useImageResolution = false;
this.wrapTextWidth = 0;
- this.textAlignment = SixLabors.Fonts.TextAlignment.Left;
+ this.horizontalAlignment = HorizontalAlignment.Left;
+ this.verticalAlignment = VerticalAlignment.Top;
this.antialiasSubpixelDepth = 16;
this.blenderMode = PixelBlenderMode.Normal;
@@ -104,7 +106,12 @@ namespace ImageSharp.Drawing
/// defined by the location and width, if equals zero, and thus
/// wrapping disabled, then the alignment is relative to the drawing location.
///
- public TextAlignment TextAlignment { get => this.textAlignment ?? TextAlignment.Left; set => this.textAlignment = value; }
+ public HorizontalAlignment HorizontalAlignment { get => this.horizontalAlignment ?? HorizontalAlignment.Left; set => this.horizontalAlignment = value; }
+
+ ///
+ /// Gets or sets a value indicating how to align the text relative to the rendering space.
+ ///
+ public VerticalAlignment VerticalAlignment { get => this.verticalAlignment ?? VerticalAlignment.Top; set => this.verticalAlignment = value; }
///
/// Performs an implicit conversion from to .
diff --git a/src/ImageSharp/Common/Extensions/ByteExtensions.cs b/src/ImageSharp/Common/Extensions/ByteExtensions.cs
index a6dc19ded4..f1161eb6f6 100644
--- a/src/ImageSharp/Common/Extensions/ByteExtensions.cs
+++ b/src/ImageSharp/Common/Extensions/ByteExtensions.cs
@@ -5,10 +5,13 @@
namespace ImageSharp
{
+ using System;
using System.Runtime.CompilerServices;
+ using ImageSharp.PixelFormats;
+
///
- /// Extension methods for the struct.
+ /// Extension methods for the struct buffers.
///
internal static class ByteExtensions
{
@@ -44,5 +47,45 @@ namespace ImageSharp
j--;
}
}
+
+ ///
+ /// Returns a reference to the given position of the array unsafe casted to .
+ ///
+ /// The byte array.
+ /// The offset in bytes.
+ /// The reference at the given offset.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref Rgb24 GetRgb24(this byte[] bytes, int offset)
+ {
+ DebugGuard.MustBeLessThan(offset + 2, bytes.Length, nameof(offset));
+
+ return ref Unsafe.As(ref bytes[offset]);
+ }
+
+ ///
+ /// Returns a reference to the given position of the span unsafe casted to .
+ ///
+ /// The byte span.
+ /// The offset in bytes.
+ /// The reference at the given offset.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref Rgb24 GetRgb24(this Span bytes, int offset)
+ {
+ DebugGuard.MustBeLessThan(offset + 2, bytes.Length, nameof(offset));
+
+ return ref Unsafe.As(ref bytes[offset]);
+ }
+
+ ///
+ /// Returns a reference to the given position of the buffer pointed by `baseRef` unsafe casted to .
+ ///
+ /// A reference to the beginning of the buffer
+ /// The offset in bytes.
+ /// The reference at the given offset.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref Rgb24 GetRgb24(ref byte baseRef, int offset)
+ {
+ return ref Unsafe.As(ref Unsafe.Add(ref baseRef, offset));
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs
index a4b392fcf1..8e55c18af8 100644
--- a/src/ImageSharp/Common/Helpers/Guard.cs
+++ b/src/ImageSharp/Common/Helpers/Guard.cs
@@ -242,7 +242,6 @@ namespace ImageSharp
/// is true
///
public static void MustBeSizedAtLeast(Span target, int minLength, string parameterName)
- where T : struct
{
if (target.Length < minLength)
{
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index dd91aa11d9..997a77d6c5 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -6,7 +6,8 @@ namespace ImageSharp.Formats
{
using System;
using System.IO;
-
+ using System.Runtime.CompilerServices;
+ using ImageSharp.Memory;
using ImageSharp.PixelFormats;
///
@@ -243,13 +244,16 @@ namespace ImageSharp.Formats
byte[] row = new byte[arrayWidth + padding];
TPixel color = default(TPixel);
+ Rgba32 rgba = default(Rgba32);
+
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
-
this.currentStream.Read(row, 0, row.Length);
-
int offset = 0;
+ Span pixelRow = pixels.GetRowSpan(y);
+
+ // TODO: Could use PixelOperations here!
for (int x = 0; x < arrayWidth; x++)
{
int colOffset = x * ppb;
@@ -260,8 +264,9 @@ namespace ImageSharp.Formats
int newX = colOffset + shift;
// Stored in b-> g-> r order.
- color.PackFromBytes(colors[colorIndex + 2], colors[colorIndex + 1], colors[colorIndex], 255);
- pixels[newX, newY] = color;
+ rgba.Bgr = Unsafe.As(ref colors[colorIndex]);
+ color.PackFromRgba32(rgba);
+ pixelRow[newX] = color;
}
offset++;
@@ -286,6 +291,8 @@ namespace ImageSharp.Formats
const int ComponentCount = 2;
TPixel color = default(TPixel);
+ Rgba32 rgba = new Rgba32(0, 0, 0, 255);
+
using (PixelArea row = new PixelArea(width, ComponentOrder.Xyz))
{
for (int y = 0; y < height; y++)
@@ -294,17 +301,19 @@ namespace ImageSharp.Formats
int newY = Invert(y, height, inverted);
+ Span pixelRow = pixels.GetRowSpan(newY);
+
int offset = 0;
for (int x = 0; x < width; x++)
{
short temp = BitConverter.ToInt16(row.Bytes, offset);
- byte r = (byte)(((temp & Rgb16RMask) >> 11) * ScaleR);
- byte g = (byte)(((temp & Rgb16GMask) >> 5) * ScaleG);
- byte b = (byte)((temp & Rgb16BMask) * ScaleR);
+ rgba.R = (byte)(((temp & Rgb16RMask) >> 11) * ScaleR);
+ rgba.G = (byte)(((temp & Rgb16GMask) >> 5) * ScaleG);
+ rgba.B = (byte)((temp & Rgb16BMask) * ScaleR);
- color.PackFromBytes(r, g, b, 255);
- pixels[x, newY] = color;
+ color.PackFromRgba32(rgba);
+ pixelRow[x] = color;
offset += ComponentCount;
}
}
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 618d268f70..5b56c4c02f 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -435,6 +435,8 @@ namespace ImageSharp.Formats
Span rowSpan = image.GetRowSpan(writeY);
+ Rgba32 rgba = new Rgba32(0, 0, 0, 255);
+
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
{
int index = indices[i];
@@ -446,7 +448,9 @@ namespace ImageSharp.Formats
int indexOffset = index * 3;
ref TPixel pixel = ref rowSpan[x];
- pixel.PackFromBytes(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2], 255);
+ rgba.Rgb = colorTable.GetRgb24(indexOffset);
+
+ pixel.PackFromRgba32(rgba);
}
i++;
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
index 211b66dacc..f84dc977f1 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
@@ -5,53 +5,120 @@
// ReSharper disable InconsistentNaming
//
#pragma warning disable
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-
-
namespace ImageSharp.Formats.Jpg
{
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+
internal partial struct Block8x8F
{
- private static readonly Vector4 CMin4 = new Vector4(-128f);
- private static readonly Vector4 CMax4 = new Vector4(127f);
- private static readonly Vector4 COff4 = new Vector4(128f);
+ private static readonly Vector4 CMin4 = new Vector4(0F);
+ private static readonly Vector4 CMax4 = new Vector4(255F);
+ private static readonly Vector4 COff4 = new Vector4(128F);
///
- /// Transpose the block into d
+ /// Transpose the block into the destination block.
///
- /// Destination
+ /// The destination block
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void TransposeInto(ref Block8x8F d)
{
- d.V0L.X = V0L.X; d.V1L.X = V0L.Y; d.V2L.X = V0L.Z; d.V3L.X = V0L.W; d.V4L.X = V0R.X; d.V5L.X = V0R.Y; d.V6L.X = V0R.Z; d.V7L.X = V0R.W;
- d.V0L.Y = V1L.X; d.V1L.Y = V1L.Y; d.V2L.Y = V1L.Z; d.V3L.Y = V1L.W; d.V4L.Y = V1R.X; d.V5L.Y = V1R.Y; d.V6L.Y = V1R.Z; d.V7L.Y = V1R.W;
- d.V0L.Z = V2L.X; d.V1L.Z = V2L.Y; d.V2L.Z = V2L.Z; d.V3L.Z = V2L.W; d.V4L.Z = V2R.X; d.V5L.Z = V2R.Y; d.V6L.Z = V2R.Z; d.V7L.Z = V2R.W;
- d.V0L.W = V3L.X; d.V1L.W = V3L.Y; d.V2L.W = V3L.Z; d.V3L.W = V3L.W; d.V4L.W = V3R.X; d.V5L.W = V3R.Y; d.V6L.W = V3R.Z; d.V7L.W = V3R.W;
- d.V0R.X = V4L.X; d.V1R.X = V4L.Y; d.V2R.X = V4L.Z; d.V3R.X = V4L.W; d.V4R.X = V4R.X; d.V5R.X = V4R.Y; d.V6R.X = V4R.Z; d.V7R.X = V4R.W;
- d.V0R.Y = V5L.X; d.V1R.Y = V5L.Y; d.V2R.Y = V5L.Z; d.V3R.Y = V5L.W; d.V4R.Y = V5R.X; d.V5R.Y = V5R.Y; d.V6R.Y = V5R.Z; d.V7R.Y = V5R.W;
- d.V0R.Z = V6L.X; d.V1R.Z = V6L.Y; d.V2R.Z = V6L.Z; d.V3R.Z = V6L.W; d.V4R.Z = V6R.X; d.V5R.Z = V6R.Y; d.V6R.Z = V6R.Z; d.V7R.Z = V6R.W;
- d.V0R.W = V7L.X; d.V1R.W = V7L.Y; d.V2R.W = V7L.Z; d.V3R.W = V7L.W; d.V4R.W = V7R.X; d.V5R.W = V7R.Y; d.V6R.W = V7R.Z; d.V7R.W = V7R.W;
+ d.V0L.X = V0L.X;
+ d.V1L.X = V0L.Y;
+ d.V2L.X = V0L.Z;
+ d.V3L.X = V0L.W;
+ d.V4L.X = V0R.X;
+ d.V5L.X = V0R.Y;
+ d.V6L.X = V0R.Z;
+ d.V7L.X = V0R.W;
+
+ d.V0L.Y = V1L.X;
+ d.V1L.Y = V1L.Y;
+ d.V2L.Y = V1L.Z;
+ d.V3L.Y = V1L.W;
+ d.V4L.Y = V1R.X;
+ d.V5L.Y = V1R.Y;
+ d.V6L.Y = V1R.Z;
+ d.V7L.Y = V1R.W;
+
+ d.V0L.Z = V2L.X;
+ d.V1L.Z = V2L.Y;
+ d.V2L.Z = V2L.Z;
+ d.V3L.Z = V2L.W;
+ d.V4L.Z = V2R.X;
+ d.V5L.Z = V2R.Y;
+ d.V6L.Z = V2R.Z;
+ d.V7L.Z = V2R.W;
+
+ d.V0L.W = V3L.X;
+ d.V1L.W = V3L.Y;
+ d.V2L.W = V3L.Z;
+ d.V3L.W = V3L.W;
+ d.V4L.W = V3R.X;
+ d.V5L.W = V3R.Y;
+ d.V6L.W = V3R.Z;
+ d.V7L.W = V3R.W;
+
+ d.V0R.X = V4L.X;
+ d.V1R.X = V4L.Y;
+ d.V2R.X = V4L.Z;
+ d.V3R.X = V4L.W;
+ d.V4R.X = V4R.X;
+ d.V5R.X = V4R.Y;
+ d.V6R.X = V4R.Z;
+ d.V7R.X = V4R.W;
+
+ d.V0R.Y = V5L.X;
+ d.V1R.Y = V5L.Y;
+ d.V2R.Y = V5L.Z;
+ d.V3R.Y = V5L.W;
+ d.V4R.Y = V5R.X;
+ d.V5R.Y = V5R.Y;
+ d.V6R.Y = V5R.Z;
+ d.V7R.Y = V5R.W;
+
+ d.V0R.Z = V6L.X;
+ d.V1R.Z = V6L.Y;
+ d.V2R.Z = V6L.Z;
+ d.V3R.Z = V6L.W;
+ d.V4R.Z = V6R.X;
+ d.V5R.Z = V6R.Y;
+ d.V6R.Z = V6R.Z;
+ d.V7R.Z = V6R.W;
+
+ d.V0R.W = V7L.X;
+ d.V1R.W = V7L.Y;
+ d.V2R.W = V7L.Z;
+ d.V3R.W = V7L.W;
+ d.V4R.W = V7R.X;
+ d.V5R.W = V7R.Y;
+ d.V6R.W = V7R.Z;
+ d.V7R.W = V7R.W;
}
///
/// Level shift by +128, clip to [0, 255]
///
- /// Destination
+ /// The destination block
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void TransformByteConvetibleColorValuesInto(ref Block8x8F d)
{
- d.V0L = Vector4.Max(Vector4.Min(V0L, CMax4), CMin4) + COff4;d.V0R = Vector4.Max(Vector4.Min(V0R, CMax4), CMin4) + COff4;
- d.V1L = Vector4.Max(Vector4.Min(V1L, CMax4), CMin4) + COff4;d.V1R = Vector4.Max(Vector4.Min(V1R, CMax4), CMin4) + COff4;
- d.V2L = Vector4.Max(Vector4.Min(V2L, CMax4), CMin4) + COff4;d.V2R = Vector4.Max(Vector4.Min(V2R, CMax4), CMin4) + COff4;
- d.V3L = Vector4.Max(Vector4.Min(V3L, CMax4), CMin4) + COff4;d.V3R = Vector4.Max(Vector4.Min(V3R, CMax4), CMin4) + COff4;
- d.V4L = Vector4.Max(Vector4.Min(V4L, CMax4), CMin4) + COff4;d.V4R = Vector4.Max(Vector4.Min(V4R, CMax4), CMin4) + COff4;
- d.V5L = Vector4.Max(Vector4.Min(V5L, CMax4), CMin4) + COff4;d.V5R = Vector4.Max(Vector4.Min(V5R, CMax4), CMin4) + COff4;
- d.V6L = Vector4.Max(Vector4.Min(V6L, CMax4), CMin4) + COff4;d.V6R = Vector4.Max(Vector4.Min(V6R, CMax4), CMin4) + COff4;
- d.V7L = Vector4.Max(Vector4.Min(V7L, CMax4), CMin4) + COff4;d.V7R = Vector4.Max(Vector4.Min(V7R, CMax4), CMin4) + COff4;
+ d.V0L = Vector4.Clamp(V0L + COff4, CMin4, CMax4);
+ d.V0R = Vector4.Clamp(V0R + COff4, CMin4, CMax4);
+ d.V1L = Vector4.Clamp(V1L + COff4, CMin4, CMax4);
+ d.V1R = Vector4.Clamp(V1R + COff4, CMin4, CMax4);
+ d.V2L = Vector4.Clamp(V2L + COff4, CMin4, CMax4);
+ d.V2R = Vector4.Clamp(V2R + COff4, CMin4, CMax4);
+ d.V3L = Vector4.Clamp(V3L + COff4, CMin4, CMax4);
+ d.V3R = Vector4.Clamp(V3R + COff4, CMin4, CMax4);
+ d.V4L = Vector4.Clamp(V4L + COff4, CMin4, CMax4);
+ d.V4R = Vector4.Clamp(V4R + COff4, CMin4, CMax4);
+ d.V5L = Vector4.Clamp(V5L + COff4, CMin4, CMax4);
+ d.V5R = Vector4.Clamp(V5R + COff4, CMin4, CMax4);
+ d.V6L = Vector4.Clamp(V6L + COff4, CMin4, CMax4);
+ d.V6R = Vector4.Clamp(V6R + COff4, CMin4, CMax4);
+ d.V7L = Vector4.Clamp(V7L + COff4, CMin4, CMax4);
+ d.V7R = Vector4.Clamp(V7R + COff4, CMin4, CMax4);
}
-
-
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
index be198a6fa7..03566acbbc 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
@@ -11,31 +11,29 @@
<#@ output extension=".cs" #>
//
#pragma warning disable
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-
<#
char[] coordz = {'X', 'Y', 'Z', 'W'};
#>
-
namespace ImageSharp.Formats.Jpg
{
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+
internal partial struct Block8x8F
{
- private static readonly Vector4 CMin4 = new Vector4(-128f);
- private static readonly Vector4 CMax4 = new Vector4(127f);
- private static readonly Vector4 COff4 = new Vector4(128f);
+ private static readonly Vector4 CMin4 = new Vector4(0F);
+ private static readonly Vector4 CMax4 = new Vector4(255F);
+ private static readonly Vector4 COff4 = new Vector4(128F);
///
- /// Transpose the block into d
+ /// Transpose the block into the destination block.
///
- /// Destination
+ /// The destination block
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void TransposeInto(ref Block8x8F d)
{
<#
- PushIndent(" ");
+ PushIndent(" ");
for (int i = 0; i < 8; i++)
{
@@ -44,13 +42,16 @@ namespace ImageSharp.Formats.Jpg
for (int j = 0; j < 8; j++)
{
+ if(i > 0 && j == 0){
+ WriteLine("");
+ }
+
char srcCoord = coordz[j % 4];
char srcSide = (j / 4) % 2 == 0 ? 'L' : 'R';
-
- string expression = $"d.V{j}{destSide}.{destCoord} = V{i}{srcSide}.{srcCoord}; ";
+
+ string expression = $"d.V{j}{destSide}.{destCoord} = V{i}{srcSide}.{srcCoord};\r\n";
Write(expression);
}
- WriteLine("");
}
PopIndent();
#>
@@ -59,27 +60,24 @@ namespace ImageSharp.Formats.Jpg
///
/// Level shift by +128, clip to [0, 255]
///
- /// Destination
+ /// The destination block
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void TransformByteConvetibleColorValuesInto(ref Block8x8F d)
{
<#
- PushIndent(" ");
+ PushIndent(" ");
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 2; j++)
{
char side = j == 0 ? 'L' : 'R';
- Write($"d.V{i}{side} = Vector4.Max(Vector4.Min(V{i}{side}, CMax4), CMin4) + COff4;");
+ Write($"d.V{i}{side} = Vector4.Clamp(V{i}{side} + COff4, CMin4, CMax4);\r\n");
}
- WriteLine("");
}
PopIndent();
#>
}
-
-
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
index 56466d7a0f..130b5856c0 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
@@ -57,6 +57,9 @@ namespace ImageSharp.Formats.Jpg
public Vector4 V7R;
#pragma warning restore SA1600 // ElementsMustBeDocumented
+ private static readonly Vector4 NegativeOne = new Vector4(-1);
+ private static readonly Vector4 Offset = new Vector4(.5F);
+
///
/// Get/Set scalar elements at a given index
///
@@ -402,12 +405,11 @@ namespace ImageSharp.Formats.Jpg
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor)
{
- // sign(v) = max(min(v, 1), -1)
- Vector4 sign = Vector4.Min(dividend, Vector4.One);
- sign = Vector4.Max(sign, new Vector4(-1));
+ // sign(dividend) = max(min(dividend, 1), -1)
+ var sign = Vector4.Clamp(dividend, NegativeOne, Vector4.One);
// AlmostRound(dividend/divisor) = dividend/divisior + 0.5*sign(dividend)
- return (dividend / divisor) + (sign * new Vector4(0.5f));
+ return (dividend / divisor) + (sign * Offset);
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrToRgbTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrToRgbTables.cs
index 27324b5f68..5c9e8f9fc3 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrToRgbTables.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrToRgbTables.cs
@@ -91,7 +91,7 @@ namespace ImageSharp.Formats.Jpg
// float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero);
byte b = (byte)(y + tables->CbBTable[cb]).Clamp(0, 255);
- packed.PackFromBytes(r, g, b, byte.MaxValue);
+ packed.PackFromRgba32(new Rgba32(r, g, b, 255));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index 13c51db243..9716843719 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -613,25 +613,23 @@ namespace ImageSharp.Formats
private void ConvertFromGrayScale(Image image)
where TPixel : struct, IPixel
{
- using (PixelAccessor pixels = image.Lock())
- {
- Parallel.For(
- 0,
- image.Height,
- image.Configuration.ParallelOptions,
- y =>
+ Parallel.For(
+ 0,
+ image.Height,
+ image.Configuration.ParallelOptions,
+ y =>
{
+ ref TPixel pixelRowBaseRef = ref image.GetPixelReference(0, y);
+
int yoff = this.grayImage.GetRowOffset(y);
+
for (int x = 0; x < image.Width; x++)
{
byte rgb = this.grayImage.Pixels[yoff + x];
-
- TPixel packed = default(TPixel);
- packed.PackFromBytes(rgb, rgb, rgb, 255);
- pixels[x, y] = packed;
+ ref TPixel pixel = ref Unsafe.Add(ref pixelRowBaseRef, x);
+ pixel.PackFromRgba32(new Rgba32(rgb, rgb, rgb, 255));
}
});
- }
this.AssignResolution(image);
}
@@ -646,30 +644,29 @@ namespace ImageSharp.Formats
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
- using (PixelAccessor pixels = image.Lock())
- {
- Parallel.For(
- 0,
- image.Height,
- image.Configuration.ParallelOptions,
- y =>
+ Parallel.For(
+ 0,
+ image.Height,
+ image.Configuration.ParallelOptions,
+ y =>
{
// TODO: Simplify + optimize + share duplicate code across converter methods
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
+ ref TPixel pixelRowBaseRef = ref image.GetPixelReference(0, y);
+
+ Rgba32 rgba = new Rgba32(0, 0, 0, 255);
for (int x = 0; x < image.Width; x++)
{
- byte red = this.ycbcrImage.YChannel[yo + x];
- byte green = this.ycbcrImage.CbChannel[co + (x / scale)];
- byte blue = this.ycbcrImage.CrChannel[co + (x / scale)];
+ rgba.R = this.ycbcrImage.YChannel[yo + x];
+ rgba.G = this.ycbcrImage.CbChannel[co + (x / scale)];
+ rgba.B = this.ycbcrImage.CrChannel[co + (x / scale)];
- TPixel packed = default(TPixel);
- packed.PackFromBytes(red, green, blue, 255);
- pixels[x, y] = packed;
+ ref TPixel pixel = ref Unsafe.Add(ref pixelRowBaseRef, x);
+ pixel.PackFromRgba32(rgba);
}
});
- }
this.AssignResolution(image);
}
@@ -729,16 +726,15 @@ namespace ImageSharp.Formats
{
int scale = this.ComponentArray[0].HorizontalFactor / this.ComponentArray[1].HorizontalFactor;
- using (PixelAccessor pixels = image.Lock())
- {
- Parallel.For(
- 0,
- image.Height,
- y =>
+ Parallel.For(
+ 0,
+ image.Height,
+ y =>
{
// TODO: Simplify + optimize + share duplicate code across converter methods
int yo = this.ycbcrImage.GetRowYOffset(y);
int co = this.ycbcrImage.GetRowCOffset(y);
+ ref TPixel pixelRowBaseRef = ref image.GetPixelReference(0, y);
for (int x = 0; x < image.Width; x++)
{
@@ -746,12 +742,10 @@ namespace ImageSharp.Formats
byte cb = this.ycbcrImage.CbChannel[co + (x / scale)];
byte cr = this.ycbcrImage.CrChannel[co + (x / scale)];
- TPixel packed = default(TPixel);
- this.PackYcck(ref packed, yy, cb, cr, x, y);
- pixels[x, y] = packed;
+ ref TPixel pixel = ref Unsafe.Add(ref pixelRowBaseRef, x);
+ this.PackYcck(ref pixel, yy, cb, cr, x, y);
}
});
- }
this.AssignResolution(image);
}
@@ -860,7 +854,7 @@ namespace ImageSharp.Formats
byte g = (byte)(((m / 255F) * (1F - keyline)).Clamp(0, 1) * 255);
byte b = (byte)(((y / 255F) * (1F - keyline)).Clamp(0, 1) * 255);
- packed.PackFromBytes(r, g, b, 255);
+ packed.PackFromRgba32(new Rgba32(r, g, b));
}
///
@@ -904,7 +898,7 @@ namespace ImageSharp.Formats
byte g = (byte)(((1 - magenta) * (1 - keyline)).Clamp(0, 1) * 255);
byte b = (byte)(((1 - yellow) * (1 - keyline)).Clamp(0, 1) * 255);
- packed.PackFromBytes(r, g, b, 255);
+ packed.PackFromRgba32(new Rgba32(r, g, b));
}
///
@@ -982,6 +976,7 @@ namespace ImageSharp.Formats
byte[] identifier = new byte[Icclength];
this.InputProcessor.ReadFull(identifier, 0, Icclength);
+ remaining -= Icclength; // we have read it by this point
if (identifier[0] == 'I' &&
identifier[1] == 'C' &&
@@ -996,7 +991,6 @@ namespace ImageSharp.Formats
identifier[10] == 'E' &&
identifier[11] == '\0')
{
- remaining -= Icclength;
byte[] profile = new byte[remaining];
this.InputProcessor.ReadFull(profile, 0, remaining);
@@ -1009,6 +1003,11 @@ namespace ImageSharp.Formats
metadata.IccProfile.Extend(profile);
}
}
+ else
+ {
+ // not an ICC profile we can handle read the remaining so we can carry on and ignore this.
+ this.InputProcessor.Skip(remaining);
+ }
}
///
diff --git a/src/ImageSharp/Formats/Jpeg/itu-t81.pdf b/src/ImageSharp/Formats/Jpeg/itu-t81.pdf
new file mode 100644
index 0000000000..83fba254b4
Binary files /dev/null and b/src/ImageSharp/Formats/Jpeg/itu-t81.pdf differ
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index f8be0f6cc7..e0bd153e63 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -178,7 +178,7 @@ namespace ImageSharp.Formats
///
/// Thrown if the stream does not contain and end chunk.
///
- ///
+ ///
/// Thrown if the image is larger than the maximum allowable size.
///
/// The decoded image
@@ -189,7 +189,6 @@ namespace ImageSharp.Formats
this.currentStream = stream;
this.currentStream.Skip(8);
Image image = null;
- PixelAccessor pixels = null;
try
{
using (var deframeStream = new ZlibInflateStream(this.currentStream))
@@ -211,11 +210,11 @@ namespace ImageSharp.Formats
case PngChunkTypes.Data:
if (image == null)
{
- this.InitializeImage(metadata, out image, out pixels);
+ this.InitializeImage(metadata, out image);
}
deframeStream.AllocateNewBytes(currentChunk.Length);
- this.ReadScanlines(deframeStream.CompressedStream, pixels);
+ this.ReadScanlines(deframeStream.CompressedStream, image);
stream.Read(this.crcBuffer, 0, 4);
break;
case PngChunkTypes.Palette:
@@ -252,7 +251,6 @@ namespace ImageSharp.Formats
}
finally
{
- pixels?.Dispose();
this.scanline?.Dispose();
this.previousScanline?.Dispose();
}
@@ -324,8 +322,7 @@ namespace ImageSharp.Formats
/// The type the pixels will be
/// The metadata information for the image
/// The image that we will populate
- /// The pixel accessor
- private void InitializeImage(ImageMetaData metadata, out Image image, out PixelAccessor pixels)
+ private void InitializeImage(ImageMetaData metadata, out Image image)
where TPixel : struct, IPixel
{
if (this.header.Width > Image.MaxWidth || this.header.Height > Image.MaxHeight)
@@ -334,7 +331,6 @@ namespace ImageSharp.Formats
}
image = new Image(this.configuration, this.header.Width, this.header.Height, metadata);
- pixels = image.Lock();
this.bytesPerPixel = this.CalculateBytesPerPixel();
this.bytesPerScanline = this.CalculateScanlineLength(this.header.Width) + 1;
this.bytesPerSample = 1;
@@ -398,17 +394,17 @@ namespace ImageSharp.Formats
///
/// The pixel format.
/// The containing data.
- /// The pixel data.
- private void ReadScanlines(Stream dataStream, PixelAccessor pixels)
+ /// The pixel data.
+ private void ReadScanlines(Stream dataStream, Image image)
where TPixel : struct, IPixel
{
if (this.header.InterlaceMethod == PngInterlaceMode.Adam7)
{
- this.DecodeInterlacedPixelData(dataStream, pixels);
+ this.DecodeInterlacedPixelData(dataStream, image);
}
else
{
- this.DecodePixelData(dataStream, pixels);
+ this.DecodePixelData(dataStream, image);
}
}
@@ -417,8 +413,8 @@ namespace ImageSharp.Formats
///
/// The pixel format.
/// The compressed pixel data stream.
- /// The image pixel accessor.
- private void DecodePixelData(Stream compressedStream, PixelAccessor pixels)
+ /// The image to decode to.
+ private void DecodePixelData(Stream compressedStream, Image image)
where TPixel : struct, IPixel
{
while (this.currentRow < this.header.Height)
@@ -462,7 +458,7 @@ namespace ImageSharp.Formats
throw new ImageFormatException("Unknown filter type.");
}
- this.ProcessDefilteredScanline(this.scanline.Array, pixels);
+ this.ProcessDefilteredScanline(this.scanline.Array, image);
Swap(ref this.scanline, ref this.previousScanline);
this.currentRow++;
@@ -475,8 +471,8 @@ namespace ImageSharp.Formats
///
/// The pixel format.
/// The compressed pixel data stream.
- /// The image pixel accessor.
- private void DecodeInterlacedPixelData(Stream compressedStream, PixelAccessor pixels)
+ /// The current image.
+ private void DecodeInterlacedPixelData(Stream compressedStream, Image image)
where TPixel : struct, IPixel
{
while (true)
@@ -537,7 +533,8 @@ namespace ImageSharp.Formats
throw new ImageFormatException("Unknown filter type.");
}
- this.ProcessInterlacedDefilteredScanline(this.scanline.Array, this.currentRow, pixels, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]);
+ Span rowSpan = image.GetRowSpan(this.currentRow);
+ this.ProcessInterlacedDefilteredScanline(this.scanline.Array, rowSpan, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]);
Swap(ref this.scanline, ref this.previousScanline);
@@ -561,12 +558,12 @@ namespace ImageSharp.Formats
///
/// The pixel format.
/// The de-filtered scanline
- /// The image pixels
- private void ProcessDefilteredScanline(byte[] defilteredScanline, PixelAccessor pixels)
+ /// The image
+ private void ProcessDefilteredScanline(byte[] defilteredScanline, Image pixels)
where TPixel : struct, IPixel
{
var color = default(TPixel);
- Span pixelBuffer = pixels.GetRowSpan(this.currentRow);
+ Span rowSpan = pixels.GetRowSpan(this.currentRow);
var scanlineBuffer = new Span(defilteredScanline, 1);
switch (this.PngColorType)
@@ -577,8 +574,8 @@ namespace ImageSharp.Formats
for (int x = 0; x < this.header.Width; x++)
{
byte intensity = (byte)(newScanline1[x] * factor);
- color.PackFromBytes(intensity, intensity, intensity, 255);
- pixels[x, this.currentRow] = color;
+ color.PackFromRgba32(new Rgba32(intensity, intensity, intensity));
+ rowSpan[x] = color;
}
break;
@@ -592,27 +589,27 @@ namespace ImageSharp.Formats
byte intensity = defilteredScanline[offset];
byte alpha = defilteredScanline[offset + this.bytesPerSample];
- color.PackFromBytes(intensity, intensity, intensity, alpha);
- pixels[x, this.currentRow] = color;
+ color.PackFromRgba32(new Rgba32(intensity, intensity, intensity));
+ rowSpan[x] = color;
}
break;
case PngColorType.Palette:
- this.ProcessScanlineFromPalette(defilteredScanline, pixels);
+ this.ProcessScanlineFromPalette(defilteredScanline, rowSpan);
break;
case PngColorType.Rgb:
- PixelOperations.Instance.PackFromXyzBytes(scanlineBuffer, pixelBuffer, this.header.Width);
+ PixelOperations.Instance.PackFromRgb24Bytes(scanlineBuffer, rowSpan, this.header.Width);
break;
case PngColorType.RgbWithAlpha:
- PixelOperations.Instance.PackFromXyzwBytes(scanlineBuffer, pixelBuffer, this.header.Width);
+ PixelOperations.Instance.PackFromRgba32Bytes(scanlineBuffer, rowSpan, this.header.Width);
break;
}
@@ -623,14 +620,16 @@ namespace ImageSharp.Formats
///
/// The type of pixel we are expanding to
/// The scanline
- /// The output pixels
- private void ProcessScanlineFromPalette(byte[] defilteredScanline, PixelAccessor pixels)
+ /// Thecurrent output image row
+ private void ProcessScanlineFromPalette(byte[] defilteredScanline, Span row)
where TPixel : struct, IPixel
{
byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
byte[] palette = this.palette;
var color = default(TPixel);
+ Rgba32 rgba = default(Rgba32);
+
if (this.paletteAlpha != null && this.paletteAlpha.Length > 0)
{
// If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha
@@ -640,36 +639,34 @@ namespace ImageSharp.Formats
int index = newScanline[x + 1];
int pixelOffset = index * 3;
- byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
+ rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
- if (a > 0)
+ if (rgba.A > 0)
{
- byte r = palette[pixelOffset];
- byte g = palette[pixelOffset + 1];
- byte b = palette[pixelOffset + 2];
- color.PackFromBytes(r, g, b, a);
+ rgba.Rgb = palette.GetRgb24(pixelOffset);
}
else
{
- color.PackFromBytes(0, 0, 0, 0);
+ rgba = default(Rgba32);
}
- pixels[x, this.currentRow] = color;
+ color.PackFromRgba32(rgba);
+ row[x] = color;
}
}
else
{
+ rgba.A = 255;
+
for (int x = 0; x < this.header.Width; x++)
{
int index = newScanline[x + 1];
int pixelOffset = index * 3;
- byte r = palette[pixelOffset];
- byte g = palette[pixelOffset + 1];
- byte b = palette[pixelOffset + 2];
+ rgba.Rgb = palette.GetRgb24(pixelOffset);
- color.PackFromBytes(r, g, b, 255);
- pixels[x, this.currentRow] = color;
+ color.PackFromRgba32(rgba);
+ row[x] = color;
}
}
}
@@ -679,11 +676,10 @@ namespace ImageSharp.Formats
///
/// The pixel format.
/// The de-filtered scanline
- /// The current image row.
- /// The image pixels
+ /// The current image row.
/// The column start index. Always 0 for none interlaced images.
/// The column increment. Always 1 for none interlaced images.
- private void ProcessInterlacedDefilteredScanline(byte[] defilteredScanline, int row, PixelAccessor pixels, int pixelOffset = 0, int increment = 1)
+ private void ProcessInterlacedDefilteredScanline(byte[] defilteredScanline, Span rowSpan, int pixelOffset = 0, int increment = 1)
where TPixel : struct, IPixel
{
var color = default(TPixel);
@@ -696,8 +692,8 @@ namespace ImageSharp.Formats
for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o++)
{
byte intensity = (byte)(newScanline1[o] * factor);
- color.PackFromBytes(intensity, intensity, intensity, 255);
- pixels[x, row] = color;
+ color.PackFromRgba32(new Rgba32(intensity, intensity, intensity));
+ rowSpan[x] = color;
}
break;
@@ -708,9 +704,8 @@ namespace ImageSharp.Formats
{
byte intensity = defilteredScanline[o];
byte alpha = defilteredScanline[o + this.bytesPerSample];
-
- color.PackFromBytes(intensity, intensity, intensity, alpha);
- pixels[x, row] = color;
+ color.PackFromRgba32(new Rgba32(intensity, intensity, intensity, alpha));
+ rowSpan[x] = color;
}
break;
@@ -718,6 +713,7 @@ namespace ImageSharp.Formats
case PngColorType.Palette:
byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
+ Rgba32 rgba = default(Rgba32);
if (this.paletteAlpha != null && this.paletteAlpha.Length > 0)
{
@@ -728,36 +724,34 @@ namespace ImageSharp.Formats
int index = newScanline[o];
int offset = index * 3;
- byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
+ rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
- if (a > 0)
+ if (rgba.A > 0)
{
- byte r = this.palette[offset];
- byte g = this.palette[offset + 1];
- byte b = this.palette[offset + 2];
- color.PackFromBytes(r, g, b, a);
+ rgba.Rgb = this.palette.GetRgb24(offset);
}
else
{
- color.PackFromBytes(0, 0, 0, 0);
+ rgba = default(Rgba32);
}
- pixels[x, row] = color;
+ color.PackFromRgba32(rgba);
+ rowSpan[x] = color;
}
}
else
{
+ rgba.A = 255;
+
for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o++)
{
int index = newScanline[o];
int offset = index * 3;
- byte r = this.palette[offset];
- byte g = this.palette[offset + 1];
- byte b = this.palette[offset + 2];
+ rgba.Rgb = this.palette.GetRgb24(offset);
- color.PackFromBytes(r, g, b, 255);
- pixels[x, row] = color;
+ color.PackFromRgba32(rgba);
+ rowSpan[x] = color;
}
}
@@ -765,14 +759,15 @@ namespace ImageSharp.Formats
case PngColorType.Rgb:
+ rgba.A = 255;
for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel)
{
- byte r = defilteredScanline[o];
- byte g = defilteredScanline[o + this.bytesPerSample];
- byte b = defilteredScanline[o + (2 * this.bytesPerSample)];
+ rgba.R = defilteredScanline[o];
+ rgba.G = defilteredScanline[o + this.bytesPerSample];
+ rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)];
- color.PackFromBytes(r, g, b, 255);
- pixels[x, row] = color;
+ color.PackFromRgba32(rgba);
+ rowSpan[x] = color;
}
break;
@@ -781,13 +776,13 @@ namespace ImageSharp.Formats
for (int x = pixelOffset, o = 1; x < this.header.Width; x += increment, o += this.bytesPerPixel)
{
- byte r = defilteredScanline[o];
- byte g = defilteredScanline[o + this.bytesPerSample];
- byte b = defilteredScanline[o + (2 * this.bytesPerSample)];
- byte a = defilteredScanline[o + (3 * this.bytesPerSample)];
+ rgba.R = defilteredScanline[o];
+ rgba.G = defilteredScanline[o + this.bytesPerSample];
+ rgba.B = defilteredScanline[o + (2 * this.bytesPerSample)];
+ rgba.A = defilteredScanline[o + (3 * this.bytesPerSample)];
- color.PackFromBytes(r, g, b, a);
- pixels[x, row] = color;
+ color.PackFromRgba32(rgba);
+ rowSpan[x] = color;
}
break;
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 0482b2691c..645df05481 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -220,11 +220,7 @@ namespace ImageSharp.Formats
this.WritePhysicalChunk(stream, image);
this.WriteGammaChunk(stream);
- using (PixelAccessor pixels = image.Lock())
- {
- this.WriteDataChunks(pixels, stream);
- }
-
+ this.WriteDataChunks(image, stream);
this.WriteEndChunk(stream);
stream.Flush();
}
@@ -302,9 +298,8 @@ namespace ImageSharp.Formats
/// Collects a row of grayscale pixels.
///
/// The pixel format.
- /// The image pixels accessor.
- /// The row index.
- private void CollectGrayscaleBytes(PixelAccessor pixels, int row)
+ /// The image row span.
+ private void CollectGrayscaleBytes(Span rowSpan)
where TPixel : struct, IPixel
{
byte[] rawScanlineArray = this.rawScanline.Array;
@@ -316,7 +311,7 @@ namespace ImageSharp.Formats
// Convert the color to YCbCr and store the luminance
// Optionally store the original color alpha.
int offset = x * this.bytesPerPixel;
- pixels[x, row].ToXyzwBytes(this.chunkTypeBuffer, 0);
+ rowSpan[x].ToXyzwBytes(this.chunkTypeBuffer, 0);
byte luminance = (byte)((0.299F * this.chunkTypeBuffer[0]) + (0.587F * this.chunkTypeBuffer[1]) + (0.114F * this.chunkTypeBuffer[2]));
for (int i = 0; i < this.bytesPerPixel; i++)
@@ -337,20 +332,17 @@ namespace ImageSharp.Formats
/// Collects a row of true color pixel data.
///
/// The pixel format.
- /// The image pixel accessor.
- /// The row index.
- private void CollecTPixelBytes(PixelAccessor pixels, int row)
+ /// The row span.
+ private void CollecTPixelBytes(Span rowSpan)
where TPixel : struct, IPixel
{
- Span rowSpan = pixels.GetRowSpan(row);
-
if (this.bytesPerPixel == 4)
{
- PixelOperations.Instance.ToXyzwBytes(rowSpan, this.rawScanline, this.width);
+ PixelOperations.Instance.ToRgba32Bytes(rowSpan, this.rawScanline, this.width);
}
else
{
- PixelOperations.Instance.ToXyzBytes(rowSpan, this.rawScanline, this.width);
+ PixelOperations.Instance.ToRgb24Bytes(rowSpan, this.rawScanline, this.width);
}
}
@@ -359,10 +351,10 @@ namespace ImageSharp.Formats
/// Each scanline is encoded in the most optimal manner to improve compression.
///
/// The pixel format.
- /// The image pixel accessor.
+ /// The row span.
/// The row.
/// The
- private Buffer EncodePixelRow(PixelAccessor pixels, int row)
+ private Buffer EncodePixelRow(Span rowSpan, int row)
where TPixel : struct, IPixel
{
switch (this.pngColorType)
@@ -372,10 +364,10 @@ namespace ImageSharp.Formats
break;
case PngColorType.Grayscale:
case PngColorType.GrayscaleWithAlpha:
- this.CollectGrayscaleBytes(pixels, row);
+ this.CollectGrayscaleBytes(rowSpan);
break;
default:
- this.CollecTPixelBytes(pixels, row);
+ this.CollecTPixelBytes(rowSpan);
break;
}
@@ -637,17 +629,17 @@ namespace ImageSharp.Formats
/// Writes the pixel information to the stream.
///
/// The pixel format.
- /// The pixel accessor.
+ /// The image.
/// The stream.
- private void WriteDataChunks(PixelAccessor pixels, Stream stream)
+ private void WriteDataChunks(Image pixels, Stream stream)
where TPixel : struct, IPixel
{
this.bytesPerScanline = this.width * this.bytesPerPixel;
int resultLength = this.bytesPerScanline + 1;
- this.previousScanline = new Buffer(this.bytesPerScanline);
- this.rawScanline = new Buffer(this.bytesPerScanline);
- this.result = new Buffer(resultLength);
+ this.previousScanline = Buffer.CreateClean(this.bytesPerScanline);
+ this.rawScanline = Buffer.CreateClean(this.bytesPerScanline);
+ this.result = Buffer.CreateClean(resultLength);
if (this.pngColorType != PngColorType.Palette)
{
@@ -667,7 +659,7 @@ namespace ImageSharp.Formats
{
for (int y = 0; y < this.height; y++)
{
- Buffer r = this.EncodePixelRow(pixels, y);
+ Buffer r = this.EncodePixelRow(pixels.GetRowSpan(y), y);
deflateStream.Write(r.Array, 0, resultLength);
Swap(ref this.rawScanline, ref this.previousScanline);
diff --git a/src/ImageSharp/Image/ImageBase{TPixel}.cs b/src/ImageSharp/Image/ImageBase{TPixel}.cs
index 508c73eb2b..647d60075d 100644
--- a/src/ImageSharp/Image/ImageBase{TPixel}.cs
+++ b/src/ImageSharp/Image/ImageBase{TPixel}.cs
@@ -11,7 +11,7 @@ namespace ImageSharp
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
- using Processing;
+ using ImageSharp.Processing;
///
/// The base class of all images. Encapsulates the basic properties and methods required to manipulate
diff --git a/src/ImageSharp/Image/ImageProcessingExtensions.cs b/src/ImageSharp/Image/ImageProcessingExtensions.cs
index c9577ac15f..8eed103d10 100644
--- a/src/ImageSharp/Image/ImageProcessingExtensions.cs
+++ b/src/ImageSharp/Image/ImageProcessingExtensions.cs
@@ -7,7 +7,7 @@ namespace ImageSharp
{
using ImageSharp.PixelFormats;
- using Processing;
+ using ImageSharp.Processing;
///
/// Extension methods for the type.
diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs
index 092706e416..059ccb9a07 100644
--- a/src/ImageSharp/Image/Image{TPixel}.cs
+++ b/src/ImageSharp/Image/Image{TPixel}.cs
@@ -15,7 +15,7 @@ namespace ImageSharp
using Formats;
using ImageSharp.PixelFormats;
- using Processing;
+ using ImageSharp.Processing;
///
/// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
diff --git a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs
index 4baae86157..3902ba4255 100644
--- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs
+++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs
@@ -275,7 +275,7 @@ namespace ImageSharp
Span source = area.GetRowSpan(y);
Span destination = this.GetRowSpan(targetX, targetY + y);
- Operations.PackFromZyxBytes(source, destination, width);
+ Operations.PackFromBgr24Bytes(source, destination, width);
}
}
@@ -295,7 +295,7 @@ namespace ImageSharp
Span source = area.GetRowSpan(y);
Span destination = this.GetRowSpan(targetX, targetY + y);
- Operations.PackFromZyxwBytes(source, destination, width);
+ Operations.PackFromBgra32Bytes(source, destination, width);
}
}
@@ -315,7 +315,7 @@ namespace ImageSharp
Span source = area.GetRowSpan(y);
Span destination = this.GetRowSpan(targetX, targetY + y);
- Operations.PackFromXyzBytes(source, destination, width);
+ Operations.PackFromRgb24Bytes(source, destination, width);
}
}
@@ -334,7 +334,7 @@ namespace ImageSharp
{
Span source = area.GetRowSpan(y);
Span destination = this.GetRowSpan(targetX, targetY + y);
- Operations.PackFromXyzwBytes(source, destination, width);
+ Operations.PackFromRgba32Bytes(source, destination, width);
}
}
@@ -353,7 +353,7 @@ namespace ImageSharp
{
Span source = this.GetRowSpan(sourceX, sourceY + y);
Span destination = area.GetRowSpan(y);
- Operations.ToZyxBytes(source, destination, width);
+ Operations.ToBgr24Bytes(source, destination, width);
}
}
@@ -372,7 +372,7 @@ namespace ImageSharp
{
Span source = this.GetRowSpan(sourceX, sourceY + y);
Span destination = area.GetRowSpan(y);
- Operations.ToZyxwBytes(source, destination, width);
+ Operations.ToBgra32Bytes(source, destination, width);
}
}
@@ -391,7 +391,7 @@ namespace ImageSharp
{
Span source = this.GetRowSpan(sourceX, sourceY + y);
Span destination = area.GetRowSpan(y);
- Operations.ToXyzBytes(source, destination, width);
+ Operations.ToRgb24Bytes(source, destination, width);
}
}
@@ -410,7 +410,7 @@ namespace ImageSharp
{
Span source = this.GetRowSpan(sourceX, sourceY + y);
Span destination = area.GetRowSpan(y);
- Operations.ToXyzwBytes(source, destination, width);
+ Operations.ToRgba32Bytes(source, destination, width);
}
}
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index 6194be1bf4..17f7bf58f3 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -53,6 +53,35 @@
TextTemplatingFileGenerator
+ Block8x8F.Generated.cs
+
+ TextTemplatingFileGenerator
+ PixelOperations{TPixel}.Generated.cs
+
+
+ TextTemplatingFileGenerator
+ Rgba32.PixelOperations.Generated.cs
+
+
+
+
+
+
+
+ True
+ True
+ Block8x8F.Generated.tt
+
+
+ True
+ True
+ PixelOperations{TPixel}.Generated.tt
+
+
+ True
+ True
+ Rgba32.PixelOperations.Generated.tt
+
\ No newline at end of file
diff --git a/src/ImageSharp/Numerics/Matrix3x2Extensions.cs b/src/ImageSharp/Numerics/Matrix3x2Extensions.cs
new file mode 100644
index 0000000000..f424624020
--- /dev/null
+++ b/src/ImageSharp/Numerics/Matrix3x2Extensions.cs
@@ -0,0 +1,72 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Extension methods for the struct
+ ///
+ public static class Matrix3x2Extensions
+ {
+ ///
+ /// Creates a rotation matrix for the given rotation in degrees and a center point.
+ ///
+ /// The angle in degrees
+ /// The center point
+ /// The rotation
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateRotation(float degree, Point centerPoint)
+ {
+ float radian = MathF.DegreeToRadian(degree);
+ return Matrix3x2.CreateRotation(radian, new Vector2(centerPoint.X, centerPoint.Y));
+ }
+
+ ///
+ /// Creates a rotation matrix for the given rotation in degrees and a center point.
+ ///
+ /// The angle in degrees
+ /// The center point
+ /// The rotation
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateRotation(float degree, PointF centerPoint)
+ {
+ float radian = MathF.DegreeToRadian(degree);
+ return Matrix3x2.CreateRotation(radian, centerPoint);
+ }
+
+ ///
+ /// Creates a skew matrix for the given angle in degrees and a center point.
+ ///
+ /// The x-angle in degrees
+ /// The y-angle in degrees
+ /// The center point
+ /// The rotation
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateSkew(float degreesX, float degreesY, Point centerPoint)
+ {
+ float radiansX = MathF.DegreeToRadian(degreesX);
+ float radiansY = MathF.DegreeToRadian(degreesY);
+ return Matrix3x2.CreateSkew(radiansX, radiansY, new Vector2(centerPoint.X, centerPoint.Y));
+ }
+
+ ///
+ /// Creates a skew matrix for the given angle in degrees and a center point.
+ ///
+ /// The x-angle in degrees
+ /// The y-angle in degrees
+ /// The rotation
+ /// The center point
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateSkew(float degreesX, float degreesY, PointF centerPoint)
+ {
+ float radiansX = MathF.DegreeToRadian(degreesX);
+ float radiansY = MathF.DegreeToRadian(degreesY);
+ return Matrix3x2.CreateSkew(radiansX, radiansY, new Vector2(centerPoint.X, centerPoint.Y));
+ }
+ }
+}
diff --git a/src/ImageSharp/Numerics/Point.cs b/src/ImageSharp/Numerics/Point.cs
index 8d523895fb..9bff27d2ac 100644
--- a/src/ImageSharp/Numerics/Point.cs
+++ b/src/ImageSharp/Numerics/Point.cs
@@ -25,6 +25,17 @@ namespace ImageSharp
///
public static readonly Point Empty = default(Point);
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The horizontal and vertical position of the point.
+ public Point(int value)
+ : this()
+ {
+ this.X = LowInt16(value);
+ this.Y = HighInt16(value);
+ }
+
///
/// Initializes a new instance of the struct.
///
@@ -38,15 +49,13 @@ namespace ImageSharp
}
///
- /// Initializes a new instance of the struct.
+ /// Initializes a new instance of the struct from the given .
///
- ///
- /// The vector representing the width and height.
- ///
- public Point(Vector2 vector)
+ /// The size
+ public Point(Size size)
{
- this.X = (int)Math.Round(vector.X);
- this.Y = (int)Math.Round(vector.Y);
+ this.X = size.Width;
+ this.Y = size.Height;
}
///
@@ -66,176 +75,160 @@ namespace ImageSharp
public bool IsEmpty => this.Equals(Empty);
///
- /// Computes the sum of adding two points.
+ /// Creates a with the coordinates of the specified .
///
- /// The point on the left hand of the operand.
- /// The point on the right hand of the operand.
- ///
- /// The
- ///
+ /// The point
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Point operator +(Point left, Point right)
- {
- return new Point(left.X + right.X, left.Y + right.Y);
- }
+ public static implicit operator PointF(Point point) => new PointF(point.X, point.Y);
+
+ ///
+ /// Creates a with the coordinates of the specified .
+ ///
+ /// The point
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Vector2(Point point) => new Vector2(point.X, point.Y);
+
+ ///
+ /// Creates a with the coordinates of the specified .
+ ///
+ /// The point
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Size(Point point) => new Size(point.X, point.Y);
///
- /// Computes the difference left by subtracting one point from another.
+ /// Translates a by a given .
///
- /// The point on the left hand of the operand.
- /// The point on the right hand of the operand.
+ /// The point on the left hand of the operand.
+ /// The size on the right hand of the operand.
///
/// The
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Point operator -(Point left, Point right)
- {
- return new Point(left.X - right.X, left.Y - right.Y);
- }
+ public static Point operator +(Point point, Size size) => Add(point, size);
+
+ ///
+ /// Translates a by the negative of a given .
+ ///
+ /// The point on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point operator -(Point point, Size size) => Subtract(point, size);
///
/// Compares two objects for equality.
///
- ///
- /// The on the left side of the operand.
- ///
- ///
- /// The on the right side of the operand.
- ///
+ /// The on the left side of the operand.
+ /// The on the right side of the operand.
///
/// True if the current left is equal to the parameter; otherwise, false.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool operator ==(Point left, Point right)
- {
- return left.Equals(right);
- }
+ public static bool operator ==(Point left, Point right) => left.Equals(right);
///
/// Compares two objects for inequality.
///
- ///
- /// The on the left side of the operand.
- ///
- ///
- /// The on the right side of the operand.
- ///
+ /// The on the left side of the operand.
+ /// The on the right side of the operand.
///
/// True if the current left is unequal to the parameter; otherwise, false.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool operator !=(Point left, Point right)
- {
- return !left.Equals(right);
- }
+ public static bool operator !=(Point left, Point right) => !left.Equals(right);
///
- /// Creates a rotation matrix for the given point and angle.
+ /// Translates a by the negative of a given .
///
- /// The origin point to rotate around
- /// Rotation in degrees
- /// The rotation
- public static Matrix3x2 CreateRotation(Point origin, float degrees)
- {
- float radians = MathF.DegreeToRadian(degrees);
- return Matrix3x2.CreateRotation(radians, new Vector2(origin.X, origin.Y));
- }
+ /// The point on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point Add(Point point, Size size) => new Point(unchecked(point.X + size.Width), unchecked(point.Y + size.Height));
///
- /// Rotates a point around a given a rotation matrix.
+ /// Translates a by the negative of a given .
///
- /// The point to rotate
- /// Rotation matrix used
- /// The rotated
- public static Point Rotate(Point point, Matrix3x2 rotation)
- {
- return new Point(Vector2.Transform(new Vector2(point.X, point.Y), rotation));
- }
+ /// The point on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point Subtract(Point point, Size size) => new Point(unchecked(point.X - size.Width), unchecked(point.Y - size.Height));
///
- /// Rotates a point around a given origin by the specified angle in degrees.
+ /// Converts a to a by performing a ceiling operation on all the coordinates.
///
- /// The point to rotate
- /// The center point to rotate around.
- /// The angle in degrees.
- /// The rotated
- public static Point Rotate(Point point, Point origin, float degrees)
- {
- return new Point(Vector2.Transform(new Vector2(point.X, point.Y), CreateRotation(origin, degrees)));
- }
+ /// The point
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point Ceiling(PointF point) => new Point(unchecked((int)MathF.Ceiling(point.X)), unchecked((int)MathF.Ceiling(point.Y)));
///
- /// Creates a skew matrix for the given point and angle.
+ /// Converts a to a by performing a round operation on all the coordinates.
///
- /// The origin point to rotate around
- /// The x-angle in degrees.
- /// The y-angle in degrees.
- /// The rotation
- public static Matrix3x2 CreateSkew(Point origin, float degreesX, float degreesY)
- {
- float radiansX = MathF.DegreeToRadian(degreesX);
- float radiansY = MathF.DegreeToRadian(degreesY);
- return Matrix3x2.CreateSkew(radiansX, radiansY, new Vector2(origin.X, origin.Y));
- }
+ /// The point
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point Round(PointF point) => new Point(unchecked((int)MathF.Round(point.X)), unchecked((int)MathF.Round(point.Y)));
///
- /// Skews a point using a given a skew matrix.
+ /// Converts a to a by performing a truncate operation on all the coordinates.
///
- /// The point to rotate
- /// Rotation matrix used
- /// The rotated
- public static Point Skew(Point point, Matrix3x2 skew)
- {
- return new Point(Vector2.Transform(new Vector2(point.X, point.Y), skew));
- }
+ /// The point
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point Truncate(PointF point) => new Point(unchecked((int)point.X), unchecked((int)point.Y));
///
- /// Skews a point around a given origin by the specified angles in degrees.
+ /// Converts a to a by performing a round operation on all the coordinates.
///
- /// The point to skew.
- /// The center point to rotate around.
- /// The x-angle in degrees.
- /// The y-angle in degrees.
- /// The skewed
- public static Point Skew(Point point, Point origin, float degreesX, float degreesY)
- {
- return new Point(Vector2.Transform(new Vector2(point.X, point.Y), CreateSkew(origin, degreesX, degreesY)));
- }
+ /// The vector
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point Round(Vector2 vector) => new Point(unchecked((int)MathF.Round(vector.X)), unchecked((int)MathF.Round(vector.Y)));
///
- /// Gets a representation for this .
+ /// Rotates a point around the given rotation matrix.
///
- /// A representation for this object.
- public Vector2 ToVector2()
- {
- return new Vector2(this.X, this.Y);
- }
+ /// The point to rotate
+ /// Rotation matrix used
+ /// The rotated
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point Rotate(Point point, Matrix3x2 rotation) => Round(Vector2.Transform(new Vector2(point.X, point.Y), rotation));
+
+ ///
+ /// Skews a point using the given skew matrix.
+ ///
+ /// The point to rotate
+ /// Rotation matrix used
+ /// The rotated
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point Skew(Point point, Matrix3x2 skew) => Round(Vector2.Transform(new Vector2(point.X, point.Y), skew));
///
/// Translates this by the specified amount.
///
/// The amount to offset the x-coordinate.
/// The amount to offset the y-coordinate.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Offset(int dx, int dy)
{
- this.X += dx;
- this.Y += dy;
+ unchecked
+ {
+ this.X += dx;
+ this.Y += dy;
+ }
}
///
/// Translates this by the specified amount.
///
- /// The used offset this .
- public void Offset(Point p)
- {
- this.Offset(p.X, p.Y);
- }
+ /// The used offset this .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Offset(Point point) => this.Offset(point.X, point.Y);
///
- public override int GetHashCode()
- {
- return this.GetHashCode(this);
- }
+ public override int GetHashCode() => this.GetHashCode(this);
///
public override string ToString()
@@ -249,34 +242,16 @@ namespace ImageSharp
}
///
- public override bool Equals(object obj)
- {
- if (obj is Point)
- {
- return this.Equals((Point)obj);
- }
-
- return false;
- }
+ public override bool Equals(object obj) => obj is Point && this.Equals((Point)obj);
///
- public bool Equals(Point other)
- {
- return this.X == other.X && this.Y == other.Y;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(Point other) => this.X == other.X && this.Y == other.Y;
- ///
- /// Returns the hash code for this instance.
- ///
- ///
- /// The instance of to return the hash code for.
- ///
- ///
- /// A 32-bit signed integer that is the hash code for this instance.
- ///
- private int GetHashCode(Point point)
- {
- return point.X ^ point.Y;
- }
+ private static short HighInt16(int n) => unchecked((short)((n >> 16) & 0xffff));
+
+ private static short LowInt16(int n) => unchecked((short)(n & 0xffff));
+
+ private int GetHashCode(Point point) => point.X ^ point.Y;
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Numerics/PointF.cs b/src/ImageSharp/Numerics/PointF.cs
new file mode 100644
index 0000000000..cbe5c7f48b
--- /dev/null
+++ b/src/ImageSharp/Numerics/PointF.cs
@@ -0,0 +1,233 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.ComponentModel;
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Represents an ordered pair of single precision floating point x- and y-coordinates that defines a point in
+ /// a two-dimensional plane.
+ ///
+ ///
+ /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
+ /// as it avoids the need to create new values for modification operations.
+ ///
+ public struct PointF : IEquatable
+ {
+ ///
+ /// Represents a that has X and Y values set to zero.
+ ///
+ public static readonly PointF Empty = default(PointF);
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The horizontal position of the point.
+ /// The vertical position of the point.
+ public PointF(float x, float y)
+ : this()
+ {
+ this.X = x;
+ this.Y = y;
+ }
+
+ ///
+ /// Initializes a new instance of the struct from the given .
+ ///
+ /// The size
+ public PointF(SizeF size)
+ {
+ this.X = size.Width;
+ this.Y = size.Height;
+ }
+
+ ///
+ /// Gets or sets the x-coordinate of this .
+ ///
+ public float X { get; set; }
+
+ ///
+ /// Gets or sets the y-coordinate of this .
+ ///
+ public float Y { get; set; }
+
+ ///
+ /// Gets a value indicating whether this is empty.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool IsEmpty => this.Equals(Empty);
+
+ ///
+ /// Creates a with the coordinates of the specified .
+ ///
+ /// The vector.
+ ///
+ /// The .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator PointF(Vector2 vector) => new PointF(vector.X, vector.Y);
+
+ ///
+ /// Creates a with the coordinates of the specified .
+ ///
+ /// The point.
+ ///
+ /// The .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Vector2(PointF point) => new Vector2(point.X, point.Y);
+
+ ///
+ /// Creates a with the coordinates of the specified by truncating each of the coordinates.
+ ///
+ /// The point.
+ ///
+ /// The .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Point(PointF point) => Point.Truncate(point);
+
+ ///
+ /// Translates a by a given .
+ ///
+ /// The point on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ ///
+ /// The
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static PointF operator +(PointF point, SizeF size) => Add(point, size);
+
+ ///
+ /// Translates a by the negative of a given .
+ ///
+ /// The point on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static PointF operator -(PointF point, SizeF size) => Subtract(point, size);
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is equal to the parameter; otherwise, false.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator ==(PointF left, PointF right) => left.Equals(right);
+
+ ///
+ /// Compares two objects for inequality.
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is unequal to the parameter; otherwise, false.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator !=(PointF left, PointF right) => !left.Equals(right);
+
+ ///
+ /// Translates a by the negative of a given .
+ ///
+ /// The point on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static PointF Add(PointF point, SizeF size) => new PointF(point.X + size.Width, point.Y + size.Height);
+
+ ///
+ /// Translates a by the negative of a given .
+ ///
+ /// The point on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static PointF Subtract(PointF point, SizeF size) => new PointF(point.X - size.Width, point.Y - size.Height);
+
+ ///
+ /// Rotates a point around the given rotation matrix.
+ ///
+ /// The point to rotate
+ /// Rotation matrix used
+ /// The rotated
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static PointF Rotate(PointF point, Matrix3x2 rotation) => Vector2.Transform(new Vector2(point.X, point.Y), rotation);
+
+ ///
+ /// Skews a point using the given skew matrix.
+ ///
+ /// The point to rotate
+ /// Rotation matrix used
+ /// The rotated
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static PointF Skew(PointF point, Matrix3x2 skew) => Vector2.Transform(new Vector2(point.X, point.Y), skew);
+
+ ///
+ /// Translates this by the specified amount.
+ ///
+ /// The amount to offset the x-coordinate.
+ /// The amount to offset the y-coordinate.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Offset(float dx, float dy)
+ {
+ this.X += dx;
+ this.Y += dy;
+ }
+
+ ///
+ /// Translates this by the specified amount.
+ ///
+ /// The used offset this .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Offset(PointF point) => this.Offset(point.X, point.Y);
+
+ ///
+ public override int GetHashCode() => this.GetHashCode(this);
+
+ ///
+ public override string ToString()
+ {
+ if (this.IsEmpty)
+ {
+ return "PointF [ Empty ]";
+ }
+
+ return $"PointF [ X={this.X}, Y={this.Y} ]";
+ }
+
+ ///
+ public override bool Equals(object obj) => obj is PointF && this.Equals((PointF)obj);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(PointF other) => this.X.Equals(other.X) && this.Y.Equals(other.Y);
+
+ ///
+ /// Returns the hash code for this instance.
+ ///
+ ///
+ /// The instance of to return the hash code for.
+ ///
+ ///
+ /// A 32-bit signed integer that is the hash code for this instance.
+ ///
+ private int GetHashCode(PointF point) => point.X.GetHashCode() ^ point.Y.GetHashCode();
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Numerics/Rectangle.cs b/src/ImageSharp/Numerics/Rectangle.cs
index b651eff71a..d16b22920a 100644
--- a/src/ImageSharp/Numerics/Rectangle.cs
+++ b/src/ImageSharp/Numerics/Rectangle.cs
@@ -8,6 +8,7 @@ namespace ImageSharp
using System;
using System.ComponentModel;
using System.Numerics;
+ using System.Runtime.CompilerServices;
///
/// Stores a set of four integers that represent the location and size of a rectangle.
@@ -23,11 +24,6 @@ namespace ImageSharp
///
public static readonly Rectangle Empty = default(Rectangle);
- ///
- /// The backing vector for SIMD support.
- ///
- private Vector4 backingVector;
-
///
/// Initializes a new instance of the struct.
///
@@ -37,7 +33,10 @@ namespace ImageSharp
/// The height of the rectangle.
public Rectangle(int x, int y, int width, int height)
{
- this.backingVector = new Vector4(x, y, width, height);
+ this.X = x;
+ this.Y = y;
+ this.Width = width;
+ this.Height = height;
}
///
@@ -51,197 +50,325 @@ namespace ImageSharp
///
public Rectangle(Point point, Size size)
{
- this.backingVector = new Vector4(point.X, point.Y, size.Width, size.Height);
+ this.X = point.X;
+ this.Y = point.Y;
+ this.Width = size.Width;
+ this.Height = size.Height;
}
///
- /// Initializes a new instance of the struct.
+ /// Gets or sets the x-coordinate of this .
///
- ///
- /// The which specifies the rectangles top left point in a two-dimensional plane.
- ///
- ///
- /// The which specifies the rectangles bottom right point in a two-dimensional plane.
- ///
- public Rectangle(Point topLeft, Point bottomRight)
- {
- this.backingVector = new Vector4(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
- }
+ public int X { get; set; }
///
- /// Initializes a new instance of the struct.
+ /// Gets or sets the y-coordinate of this .
///
- /// The vector.
- public Rectangle(Vector4 vector)
- {
- this.backingVector = vector;
- }
+ public int Y { get; set; }
///
- /// Gets or sets the x-coordinate of this .
+ /// Gets or sets the width of this .
+ ///
+ public int Width { get; set; }
+
+ ///
+ /// Gets or sets the height of this .
///
- public int X
+ public int Height { get; set; }
+
+ ///
+ /// Gets or sets the coordinates of the upper-left corner of the rectangular region represented by this .
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Point Location
{
- get
- {
- return (int)this.backingVector.X;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => new Point(this.X, this.Y);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
- this.backingVector.X = value;
+ this.X = value.X;
+ this.Y = value.Y;
}
}
///
- /// Gets or sets the y-coordinate of this .
+ /// Gets or sets the size of this .
///
- public int Y
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Size Size
{
- get
- {
- return (int)this.backingVector.Y;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => new Size(this.Width, this.Height);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
- this.backingVector.Y = value;
+ this.Width = value.Width;
+ this.Height = value.Height;
}
}
///
- /// Gets or sets the width of this .
+ /// Gets a value indicating whether this is empty.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool IsEmpty => this.Equals(Empty);
+
+ ///
+ /// Gets the y-coordinate of the top edge of this .
///
- public int Width
+ public int Top
{
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- return (int)this.backingVector.Z;
+ return this.Y;
}
+ }
- set
+ ///
+ /// Gets the x-coordinate of the right edge of this .
+ ///
+ public int Right
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
{
- this.backingVector.Z = value;
+ return unchecked(this.X + this.Width);
}
}
///
- /// Gets or sets the height of this .
+ /// Gets the y-coordinate of the bottom edge of this .
///
- public int Height
+ public int Bottom
{
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- return (int)this.backingVector.W;
+ return unchecked(this.Y + this.Height);
}
+ }
- set
+ ///
+ /// Gets the x-coordinate of the left edge of this .
+ ///
+ public int Left
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
{
- this.backingVector.W = value;
+ return this.X;
}
}
///
- /// Gets the size of this .
+ /// Creates a with the coordinates of the specified .
///
- public Size Size => new Size(this.Width, this.Height);
+ /// The rectangle
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator RectangleF(Rectangle rectangle) => new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
///
- /// Gets a value indicating whether this is empty.
+ /// Creates a with the coordinates of the specified .
///
- [EditorBrowsable(EditorBrowsableState.Never)]
- public bool IsEmpty => this.Equals(Empty);
+ /// The rectangle
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Vector4(Rectangle rectangle) => new Vector4(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
///
- /// Gets the y-coordinate of the top edge of this .
+ /// Compares two objects for equality.
///
- public int Top => this.Y;
+ /// The on the left side of the operand.
+ /// The on the right side of the operand.
+ ///
+ /// True if the current left is equal to the parameter; otherwise, false.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator ==(Rectangle left, Rectangle right) => left.Equals(right);
///
- /// Gets the x-coordinate of the right edge of this .
+ /// Compares two objects for inequality.
///
- public int Right => this.X + this.Width;
+ /// The on the left side of the operand.
+ /// The on the right side of the operand.
+ ///
+ /// True if the current left is unequal to the parameter; otherwise, false.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator !=(Rectangle left, Rectangle right) => !left.Equals(right);
///
- /// Gets the y-coordinate of the bottom edge of this .
+ /// Creates a new with the specified location and size.
+ /// The left coordinate of the rectangle
+ /// The top coordinate of the rectangle
+ /// The right coordinate of the rectangle
+ /// The bottom coordinate of the rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+
+ // ReSharper disable once InconsistentNaming
+ public static Rectangle FromLTRB(int left, int top, int right, int bottom) => new Rectangle(left, top, unchecked(right - left), unchecked(bottom - top));
+
+ ///
+ /// Returns the center point of the given
///
- public int Bottom => this.Y + this.Height;
+ /// The rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Point Center(Rectangle rectangle) => new Point(rectangle.Left + (rectangle.Width / 2), rectangle.Top + (rectangle.Height / 2));
///
- /// Gets the x-coordinate of the left edge of this .
+ /// Creates a rectangle that represents the intersection between and
+ /// . If there is no intersection, an empty rectangle is returned.
///
- public int Left => this.X;
+ /// The first rectangle
+ /// The second rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Rectangle Intersect(Rectangle a, Rectangle b)
+ {
+ int x1 = Math.Max(a.X, b.X);
+ int x2 = Math.Min(a.Right, b.Right);
+ int y1 = Math.Max(a.Y, b.Y);
+ int y2 = Math.Min(a.Bottom, b.Bottom);
+
+ if (x2 >= x1 && y2 >= y1)
+ {
+ return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ return Empty;
+ }
///
- /// Computes the sum of adding two rectangles.
+ /// Creates a that is inflated by the specified amount.
///
- /// The rectangle on the left hand of the operand.
- /// The rectangle on the right hand of the operand.
- ///
- /// The
- ///
- public static Rectangle operator +(Rectangle left, Rectangle right)
+ /// The rectangle
+ /// The amount to inflate the width by
+ /// The amount to inflate the height by
+ /// A new
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Rectangle Inflate(Rectangle rectangle, int x, int y)
{
- return new Rectangle(left.backingVector + right.backingVector);
+ Rectangle r = rectangle;
+ r.Inflate(x, y);
+ return r;
}
///
- /// Computes the difference left by subtracting one rectangle from another.
+ /// Converts a to a by performing a ceiling operation on all the coordinates.
///
- /// The rectangle on the left hand of the operand.
- /// The rectangle on the right hand of the operand.
- ///
- /// The
- ///
- public static Rectangle operator -(Rectangle left, Rectangle right)
+ /// The rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Rectangle Ceiling(RectangleF rectangle)
{
- return new Rectangle(left.backingVector - right.backingVector);
+ unchecked
+ {
+ return new Rectangle(
+ (int)MathF.Ceiling(rectangle.X),
+ (int)MathF.Ceiling(rectangle.Y),
+ (int)MathF.Ceiling(rectangle.Width),
+ (int)MathF.Ceiling(rectangle.Height));
+ }
}
///
- /// Compares two objects for equality.
+ /// Converts a to a by performing a truncate operation on all the coordinates.
///
- ///
- /// The on the left side of the operand.
- ///
- ///
- /// The on the right side of the operand.
- ///
- ///
- /// True if the current left is equal to the parameter; otherwise, false.
- ///
- public static bool operator ==(Rectangle left, Rectangle right)
+ /// The rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Rectangle Truncate(RectangleF rectangle)
{
- return left.Equals(right);
+ unchecked
+ {
+ return new Rectangle(
+ (int)rectangle.X,
+ (int)rectangle.Y,
+ (int)rectangle.Width,
+ (int)rectangle.Height);
+ }
}
///
- /// Compares two objects for inequality.
+ /// Converts a to a by performing a round operation on all the coordinates.
///
- ///
- /// The on the left side of the operand.
- ///
- ///
- /// The on the right side of the operand.
- ///
- ///
- /// True if the current left is unequal to the parameter; otherwise, false.
- ///
- public static bool operator !=(Rectangle left, Rectangle right)
+ /// The rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Rectangle Round(RectangleF rectangle)
{
- return !left.Equals(right);
+ unchecked
+ {
+ return new Rectangle(
+ (int)MathF.Round(rectangle.X),
+ (int)MathF.Round(rectangle.Y),
+ (int)MathF.Round(rectangle.Width),
+ (int)MathF.Round(rectangle.Height));
+ }
}
///
- /// Returns the center point of the given
+ /// Creates a rectangle that represents the union between and .
+ ///
+ /// The first rectangle
+ /// The second rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Rectangle Union(Rectangle a, Rectangle b)
+ {
+ int x1 = Math.Min(a.X, b.X);
+ int x2 = Math.Max(a.Right, b.Right);
+ int y1 = Math.Min(a.Y, b.Y);
+ int y2 = Math.Max(a.Bottom, b.Bottom);
+
+ return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ ///
+ /// Creates a Rectangle that represents the intersection between this Rectangle and the .
///
/// The rectangle
- ///
- public static Point Center(Rectangle rectangle)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Intersect(Rectangle rectangle)
{
- return new Point(rectangle.Left + (rectangle.Width / 2), rectangle.Top + (rectangle.Height / 2));
+ Rectangle result = Intersect(rectangle, this);
+
+ this.X = result.X;
+ this.Y = result.Y;
+ this.Width = result.Width;
+ this.Height = result.Height;
}
+ ///
+ /// Inflates this by the specified amount.
+ ///
+ /// The width
+ /// The height
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Inflate(int width, int height)
+ {
+ unchecked
+ {
+ this.X -= width;
+ this.Y -= height;
+
+ this.Width += 2 * width;
+ this.Height += 2 * height;
+ }
+ }
+
+ ///
+ /// Inflates this by the specified amount.
+ ///
+ /// The size
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Inflate(Size size) => this.Inflate(size.Width, size.Height);
+
///
/// Determines if the specfied point is contained within the rectangular region defined by
/// this .
@@ -249,33 +376,63 @@ namespace ImageSharp
/// The x-coordinate of the given point.
/// The y-coordinate of the given point.
/// The
- public bool Contains(int x, int y)
- {
- // TODO: SIMD?
- return this.X <= x
- && x < this.Right
- && this.Y <= y
- && y < this.Bottom;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Contains(int x, int y) => this.X <= x && x < this.Right && this.Y <= y && y < this.Bottom;
+
+ ///
+ /// Determines if the specified point is contained within the rectangular region defined by this .
+ ///
+ /// The point
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Contains(Point point) => this.Contains(point.X, point.Y);
+
+ ///
+ /// Determines if the rectangular region represented by is entirely contained
+ /// within the rectangular region represented by this .
+ ///
+ /// The rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Contains(Rectangle rectangle) =>
+ (this.X <= rectangle.X) && (rectangle.Right <= this.Right) &&
+ (this.Y <= rectangle.Y) && (rectangle.Bottom <= this.Bottom);
///
/// Determines if the specfied intersects the rectangular region defined by
/// this .
///
- /// The other Rectange
+ /// The other Rectange
/// The
- public bool Intersects(Rectangle rect)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IntersectsWith(Rectangle rectangle) =>
+ (rectangle.X < this.Right) && (this.X < rectangle.Right) &&
+ (rectangle.Y < this.Bottom) && (this.Y < rectangle.Bottom);
+
+ ///
+ /// Adjusts the location of this rectangle by the specified amount.
+ ///
+ /// The point
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Offset(Point point) => this.Offset(point.X, point.Y);
+
+ ///
+ /// Adjusts the location of this rectangle by the specified amount.
+ ///
+ /// The amount to offset the x-coordinate.
+ /// The amount to offset the y-coordinate.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Offset(int dx, int dy)
{
- return rect.Left <= this.Right && rect.Right >= this.Left
- &&
- rect.Top <= this.Bottom && rect.Bottom >= this.Top;
+ unchecked
+ {
+ this.X += dx;
+ this.Y += dy;
+ }
}
///
- public override int GetHashCode()
- {
- return this.GetHashCode(this);
- }
+ public override int GetHashCode() => this.GetHashCode(this);
///
public override string ToString()
@@ -285,39 +442,26 @@ namespace ImageSharp
return "Rectangle [ Empty ]";
}
- return
- $"Rectangle [ X={this.X}, Y={this.Y}, Width={this.Width}, Height={this.Height} ]";
+ return $"Rectangle [ X={this.X}, Y={this.Y}, Width={this.Width}, Height={this.Height} ]";
}
///
- public override bool Equals(object obj)
- {
- if (obj is Rectangle)
- {
- return this.Equals((Rectangle)obj);
- }
-
- return false;
- }
+ public override bool Equals(object obj) => obj is Rectangle && this.Equals((Rectangle)obj);
///
- public bool Equals(Rectangle other)
- {
- return this.backingVector.Equals(other.backingVector);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(Rectangle other) => this.X == other.X && this.Y == other.Y && this.Width == other.Width && this.Height == other.Height;
- ///
- /// Returns the hash code for this instance.
- ///
- ///
- /// The instance of to return the hash code for.
- ///
- ///
- /// A 32-bit signed integer that is the hash code for this instance.
- ///
private int GetHashCode(Rectangle rectangle)
{
- return rectangle.backingVector.GetHashCode();
+ unchecked
+ {
+ int hashCode = rectangle.X;
+ hashCode = (hashCode * 397) ^ rectangle.Y;
+ hashCode = (hashCode * 397) ^ rectangle.Width;
+ hashCode = (hashCode * 397) ^ rectangle.Height;
+ return hashCode;
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Numerics/RectangleF.cs b/src/ImageSharp/Numerics/RectangleF.cs
index 2ed57c8414..7611c96029 100644
--- a/src/ImageSharp/Numerics/RectangleF.cs
+++ b/src/ImageSharp/Numerics/RectangleF.cs
@@ -8,9 +8,10 @@ namespace ImageSharp
using System;
using System.ComponentModel;
using System.Numerics;
+ using System.Runtime.CompilerServices;
///
- /// Stores a set of four integers that represent the location and size of a rectangle.
+ /// Stores a set of four single precision floating points that represent the location and size of a rectangle.
///
///
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
@@ -19,15 +20,10 @@ namespace ImageSharp
public struct RectangleF : IEquatable
{
///
- /// Represents a that has X, Y, Width, and Height values set to zero.
+ /// Represents a that has X, Y, Width, and Height values set to zero.
///
public static readonly RectangleF Empty = default(RectangleF);
- ///
- /// The backing vector for SIMD support.
- ///
- private Vector4 backingVector;
-
///
/// Initializes a new instance of the struct.
///
@@ -37,79 +33,80 @@ namespace ImageSharp
/// The height of the rectangle.
public RectangleF(float x, float y, float width, float height)
{
- this.backingVector = new Vector4(x, y, width, height);
+ this.X = x;
+ this.Y = y;
+ this.Width = width;
+ this.Height = height;
}
///
/// Initializes a new instance of the struct.
///
- /// The vector.
- public RectangleF(Vector4 vector)
+ ///
+ /// The which specifies the rectangles point in a two-dimensional plane.
+ ///
+ ///
+ /// The which specifies the rectangles height and width.
+ ///
+ public RectangleF(PointF point, SizeF size)
{
- this.backingVector = vector;
+ this.X = point.X;
+ this.Y = point.Y;
+ this.Width = size.Width;
+ this.Height = size.Height;
}
///
/// Gets or sets the x-coordinate of this .
///
- public float X
- {
- get
- {
- return this.backingVector.X;
- }
-
- set
- {
- this.backingVector.X = value;
- }
- }
+ public float X { get; set; }
///
/// Gets or sets the y-coordinate of this .
///
- public float Y
- {
- get
- {
- return this.backingVector.Y;
- }
-
- set
- {
- this.backingVector.Y = value;
- }
- }
+ public float Y { get; set; }
///
/// Gets or sets the width of this .
///
- public float Width
+ public float Width { get; set; }
+
+ ///
+ /// Gets or sets the height of this .
+ ///
+ public float Height { get; set; }
+
+ ///
+ /// Gets or sets the coordinates of the upper-left corner of the rectangular region represented by this .
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public PointF Location
{
- get
- {
- return this.backingVector.Z;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => new PointF(this.X, this.Y);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
- this.backingVector.Z = value;
+ this.X = value.X;
+ this.Y = value.Y;
}
}
///
- /// Gets or sets the height of this .
+ /// Gets or sets the size of this .
///
- public float Height
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public SizeF Size
{
- get
- {
- return this.backingVector.W;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => new SizeF(this.Width, this.Height);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
- this.backingVector.W = value;
+ this.Width = value.Width;
+ this.Height = value.Height;
}
}
@@ -117,141 +114,196 @@ namespace ImageSharp
/// Gets a value indicating whether this is empty.
///
[EditorBrowsable(EditorBrowsableState.Never)]
- public bool IsEmpty => this.Equals(Empty);
+ public bool IsEmpty => (this.Width <= 0) || (this.Height <= 0);
///
/// Gets the y-coordinate of the top edge of this .
///
- public float Top => this.Y;
+ public float Top
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return this.Y;
+ }
+ }
///
/// Gets the x-coordinate of the right edge of this .
///
- public float Right => this.X + this.Width;
+ public float Right
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return this.X + this.Width;
+ }
+ }
///
/// Gets the y-coordinate of the bottom edge of this .
///
- public float Bottom => this.Y + this.Height;
+ public float Bottom
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return this.Y + this.Height;
+ }
+ }
///
/// Gets the x-coordinate of the left edge of this .
///
- public float Left => this.X;
+ public float Left
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return this.X;
+ }
+ }
///
- /// Performs an implicit conversion from to .
+ /// Creates a with the coordinates of the specified by truncating each coordinate.
///
- /// The d.
- ///
- /// The result of the conversion.
- ///
- public static implicit operator RectangleF(Rectangle d)
- {
- return new RectangleF(d.Left, d.Top, d.Width, d.Height);
- }
+ /// The rectangle
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Rectangle(RectangleF rectangle) => Rectangle.Truncate(rectangle);
///
- /// Computes the sum of adding two rectangles.
+ /// Compares two objects for equality.
///
- /// The rectangle on the left hand of the operand.
- /// The rectangle on the right hand of the operand.
+ /// The on the left side of the operand.
+ /// The on the right side of the operand.
///
- /// The
+ /// True if the current left is equal to the parameter; otherwise, false.
///
- public static RectangleF operator +(RectangleF left, RectangleF right)
- {
- return new RectangleF(left.backingVector + right.backingVector);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator ==(RectangleF left, RectangleF right) => left.Equals(right);
///
- /// Computes the difference left by subtracting one rectangle from another.
+ /// Compares two objects for inequality.
///
- /// The rectangle on the left hand of the operand.
- /// The rectangle on the right hand of the operand.
+ /// The on the left side of the operand.
+ /// The on the right side of the operand.
///
- /// The
+ /// True if the current left is unequal to the parameter; otherwise, false.
///
- public static RectangleF operator -(RectangleF left, RectangleF right)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator !=(RectangleF left, RectangleF right) => !left.Equals(right);
+
+ ///
+ /// Creates a new with the specified location and size.
+ /// The left coordinate of the rectangle
+ /// The top coordinate of the rectangle
+ /// The right coordinate of the rectangle
+ /// The bottom coordinate of the rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+
+ // ReSharper disable once InconsistentNaming
+ public static RectangleF FromLTRB(float left, float top, float right, float bottom) => new RectangleF(left, top, right - left, bottom - top);
+
+ ///
+ /// Returns the center point of the given
+ ///
+ /// The rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static PointF Center(RectangleF rectangle) => new PointF(rectangle.Left + (rectangle.Width / 2), rectangle.Top + (rectangle.Height / 2));
+
+ ///
+ /// Creates a rectangle that represents the intersection between and
+ /// . If there is no intersection, an empty rectangle is returned.
+ ///
+ /// The first rectangle
+ /// The second rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static RectangleF Intersect(RectangleF a, RectangleF b)
{
- return new RectangleF(left.backingVector - right.backingVector);
+ float x1 = MathF.Max(a.X, b.X);
+ float x2 = MathF.Min(a.Right, b.Right);
+ float y1 = MathF.Max(a.Y, b.Y);
+ float y2 = MathF.Min(a.Bottom, b.Bottom);
+
+ if (x2 >= x1 && y2 >= y1)
+ {
+ return new RectangleF(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ return Empty;
}
///
- /// Compares two objects for equality.
+ /// Creates a that is inflated by the specified amount.
///
- ///
- /// The on the left side of the operand.
- ///
- ///
- /// The on the right side of the operand.
- ///
- ///
- /// True if the current left is equal to the parameter; otherwise, false.
- ///
- public static bool operator ==(RectangleF left, RectangleF right)
+ /// The rectangle
+ /// The amount to inflate the width by
+ /// The amount to inflate the height by
+ /// A new
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static RectangleF Inflate(RectangleF rectangle, float x, float y)
{
- return left.Equals(right);
+ RectangleF r = rectangle;
+ r.Inflate(x, y);
+ return r;
}
///
- /// Compares two objects for inequality.
+ /// Creates a rectangle that represents the union between and .
///
- ///
- /// The on the left side of the operand.
- ///
- ///
- /// The on the right side of the operand.
- ///
- ///
- /// True if the current left is unequal to the parameter; otherwise, false.
- ///
- public static bool operator !=(RectangleF left, RectangleF right)
+ /// The first rectangle
+ /// The second rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static RectangleF Union(RectangleF a, RectangleF b)
{
- return !left.Equals(right);
+ float x1 = MathF.Min(a.X, b.X);
+ float x2 = MathF.Max(a.Right, b.Right);
+ float y1 = MathF.Min(a.Y, b.Y);
+ float y2 = MathF.Max(a.Bottom, b.Bottom);
+
+ return new RectangleF(x1, y1, x2 - x1, y2 - y1);
}
///
- /// Returns the center point of the given
+ /// Creates a RectangleF that represents the intersection between this RectangleF and the .
///
/// The rectangle
- ///
- public static Vector2 Center(RectangleF rectangle)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Intersect(RectangleF rectangle)
{
- return new Vector2(rectangle.Left + (rectangle.Width / 2), rectangle.Top + (rectangle.Height / 2));
+ RectangleF result = Intersect(rectangle, this);
+
+ this.X = result.X;
+ this.Y = result.Y;
+ this.Width = result.Width;
+ this.Height = result.Height;
}
///
- /// Rounds the points away from the center this into a
- /// by rounding the dimensions to the nerent integer ensuring that the new rectangle is
- /// never smaller than the source
+ /// Inflates this by the specified amount.
///
- /// The source area to round out
- ///
- /// The smallest that the will fit inside.
- ///
- public static Rectangle Ceiling(RectangleF source)
+ /// The width
+ /// The height
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Inflate(float width, float height)
{
- int y = (int)Math.Floor(source.Y);
- int width = (int)Math.Ceiling(source.Width);
- int x = (int)Math.Floor(source.X);
- int height = (int)Math.Ceiling(source.Height);
- return new Rectangle(x, y, width, height);
+ this.X -= width;
+ this.Y -= height;
+
+ this.Width += 2 * width;
+ this.Height += 2 * height;
}
///
- /// Outsets the specified region.
+ /// Inflates this by the specified amount.
///
- /// The region.
- /// The width.
- ///
- /// The with all dimensions move away from the center by the offset.
- ///
- public static RectangleF Outset(RectangleF region, float width)
- {
- float dblWidth = width * 2;
- return new RectangleF(region.X - width, region.Y - width, region.Width + dblWidth, region.Height + dblWidth);
- }
+ /// The size
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Inflate(SizeF size) => this.Inflate(size.Width, size.Height);
///
/// Determines if the specfied point is contained within the rectangular region defined by
@@ -260,75 +312,89 @@ namespace ImageSharp
/// The x-coordinate of the given point.
/// The y-coordinate of the given point.
/// The
- public bool Contains(float x, float y)
- {
- // TODO: SIMD?
- return this.X <= x
- && x < this.Right
- && this.Y <= y
- && y < this.Bottom;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Contains(float x, float y) => this.X <= x && x < this.Right && this.Y <= y && y < this.Bottom;
+
+ ///
+ /// Determines if the specified point is contained within the rectangular region defined by this .
+ ///
+ /// The point
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Contains(PointF point) => this.Contains(point.X, point.Y);
+
+ ///
+ /// Determines if the rectangular region represented by is entirely contained
+ /// within the rectangular region represented by this .
+ ///
+ /// The rectangle
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Contains(RectangleF rectangle) =>
+ (this.X <= rectangle.X) && (rectangle.Right <= this.Right) &&
+ (this.Y <= rectangle.Y) && (rectangle.Bottom <= this.Bottom);
///
- /// Determines if the specfied intersects the rectangular region defined by
- /// this .
+ /// Determines if the specfied intersects the rectangular region defined by
+ /// this .
///
- /// The other Rectange
+ /// The other Rectange
/// The
- public bool Intersects(RectangleF rect)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IntersectsWith(RectangleF rectangle) =>
+ (rectangle.X < this.Right) && (this.X < rectangle.Right) &&
+ (rectangle.Y < this.Bottom) && (this.Y < rectangle.Bottom);
+
+ ///
+ /// Adjusts the location of this rectangle by the specified amount.
+ ///
+ /// The point
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Offset(PointF point) => this.Offset(point.X, point.Y);
+
+ ///
+ /// Adjusts the location of this rectangle by the specified amount.
+ ///
+ /// The amount to offset the x-coordinate.
+ /// The amount to offset the y-coordinate.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Offset(float dx, float dy)
{
- return rect.Left <= this.Right && rect.Right >= this.Left
- &&
- rect.Top <= this.Bottom && rect.Bottom >= this.Top;
+ this.X += dx;
+ this.Y += dy;
}
///
- public override int GetHashCode()
- {
- return this.GetHashCode(this);
- }
+ public override int GetHashCode() => this.GetHashCode(this);
///
public override string ToString()
{
if (this.IsEmpty)
{
- return "Rectangle [ Empty ]";
+ return "RectangleF [ Empty ]";
}
- return
- $"Rectangle [ X={this.X}, Y={this.Y}, Width={this.Width}, Height={this.Height} ]";
+ return $"RectangleF [ X={this.X}, Y={this.Y}, Width={this.Width}, Height={this.Height} ]";
}
///
- public override bool Equals(object obj)
- {
- if (obj is RectangleF)
- {
- return this.Equals((RectangleF)obj);
- }
-
- return false;
- }
+ public override bool Equals(object obj) => obj is RectangleF && this.Equals((RectangleF)obj);
///
- public bool Equals(RectangleF other)
- {
- return this.backingVector.Equals(other.backingVector);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(RectangleF other) => this.X.Equals(other.X) && this.Y.Equals(other.Y) && this.Width.Equals(other.Width) && this.Height.Equals(other.Height);
- ///
- /// Returns the hash code for this instance.
- ///
- ///
- /// The instance of to return the hash code for.
- ///
- ///
- /// A 32-bit signed integer that is the hash code for this instance.
- ///
private int GetHashCode(RectangleF rectangle)
{
- return rectangle.backingVector.GetHashCode();
+ unchecked
+ {
+ int hashCode = rectangle.X.GetHashCode();
+ hashCode = (hashCode * 397) ^ rectangle.Y.GetHashCode();
+ hashCode = (hashCode * 397) ^ rectangle.Width.GetHashCode();
+ hashCode = (hashCode * 397) ^ rectangle.Height.GetHashCode();
+ return hashCode;
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Numerics/Size.cs b/src/ImageSharp/Numerics/Size.cs
index bae645ac8e..79ee1ddead 100644
--- a/src/ImageSharp/Numerics/Size.cs
+++ b/src/ImageSharp/Numerics/Size.cs
@@ -23,6 +23,17 @@ namespace ImageSharp
///
public static readonly Size Empty = default(Size);
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The width and height of the size
+ public Size(int value)
+ : this()
+ {
+ this.Width = value;
+ this.Height = value;
+ }
+
///
/// Initializes a new instance of the struct.
///
@@ -34,6 +45,27 @@ namespace ImageSharp
this.Height = height;
}
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The size
+ public Size(Size size)
+ : this()
+ {
+ this.Width = size.Width;
+ this.Height = size.Height;
+ }
+
+ ///
+ /// Initializes a new instance of the struct from the given .
+ ///
+ /// The point
+ public Size(Point point)
+ {
+ this.Width = point.X;
+ this.Height = point.Y;
+ }
+
///
/// Gets or sets the width of this .
///
@@ -50,6 +82,20 @@ namespace ImageSharp
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.Equals(Empty);
+ ///
+ /// Creates a with the dimensions of the specified .
+ ///
+ /// The point
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator SizeF(Size size) => new SizeF(size.Width, size.Height);
+
+ ///
+ /// Converts the given into a .
+ ///
+ /// The size
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Point(Size size) => new Point(size.Width, size.Height);
+
///
/// Computes the sum of adding two sizes.
///
@@ -59,10 +105,7 @@ namespace ImageSharp
/// The
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Size operator +(Size left, Size right)
- {
- return new Size(left.Width + right.Width, left.Height + right.Height);
- }
+ public static Size operator +(Size left, Size right) => Add(left, right);
///
/// Computes the difference left by subtracting one size from another.
@@ -73,10 +116,7 @@ namespace ImageSharp
/// The
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Size operator -(Size left, Size right)
- {
- return new Size(left.Width - right.Width, left.Height - right.Height);
- }
+ public static Size operator -(Size left, Size right) => Subtract(left, right);
///
/// Compares two objects for equality.
@@ -91,10 +131,7 @@ namespace ImageSharp
/// True if the current left is equal to the parameter; otherwise, false.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool operator ==(Size left, Size right)
- {
- return left.Equals(right);
- }
+ public static bool operator ==(Size left, Size right) => left.Equals(right);
///
/// Compares two objects for inequality.
@@ -109,16 +146,52 @@ namespace ImageSharp
/// True if the current left is unequal to the parameter; otherwise, false.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool operator !=(Size left, Size right)
- {
- return !left.Equals(right);
- }
+ public static bool operator !=(Size left, Size right) => !left.Equals(right);
+
+ ///
+ /// Performs vector addition of two objects.
+ ///
+ /// The size on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Size Add(Size left, Size right) => new Size(unchecked(left.Width + right.Width), unchecked(left.Height + right.Height));
+
+ ///
+ /// Contracts a by another
+ ///
+ /// The size on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Size Subtract(Size left, Size right) => new Size(unchecked(left.Width - right.Width), unchecked(left.Height - right.Height));
+
+ ///
+ /// Converts a to a by performing a ceiling operation on all the dimensions.
+ ///
+ /// The size
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Size Ceiling(SizeF size) => new Size(unchecked((int)MathF.Ceiling(size.Width)), unchecked((int)MathF.Ceiling(size.Height)));
+
+ ///
+ /// Converts a to a by performing a round operation on all the dimensions.
+ ///
+ /// The size
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Size Round(SizeF size) => new Size(unchecked((int)MathF.Round(size.Width)), unchecked((int)MathF.Round(size.Height)));
+
+ ///
+ /// Converts a to a by performing a round operation on all the dimensions.
+ ///
+ /// The size
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Size Truncate(SizeF size) => new Size(unchecked((int)size.Width), unchecked((int)size.Height));
///
- public override int GetHashCode()
- {
- return this.GetHashCode(this);
- }
+ public override int GetHashCode() => this.GetHashCode(this);
///
public override string ToString()
@@ -132,22 +205,11 @@ namespace ImageSharp
}
///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override bool Equals(object obj)
- {
- if (obj is Size)
- {
- return this.Equals((Size)obj);
- }
-
- return false;
- }
+ public override bool Equals(object obj) => obj is Size && this.Equals((Size)obj);
///
- public bool Equals(Size other)
- {
- return this.Width == other.Width && this.Height == other.Height;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(Size other) => this.Width == other.Width && this.Height == other.Height;
///
/// Returns the hash code for this instance.
@@ -158,9 +220,6 @@ namespace ImageSharp
///
/// A 32-bit signed integer that is the hash code for this instance.
///
- private int GetHashCode(Size size)
- {
- return size.Width ^ size.Height;
- }
+ private int GetHashCode(Size size) => size.Width ^ size.Height;
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Numerics/SizeF.cs b/src/ImageSharp/Numerics/SizeF.cs
new file mode 100644
index 0000000000..78078fd01f
--- /dev/null
+++ b/src/ImageSharp/Numerics/SizeF.cs
@@ -0,0 +1,179 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.ComponentModel;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Stores an ordered pair of single precision floating points, which specify a height and width.
+ ///
+ ///
+ /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
+ /// as it avoids the need to create new values for modification operations.
+ ///
+ public struct SizeF : IEquatable
+ {
+ ///
+ /// Represents a that has Width and Height values set to zero.
+ ///
+ public static readonly SizeF Empty = default(SizeF);
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The width of the size.
+ /// The height of the size.
+ public SizeF(float width, float height)
+ {
+ this.Width = width;
+ this.Height = height;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The size
+ public SizeF(SizeF size)
+ : this()
+ {
+ this.Width = size.Width;
+ this.Height = size.Height;
+ }
+
+ ///
+ /// Initializes a new instance of the struct from the given .
+ ///
+ /// The point
+ public SizeF(PointF point)
+ {
+ this.Width = point.X;
+ this.Height = point.Y;
+ }
+
+ ///
+ /// Gets or sets the width of this .
+ ///
+ public float Width { get; set; }
+
+ ///
+ /// Gets or sets the height of this .
+ ///
+ public float Height { get; set; }
+
+ ///
+ /// Gets a value indicating whether this is empty.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool IsEmpty => this.Equals(Empty);
+
+ ///
+ /// Creates a with the dimensions of the specified by truncating each of the dimensions.
+ ///
+ /// The size.
+ ///
+ /// The .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Size(SizeF size) => new Size(unchecked((int)size.Width), unchecked((int)size.Height));
+
+ ///
+ /// Converts the given into a .
+ ///
+ /// The size
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator PointF(SizeF size) => new PointF(size.Width, size.Height);
+
+ ///
+ /// Computes the sum of adding two sizes.
+ ///
+ /// The size on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ ///
+ /// The
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static SizeF operator +(SizeF left, SizeF right) => Add(left, right);
+
+ ///
+ /// Computes the difference left by subtracting one size from another.
+ ///
+ /// The size on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ ///
+ /// The
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static SizeF operator -(SizeF left, SizeF right) => Subtract(left, right);
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ /// The size on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ ///
+ /// True if the current left is equal to the parameter; otherwise, false.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator ==(SizeF left, SizeF right) => left.Equals(right);
+
+ ///
+ /// Compares two objects for inequality.
+ ///
+ /// The size on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ ///
+ /// True if the current left is unequal to the parameter; otherwise, false.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator !=(SizeF left, SizeF right) => !left.Equals(right);
+
+ ///
+ /// Performs vector addition of two objects.
+ ///
+ /// The size on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static SizeF Add(SizeF left, SizeF right) => new SizeF(left.Width + right.Width, left.Height + right.Height);
+
+ ///
+ /// Contracts a by another
+ ///
+ /// The size on the left hand of the operand.
+ /// The size on the right hand of the operand.
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static SizeF Subtract(SizeF left, SizeF right) => new SizeF(left.Width - right.Width, left.Height - right.Height);
+
+ ///
+ public override int GetHashCode()
+ {
+ return this.GetHashCode(this);
+ }
+
+ ///
+ public override string ToString()
+ {
+ if (this.IsEmpty)
+ {
+ return "SizeF [ Empty ]";
+ }
+
+ return $"SizeF [ Width={this.Width}, Height={this.Height} ]";
+ }
+
+ ///
+ public override bool Equals(object obj) => obj is SizeF && this.Equals((SizeF)obj);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(SizeF other) => this.Width.Equals(other.Width) && this.Height.Equals(other.Height);
+
+ private int GetHashCode(SizeF size) => size.Width.GetHashCode() ^ size.Height.GetHashCode();
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs
index c184ed9cf6..59934fdc64 100644
--- a/src/ImageSharp/PixelFormats/Alpha8.cs
+++ b/src/ImageSharp/PixelFormats/Alpha8.cs
@@ -62,7 +62,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -80,47 +80,43 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- this.PackedValue = w;
+ this.PackedValue = source.A;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- bytes[startIndex] = 0;
- bytes[startIndex + 1] = 0;
- bytes[startIndex + 2] = 0;
+ dest = default(Rgb24);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- bytes[startIndex] = 0;
- bytes[startIndex + 1] = 0;
- bytes[startIndex + 2] = 0;
- bytes[startIndex + 3] = this.PackedValue;
+ dest.R = 0;
+ dest.G = 0;
+ dest.B = 0;
+ dest.A = this.PackedValue;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- bytes[startIndex] = 0;
- bytes[startIndex + 1] = 0;
- bytes[startIndex + 2] = 0;
+ dest = default(Bgr24);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- bytes[startIndex] = 0;
- bytes[startIndex + 1] = 0;
- bytes[startIndex + 2] = 0;
- bytes[startIndex + 3] = this.PackedValue;
+ dest.R = 0;
+ dest.G = 0;
+ dest.B = 0;
+ dest.A = this.PackedValue;
}
///
diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs
index bd47f72f93..f389723dc3 100644
--- a/src/ImageSharp/PixelFormats/Argb32.cs
+++ b/src/ImageSharp/PixelFormats/Argb32.cs
@@ -59,11 +59,24 @@ namespace ImageSharp.PixelFormats
/// The green component.
/// The blue component.
/// The alpha component.
- public Argb32(byte r, byte g, byte b, byte a = 255)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Argb32(byte r, byte g, byte b, byte a)
{
this.PackedValue = Pack(r, g, b, a);
}
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The red component.
+ /// The green component.
+ /// The blue component.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Argb32(byte r, byte g, byte b)
+ {
+ this.PackedValue = Pack(r, g, b, 255);
+ }
+
///
/// Initializes a new instance of the struct.
///
@@ -224,7 +237,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -235,47 +248,47 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- this.PackedValue = Pack(x, y, z, w);
+ this.PackedValue = Pack(source.R, source.G, source.B, source.A);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- bytes[startIndex] = this.R;
- bytes[startIndex + 1] = this.G;
- bytes[startIndex + 2] = this.B;
+ dest.R = this.R;
+ dest.G = this.G;
+ dest.B = this.B;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- bytes[startIndex] = this.R;
- bytes[startIndex + 1] = this.G;
- bytes[startIndex + 2] = this.B;
- bytes[startIndex + 3] = this.A;
+ dest.R = this.R;
+ dest.G = this.G;
+ dest.B = this.B;
+ dest.A = this.A;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- bytes[startIndex] = this.B;
- bytes[startIndex + 1] = this.G;
- bytes[startIndex + 2] = this.R;
+ dest.R = this.R;
+ dest.G = this.G;
+ dest.B = this.B;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- bytes[startIndex] = this.B;
- bytes[startIndex + 1] = this.G;
- bytes[startIndex + 2] = this.R;
- bytes[startIndex + 3] = this.A;
+ dest.R = this.R;
+ dest.G = this.G;
+ dest.B = this.B;
+ dest.A = this.A;
}
///
diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs
new file mode 100644
index 0000000000..aaed5c3852
--- /dev/null
+++ b/src/ImageSharp/PixelFormats/Bgr24.cs
@@ -0,0 +1,135 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.PixelFormats
+{
+ using System;
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
+
+ ///
+ /// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255.
+ /// The color components are stored in blue, green, red order.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Bgr24 : IPixel
+ {
+ ///
+ /// The blue component.
+ ///
+ public byte B;
+
+ ///
+ /// The green component.
+ ///
+ public byte G;
+
+ ///
+ /// The red component.
+ ///
+ public byte R;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The red component.
+ /// The green component.
+ /// The blue component.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Bgr24(byte r, byte g, byte b)
+ {
+ this.R = r;
+ this.G = g;
+ this.B = b;
+ }
+
+ ///
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool Equals(Bgr24 other)
+ {
+ return this.R == other.R && this.G == other.G && this.B == other.B;
+ }
+
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj?.GetType() == typeof(Bgr24) && this.Equals((Bgr24)obj);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hashCode = this.B;
+ hashCode = (hashCode * 397) ^ this.G;
+ hashCode = (hashCode * 397) ^ this.R;
+ return hashCode;
+ }
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void PackFromRgba32(Rgba32 source)
+ {
+ this = source.Bgr;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void PackFromVector4(Vector4 vector)
+ {
+ var rgba = default(Rgba32);
+ rgba.PackFromVector4(vector);
+ this.PackFromRgba32(rgba);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector4 ToVector4()
+ {
+ return new Rgba32(this.R, this.G, this.B, 255).ToVector4();
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void ToRgb24(ref Rgb24 dest)
+ {
+ dest.R = this.R;
+ dest.G = this.G;
+ dest.B = this.B;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void ToRgba32(ref Rgba32 dest)
+ {
+ dest.R = this.R;
+ dest.G = this.G;
+ dest.B = this.B;
+ dest.A = 255;
+ }
+
+ ///
+ public void ToBgr24(ref Bgr24 dest)
+ {
+ dest = this;
+ }
+
+ ///
+ public void ToBgra32(ref Bgra32 dest)
+ {
+ dest.R = this.R;
+ dest.G = this.G;
+ dest.B = this.B;
+ dest.A = 255;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs
index 92bbac14cc..af22b14a09 100644
--- a/src/ImageSharp/PixelFormats/Bgr565.cs
+++ b/src/ImageSharp/PixelFormats/Bgr565.cs
@@ -71,7 +71,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
/// Expands the packed representation into a .
@@ -103,51 +103,51 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- this.PackFromVector4(new Vector4(x, y, z, w) / 255F);
+ this.PackFromVector4(source.ToVector4());
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)MathF.Round(vector.X);
- bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
- bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = (byte)MathF.Round(vector.Z);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
- 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);
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = (byte)MathF.Round(vector.Z);
+ dest.A = (byte)MathF.Round(vector.W);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)MathF.Round(vector.Z);
- bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
- bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = (byte)MathF.Round(vector.Z);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
- 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);
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = (byte)MathF.Round(vector.Z);
+ dest.A = (byte)MathF.Round(vector.W);
}
///
diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs
new file mode 100644
index 0000000000..f1ac20b567
--- /dev/null
+++ b/src/ImageSharp/PixelFormats/Bgra32.cs
@@ -0,0 +1,187 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.PixelFormats
+{
+ using System;
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
+
+ ///
+ /// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
+ /// The color components are stored in blue, green, red, and alpha order.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Bgra32 : IPixel, IPackedVector
+ {
+ ///
+ /// Gets or sets the blue component.
+ ///
+ public byte B;
+
+ ///
+ /// Gets or sets the green component.
+ ///
+ public byte G;
+
+ ///
+ /// Gets or sets the red component.
+ ///
+ public byte R;
+
+ ///
+ /// Gets or sets the alpha component.
+ ///
+ public byte A;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The red component.
+ /// The green component.
+ /// The blue component.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Bgra32(byte r, byte g, byte b)
+ {
+ this.R = r;
+ this.G = g;
+ this.B = b;
+ this.A = 255;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The red component.
+ /// The green component.
+ /// The blue component.
+ /// The alpha component.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Bgra32(byte r, byte g, byte b, byte a)
+ {
+ this.R = r;
+ this.G = g;
+ this.B = b;
+ this.A = a;
+ }
+
+ ///
+ /// Gets or sets the packed representation of the Bgra32 struct.
+ ///
+ public uint Bgra
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return Unsafe.As(ref this);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set
+ {
+ Unsafe.As(ref this) = value;
+ }
+ }
+
+ ///
+ public uint PackedValue
+ {
+ get => this.Bgra;
+ set => this.Bgra = value;
+ }
+
+ ///
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
+
+ ///
+ public bool Equals(Bgra32 other)
+ {
+ return this.R == other.R && this.G == other.G && this.B == other.B && this.A == other.A;
+ }
+
+ ///
+ public override bool Equals(object obj) => obj?.GetType() == typeof(Bgra32) && this.Equals((Bgra32)obj);
+
+ ///
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hashCode = this.B;
+ hashCode = (hashCode * 397) ^ this.G;
+ hashCode = (hashCode * 397) ^ this.R;
+ hashCode = (hashCode * 397) ^ this.A;
+ return hashCode;
+ }
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void PackFromVector4(Vector4 vector)
+ {
+ var rgba = default(Rgba32);
+ rgba.PackFromVector4(vector);
+ this.PackFromRgba32(rgba);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector4 ToVector4()
+ {
+ return this.ToRgba32().ToVector4();
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void PackFromRgba32(Rgba32 source)
+ {
+ this.R = source.R;
+ this.G = source.G;
+ this.B = source.B;
+ this.A = source.A;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void ToRgb24(ref Rgb24 dest)
+ {
+ dest.R = this.R;
+ dest.G = this.G;
+ dest.B = this.B;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void ToRgba32(ref Rgba32 dest)
+ {
+ dest.R = this.R;
+ dest.G = this.G;
+ dest.B = this.B;
+ dest.A = this.A;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void ToBgr24(ref Bgr24 dest)
+ {
+ dest = Unsafe.As(ref this);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void ToBgra32(ref Bgra32 dest)
+ {
+ dest = this;
+ }
+
+ ///
+ /// Converts the pixel to format.
+ ///
+ /// The RGBA value
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A);
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs
index 0bac00dfe3..746e1062ba 100644
--- a/src/ImageSharp/PixelFormats/Bgra4444.cs
+++ b/src/ImageSharp/PixelFormats/Bgra4444.cs
@@ -70,7 +70,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -79,10 +79,10 @@ namespace ImageSharp.PixelFormats
const float Max = 1 / 15F;
return new Vector4(
- ((this.PackedValue >> 8) & 0x0F) * Max,
- ((this.PackedValue >> 4) & 0x0F) * Max,
- (this.PackedValue & 0x0F) * Max,
- ((this.PackedValue >> 12) & 0x0F) * Max);
+ ((this.PackedValue >> 8) & 0x0F) * Max,
+ ((this.PackedValue >> 4) & 0x0F) * Max,
+ (this.PackedValue & 0x0F) * Max,
+ ((this.PackedValue >> 12) & 0x0F) * Max);
}
///
@@ -94,51 +94,51 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- this.PackFromVector4(new Vector4(x, y, z, w) / 255F);
+ this.PackFromVector4(source.ToVector4());
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
- bytes[startIndex + 3] = (byte)vector.W;
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
- bytes[startIndex + 3] = (byte)vector.W;
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
@@ -179,9 +179,9 @@ namespace ImageSharp.PixelFormats
private static ushort Pack(float x, float y, float z, float w)
{
return (ushort)((((int)Math.Round(w.Clamp(0, 1) * 15F) & 0x0F) << 12) |
- (((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) |
- (((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) |
- ((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F));
+ (((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) |
+ (((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) |
+ ((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F));
}
}
}
diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs
index f151db644a..198f911088 100644
--- a/src/ImageSharp/PixelFormats/Bgra5551.cs
+++ b/src/ImageSharp/PixelFormats/Bgra5551.cs
@@ -72,7 +72,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -94,51 +94,51 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- this.PackFromVector4(new Vector4(x, y, z, w) / 255F);
+ this.PackFromVector4(source.ToVector4());
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- Vector4 vector = this.ToVector4() * 255F;
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
@@ -190,5 +190,8 @@ namespace ImageSharp.PixelFormats
(((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F) << 0) |
(((int)Math.Round(w.Clamp(0, 1)) & 0x1) << 15));
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Vector4 ToScaledVector4() => this.ToVector4() * 255f;
}
}
diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs
index 264bc74972..14053ba122 100644
--- a/src/ImageSharp/PixelFormats/Byte4.cs
+++ b/src/ImageSharp/PixelFormats/Byte4.cs
@@ -73,7 +73,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -95,51 +95,51 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- this.PackFromVector4(new Vector4(x, y, z, w));
+ this.PackFromVector4(source.ToUnscaledVector4());
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToVector4();
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToVector4();
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
- bytes[startIndex + 3] = (byte)vector.W;
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToVector4();
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToVector4();
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
- bytes[startIndex + 3] = (byte)vector.W;
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
index 4b21130c0d..92fb006abf 100644
--- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
+++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
@@ -35,12 +35,13 @@ namespace ImageSharp.PixelFormats
}
TPixel result = default(TPixel);
-
- result.PackFromBytes(
+ Rgba32 rgba = new Rgba32(
(byte)(packedValue >> 24),
(byte)(packedValue >> 16),
(byte)(packedValue >> 8),
(byte)(packedValue >> 0));
+
+ result.PackFromRgba32(rgba);
return result;
}
@@ -51,12 +52,7 @@ namespace ImageSharp.PixelFormats
/// The green intensity.
/// The blue intensity.
/// Returns a that represents the color defined by the provided RGB values with 100% opacity.
- public static TPixel FromRGB(byte red, byte green, byte blue)
- {
- TPixel color = default(TPixel);
- color.PackFromBytes(red, green, blue, 255);
- return color;
- }
+ public static TPixel FromRGB(byte red, byte green, byte blue) => FromRGBA(red, green, blue, 255);
///
/// Creates a new representation from standard RGBA bytes.
@@ -69,7 +65,7 @@ namespace ImageSharp.PixelFormats
public static TPixel FromRGBA(byte red, byte green, byte blue, byte alpha)
{
TPixel color = default(TPixel);
- color.PackFromBytes(red, green, blue, alpha);
+ color.PackFromRgba32(new Rgba32(red, green, blue, alpha));
return color;
}
diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs
new file mode 100644
index 0000000000..c042d76786
--- /dev/null
+++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs
@@ -0,0 +1,302 @@
+//
+
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.PixelFormats
+{
+ using System;
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+
+ public partial class PixelOperations
+ {
+
+ ///
+ /// Converts 'count' elements in 'source` span of data to a span of -s.
+ ///
+ /// The source of data.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ internal virtual void PackFromRgba32(Span source, Span destPixels, int count)
+ {
+ GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
+
+ ref Rgba32 sourceRef = ref source.DangerousGetPinnableReference();
+ ref TPixel destRef = ref destPixels.DangerousGetPinnableReference();
+
+ Rgba32 rgba = new Rgba32(0, 0, 0, 255);
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel dp = ref Unsafe.Add(ref destRef, i);
+ rgba = Unsafe.Add(ref sourceRef, i);
+ dp.PackFromRgba32(rgba);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span.
+ /// The layout of the data in 'sourceBytes' must be compatible with layout.
+ ///
+ /// The to the source bytes.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void PackFromRgba32Bytes(Span sourceBytes, Span destPixels, int count)
+ {
+ this.PackFromRgba32(sourceBytes.NonPortableCast(), destPixels, count);
+ }
+
+ ///
+ /// Converts 'count' pixels in 'sourcePixels` span to a span of -s.
+ /// Bulk version of .
+ ///
+ /// The span of source pixels
+ /// The destination span of data.
+ /// The number of pixels to convert.
+ internal virtual void ToRgba32(Span sourcePixels, Span dest, int count)
+ {
+ GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
+
+ ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference();
+ ref Rgba32 destBaseRef = ref dest.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
+ ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i);
+ sp.ToRgba32(ref dp);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span as destination.
+ /// The layout of the data in 'destBytes' must be compatible with layout.
+ ///
+ /// The to the source colors.
+ /// The to the destination bytes.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void ToRgba32Bytes(Span sourceColors, Span destBytes, int count)
+ {
+ this.ToRgba32(sourceColors, destBytes.NonPortableCast(), count);
+ }
+
+ ///
+ /// Converts 'count' elements in 'source` span of data to a span of -s.
+ ///
+ /// The source of data.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ internal virtual void PackFromBgra32(Span source, Span destPixels, int count)
+ {
+ GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
+
+ ref Bgra32 sourceRef = ref source.DangerousGetPinnableReference();
+ ref TPixel destRef = ref destPixels.DangerousGetPinnableReference();
+
+ Rgba32 rgba = new Rgba32(0, 0, 0, 255);
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel dp = ref Unsafe.Add(ref destRef, i);
+ rgba = Unsafe.Add(ref sourceRef, i).ToRgba32();
+ dp.PackFromRgba32(rgba);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span.
+ /// The layout of the data in 'sourceBytes' must be compatible with layout.
+ ///
+ /// The to the source bytes.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void PackFromBgra32Bytes(Span sourceBytes, Span destPixels, int count)
+ {
+ this.PackFromBgra32(sourceBytes.NonPortableCast(), destPixels, count);
+ }
+
+ ///
+ /// Converts 'count' pixels in 'sourcePixels` span to a span of -s.
+ /// Bulk version of .
+ ///
+ /// The span of source pixels
+ /// The destination span of data.
+ /// The number of pixels to convert.
+ internal virtual void ToBgra32(Span sourcePixels, Span dest, int count)
+ {
+ GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
+
+ ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference();
+ ref Bgra32 destBaseRef = ref dest.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
+ ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i);
+ sp.ToBgra32(ref dp);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span as destination.
+ /// The layout of the data in 'destBytes' must be compatible with layout.
+ ///
+ /// The to the source colors.
+ /// The to the destination bytes.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void ToBgra32Bytes(Span sourceColors, Span destBytes, int count)
+ {
+ this.ToBgra32(sourceColors, destBytes.NonPortableCast(), count);
+ }
+
+ ///
+ /// Converts 'count' elements in 'source` span of data to a span of -s.
+ ///
+ /// The source of data.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ internal virtual void PackFromRgb24(Span source, Span destPixels, int count)
+ {
+ GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
+
+ ref Rgb24 sourceRef = ref source.DangerousGetPinnableReference();
+ ref TPixel destRef = ref destPixels.DangerousGetPinnableReference();
+
+ Rgba32 rgba = new Rgba32(0, 0, 0, 255);
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel dp = ref Unsafe.Add(ref destRef, i);
+ rgba.Rgb = Unsafe.Add(ref sourceRef, i);
+ dp.PackFromRgba32(rgba);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span.
+ /// The layout of the data in 'sourceBytes' must be compatible with layout.
+ ///
+ /// The to the source bytes.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void PackFromRgb24Bytes(Span sourceBytes, Span destPixels, int count)
+ {
+ this.PackFromRgb24(sourceBytes.NonPortableCast(), destPixels, count);
+ }
+
+ ///
+ /// Converts 'count' pixels in 'sourcePixels` span to a span of -s.
+ /// Bulk version of .
+ ///
+ /// The span of source pixels
+ /// The destination span of data.
+ /// The number of pixels to convert.
+ internal virtual void ToRgb24(Span sourcePixels, Span dest, int count)
+ {
+ GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
+
+ ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference();
+ ref Rgb24 destBaseRef = ref dest.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
+ ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i);
+ sp.ToRgb24(ref dp);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span as destination.
+ /// The layout of the data in 'destBytes' must be compatible with layout.
+ ///
+ /// The to the source colors.
+ /// The to the destination bytes.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void ToRgb24Bytes(Span sourceColors, Span destBytes, int count)
+ {
+ this.ToRgb24(sourceColors, destBytes.NonPortableCast(), count);
+ }
+
+ ///
+ /// Converts 'count' elements in 'source` span of data to a span of -s.
+ ///
+ /// The source of data.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ internal virtual void PackFromBgr24(Span source, Span destPixels, int count)
+ {
+ GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
+
+ ref Bgr24 sourceRef = ref source.DangerousGetPinnableReference();
+ ref TPixel destRef = ref destPixels.DangerousGetPinnableReference();
+
+ Rgba32 rgba = new Rgba32(0, 0, 0, 255);
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel dp = ref Unsafe.Add(ref destRef, i);
+ rgba.Bgr = Unsafe.Add(ref sourceRef, i);
+ dp.PackFromRgba32(rgba);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span.
+ /// The layout of the data in 'sourceBytes' must be compatible with layout.
+ ///
+ /// The to the source bytes.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void PackFromBgr24Bytes(Span sourceBytes, Span destPixels, int count)
+ {
+ this.PackFromBgr24(sourceBytes.NonPortableCast(), destPixels, count);
+ }
+
+ ///
+ /// Converts 'count' pixels in 'sourcePixels` span to a span of -s.
+ /// Bulk version of .
+ ///
+ /// The span of source pixels
+ /// The destination span of data.
+ /// The number of pixels to convert.
+ internal virtual void ToBgr24(Span sourcePixels, Span dest, int count)
+ {
+ GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
+
+ ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference();
+ ref Bgr24 destBaseRef = ref dest.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
+ ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i);
+ sp.ToBgr24(ref dp);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span as destination.
+ /// The layout of the data in 'destBytes' must be compatible with layout.
+ ///
+ /// The to the source colors.
+ /// The to the destination bytes.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void ToBgr24Bytes(Span sourceColors, Span destBytes, int count)
+ {
+ this.ToBgr24(sourceColors, destBytes.NonPortableCast(), count);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt
new file mode 100644
index 0000000000..16292489fc
--- /dev/null
+++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt
@@ -0,0 +1,130 @@
+<#
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+#>
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ assembly name="System.Core" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Text" #>
+<#@ import namespace="System.Collections.Generic" #>
+<#@ output extension=".cs" #>
+<#
+ void GenerateToDestFormatMethods(string pixelType)
+ {
+ #>
+
+ ///
+ /// Converts 'count' pixels in 'sourcePixels` span to a span of -s.
+ /// Bulk version of .
+ ///
+ /// The span of source pixels
+ /// The destination span of data.
+ /// The number of pixels to convert.
+ internal virtual void To<#=pixelType#>(Span sourcePixels, Span<<#=pixelType#>> dest, int count)
+ {
+ GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
+
+ ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference();
+ ref <#=pixelType#> destBaseRef = ref dest.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
+ ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i);
+ sp.To<#=pixelType#>(ref dp);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span as destination.
+ /// The layout of the data in 'destBytes' must be compatible with layout.
+ ///
+ /// The to the source colors.
+ /// The to the destination bytes.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void To<#=pixelType#>Bytes(Span sourceColors, Span destBytes, int count)
+ {
+ this.To<#=pixelType#>(sourceColors, destBytes.NonPortableCast>(), count);
+ }
+ <#
+ }
+
+ void GeneratePackFromMethodUsingPackFromRgba32(string pixelType, string rgbaOperationCode)
+ {
+ #>
+
+ ///
+ /// Converts 'count' elements in 'source` span of data to a span of -s.
+ ///
+ /// The source of data.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ internal virtual void PackFrom<#=pixelType#>(Span<<#=pixelType#>> source, Span destPixels, int count)
+ {
+ GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
+
+ ref <#=pixelType#> sourceRef = ref source.DangerousGetPinnableReference();
+ ref TPixel destRef = ref destPixels.DangerousGetPinnableReference();
+
+ Rgba32 rgba = new Rgba32(0, 0, 0, 255);
+
+ for (int i = 0; i < count; i++)
+ {
+ ref TPixel dp = ref Unsafe.Add(ref destRef, i);
+ <#=rgbaOperationCode#>
+ dp.PackFromRgba32(rgba);
+ }
+ }
+
+ ///
+ /// A helper for that expects a byte span.
+ /// The layout of the data in 'sourceBytes' must be compatible with layout.
+ ///
+ /// The to the source bytes.
+ /// The to the destination pixels.
+ /// The number of pixels to convert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void PackFrom<#=pixelType#>Bytes(Span sourceBytes, Span destPixels, int count)
+ {
+ this.PackFrom<#=pixelType#>(sourceBytes.NonPortableCast>(), destPixels, count);
+ }
+ <#
+ }
+
+#>
+//
+
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.PixelFormats
+{
+ using System;
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+
+ public partial class PixelOperations
+ {
+ <#
+
+ GeneratePackFromMethodUsingPackFromRgba32("Rgba32", "rgba = Unsafe.Add(ref sourceRef, i);");
+ GenerateToDestFormatMethods("Rgba32");
+
+ GeneratePackFromMethodUsingPackFromRgba32("Bgra32", "rgba = Unsafe.Add(ref sourceRef, i).ToRgba32();");
+ GenerateToDestFormatMethods("Bgra32");
+
+ GeneratePackFromMethodUsingPackFromRgba32("Rgb24", "rgba.Rgb = Unsafe.Add(ref sourceRef, i);");
+ GenerateToDestFormatMethods("Rgb24");
+
+ GeneratePackFromMethodUsingPackFromRgba32("Bgr24", "rgba.Bgr = Unsafe.Add(ref sourceRef, i);");
+ GenerateToDestFormatMethods("Bgr24");
+
+ #>
+
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs
new file mode 100644
index 0000000000..e42c575d89
--- /dev/null
+++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs
@@ -0,0 +1,130 @@
+//
+
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
+
+ using ImageSharp.Memory;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Provides optimized overrides for bulk operations.
+ ///
+ public partial struct Rgba32
+ {
+ internal partial class PixelOperations : PixelOperations
+ {
+
+ ///
+ internal override void PackFromRgb24(Span source, Span destPixels, int count)
+ {
+ GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
+
+ ref Rgb24 sourceRef = ref source.DangerousGetPinnableReference();
+ ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
+ ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
+ Unsafe.As(ref dp) = sp; dp.A = 255;
+ }
+ }
+
+
+ ///
+ internal override void ToRgb24(Span sourcePixels, Span dest, int count)
+ {
+ GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
+
+ ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference();
+ ref Rgb24 destRef = ref dest.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
+ ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
+ dp = Unsafe.As(ref sp);
+ }
+ }
+
+
+ ///
+ internal override void PackFromBgr24(Span source, Span destPixels, int count)
+ {
+ GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
+
+ ref Bgr24 sourceRef = ref source.DangerousGetPinnableReference();
+ ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
+ ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
+ dp.Bgr = sp; dp.A = 255;
+ }
+ }
+
+
+ ///
+ internal override void ToBgr24(Span sourcePixels, Span dest, int count)
+ {
+ GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
+
+ ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference();
+ ref Bgr24 destRef = ref dest.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
+ ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
+ dp = sp.Bgr;
+ }
+ }
+
+
+ ///
+ internal override void PackFromBgra32(Span source, Span destPixels, int count)
+ {
+ GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
+
+ ref Bgra32 sourceRef = ref source.DangerousGetPinnableReference();
+ ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
+ ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
+ dp = sp.ToRgba32();
+ }
+ }
+
+
+ ///
+ internal override void ToBgra32(Span sourcePixels, Span dest, int count)
+ {
+ GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
+
+ ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference();
+ ref Bgra32 destRef = ref dest.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
+ ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
+ dp = sp.ToBgra32();
+ }
+ }
+
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt
new file mode 100644
index 0000000000..9c01fa9157
--- /dev/null
+++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt
@@ -0,0 +1,99 @@
+<#
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+#>
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ assembly name="System.Core" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Text" #>
+<#@ import namespace="System.Collections.Generic" #>
+<#@ output extension=".cs" #>
+<#
+
+ void GeneratePackFromMethod(string pixelType, string converterCode)
+ {
+ #>
+
+ ///
+ internal override void PackFrom<#=pixelType#>(Span<<#=pixelType#>> source, Span destPixels, int count)
+ {
+ GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
+
+ ref <#=pixelType#> sourceRef = ref source.DangerousGetPinnableReference();
+ ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceRef, i);
+ ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
+ <#=converterCode#>
+ }
+ }
+
+ <#
+ }
+
+ void GenerateConvertToMethod(string pixelType, string converterCode)
+ {
+ #>
+
+ ///
+ internal override void To<#=pixelType#>(Span sourcePixels, Span<<#=pixelType#>> dest, int count)
+ {
+ GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
+
+ ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference();
+ ref <#=pixelType#> destRef = ref dest.DangerousGetPinnableReference();
+
+ for (int i = 0; i < count; i++)
+ {
+ ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
+ ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
+ <#=converterCode#>
+ }
+ }
+
+ <#
+ }
+
+#>
+//
+
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System;
+ using System.Numerics;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
+
+ using ImageSharp.Memory;
+ using ImageSharp.PixelFormats;
+
+ ///
+ /// Provides optimized overrides for bulk operations.
+ ///
+ public partial struct Rgba32
+ {
+ internal partial class PixelOperations : PixelOperations
+ {
+ <#
+ GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = 255;");
+ GenerateConvertToMethod("Rgb24", "dp = Unsafe.As(ref sp);");
+
+ GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = 255;");
+ GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;");
+
+ GeneratePackFromMethod("Bgra32", "dp = sp.ToRgba32();");
+ GenerateConvertToMethod("Bgra32", "dp = sp.ToBgra32();");
+ #>
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs
index 4cc9acc222..3bdfc9f1cf 100644
--- a/src/ImageSharp/PixelFormats/HalfSingle.cs
+++ b/src/ImageSharp/PixelFormats/HalfSingle.cs
@@ -76,7 +76,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
/// Expands the packed representation into a .
@@ -104,67 +104,51 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- this.PackFromVector4(new Vector4(x, y, z, w) / MaxBytes);
+ this.PackFromVector4(source.ToVector4());
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
@@ -192,5 +176,15 @@ namespace ImageSharp.PixelFormats
{
return this.PackedValue.GetHashCode();
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Vector4 ToScaledVector4()
+ {
+ Vector4 vector = this.ToVector4();
+ vector *= MaxBytes;
+ vector += Half;
+ vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
+ return vector;
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs
index f490f71690..7f1fe4ebdd 100644
--- a/src/ImageSharp/PixelFormats/HalfVector2.cs
+++ b/src/ImageSharp/PixelFormats/HalfVector2.cs
@@ -86,7 +86,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
/// Expands the packed representation into a .
@@ -118,67 +118,51 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- this.PackFromVector4(new Vector4(x, y, z, w) / MaxBytes);
+ this.PackFromVector4(source.ToVector4());
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = 0;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = 0;
+ dest.A = 255;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = 0;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = 0;
+ dest.A = 255;
}
///
@@ -220,5 +204,15 @@ namespace ImageSharp.PixelFormats
uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10);
return num2 | num;
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Vector4 ToScaledVector4()
+ {
+ Vector4 vector = this.ToVector4();
+ vector *= MaxBytes;
+ vector += Half;
+ vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
+ return vector;
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs
index 7c496c161b..062287dbe6 100644
--- a/src/ImageSharp/PixelFormats/HalfVector4.cs
+++ b/src/ImageSharp/PixelFormats/HalfVector4.cs
@@ -89,7 +89,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -111,67 +111,51 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- this.PackFromVector4(new Vector4(x, y, z, w) / MaxBytes);
+ this.PackFromVector4(source.ToVector4());
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= MaxBytes;
- vector += Half;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
@@ -214,5 +198,15 @@ namespace ImageSharp.PixelFormats
ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30;
return num4 | num3 | num2 | num1;
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Vector4 ToScaledVector4()
+ {
+ Vector4 vector = this.ToVector4();
+ vector *= MaxBytes;
+ vector += Half;
+ vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
+ return vector;
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs
index 030cb93f46..9090e1210c 100644
--- a/src/ImageSharp/PixelFormats/IPixel.cs
+++ b/src/ImageSharp/PixelFormats/IPixel.cs
@@ -20,7 +20,7 @@ namespace ImageSharp.PixelFormats
/// This method is not intended to be consumed directly. Use instead.
///
/// The instance.
- PixelOperations CreateBulkOperations();
+ PixelOperations CreatePixelOperations();
}
///
@@ -42,44 +42,33 @@ namespace ImageSharp.PixelFormats
Vector4 ToVector4();
///
- /// Sets the packed representation from the given byte array.
+ /// Packs the pixel from an value.
///
- /// The x-component.
- /// The y-component.
- /// The z-component.
- /// The w-component.
- void PackFromBytes(byte x, byte y, byte z, byte w);
+ /// The value.
+ void PackFromRgba32(Rgba32 source);
///
- /// Expands the packed representation into a given byte array.
- /// Output is expanded to X-> Y-> Z order. Equivalent to R-> G-> B in
+ /// Converts the pixel to format.
///
- /// The bytes to set the color in.
- /// The starting index of the .
- void ToXyzBytes(Span bytes, int startIndex);
+ /// The destination pixel to write to
+ void ToRgb24(ref Rgb24 dest);
///
- /// Expands the packed representation into a given byte array.
- /// Output is expanded to X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in
+ /// Converts the pixel to format.
///
- /// The bytes to set the color in.
- /// The starting index of the .
- void ToXyzwBytes(Span bytes, int startIndex);
+ /// The destination pixel to write to
+ void ToRgba32(ref Rgba32 dest);
///
- /// Expands the packed representation into a given byte array.
- /// Output is expanded to Z-> Y-> X order. Equivalent to B-> G-> R in
+ /// Converts the pixel to format.
///
- /// The bytes to set the color in.
- /// The starting index of the .
- void ToZyxBytes(Span bytes, int startIndex);
+ /// The destination pixel to write to
+ void ToBgr24(ref Bgr24 dest);
///
- /// Expands the packed representation into a given byte array.
- /// Output is expanded to Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in
+ /// Converts the pixel to format.
///
- /// The bytes to set the color in.
- /// The starting index of the .
- void ToZyxwBytes(Span bytes, int startIndex);
+ /// The destination pixel to write to
+ void ToBgra32(ref Bgra32 dest);
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs
index 47a4f30059..992986f92b 100644
--- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs
+++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs
@@ -91,7 +91,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
/// Expands the packed representation into a .
@@ -122,9 +122,9 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- Vector4 vector = new Vector4(x, y, z, w);
+ Vector4 vector = source.ToUnscaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
@@ -134,68 +134,44 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = 0;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = 0;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = 0;
- bytes[startIndex + 3] = 255;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = 0;
+ dest.A = 255;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = 0;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = 0;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = 0;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
- bytes[startIndex + 3] = 255;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = 0;
+ dest.A = 255;
}
///
@@ -238,5 +214,17 @@ namespace ImageSharp.PixelFormats
return (ushort)(byte2 | byte1);
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Vector4 ToScaledVector4()
+ {
+ Vector4 vector = this.ToVector4();
+ vector *= Half;
+ vector += Round;
+ vector += Half;
+ vector += Round;
+ vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
+ return vector;
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs
index 4559bd082f..99f603f690 100644
--- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs
+++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs
@@ -93,7 +93,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -115,9 +115,9 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- Vector4 vector = new Vector4(x, y, z, w);
+ Vector4 vector = source.ToUnscaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
@@ -127,68 +127,44 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.X;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.Z;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)vector.Z;
- bytes[startIndex + 1] = (byte)vector.Y;
- bytes[startIndex + 2] = (byte)vector.X;
- bytes[startIndex + 3] = (byte)vector.W;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)vector.X;
+ dest.G = (byte)vector.Y;
+ dest.B = (byte)vector.Z;
+ dest.A = (byte)vector.W;
}
///
@@ -235,5 +211,17 @@ namespace ImageSharp.PixelFormats
return byte4 | byte3 | byte2 | byte1;
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Vector4 ToScaledVector4()
+ {
+ Vector4 vector = this.ToVector4();
+ vector *= Half;
+ vector += Round;
+ vector += Half;
+ vector += Round;
+ vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
+ return vector;
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs
index 648b68905a..a0615563f0 100644
--- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs
+++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs
@@ -91,7 +91,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -109,9 +109,9 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- Vector4 vector = new Vector4(x, y, z, w);
+ Vector4 vector = source.ToUnscaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
@@ -121,68 +121,44 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)MathF.Round(vector.X);
- bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
- bytes[startIndex + 2] = 0;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = 0;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)MathF.Round(vector.X);
- bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
- bytes[startIndex + 2] = 0;
- bytes[startIndex + 3] = 255;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = 0;
+ dest.A = 255;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = 0;
- bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
- bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = 0;
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = 0;
- bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
- bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
- bytes[startIndex + 3] = 255;
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = 0;
+ dest.A = 255;
}
///
@@ -245,5 +221,17 @@ namespace ImageSharp.PixelFormats
return word2 | word1;
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Vector4 ToScaledVector4()
+ {
+ Vector4 vector = this.ToVector4();
+ vector *= Half;
+ vector += Round;
+ vector += Half;
+ vector += Round;
+ vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
+ return vector;
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs
index 7b520aacef..f35fb63684 100644
--- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs
+++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs
@@ -93,7 +93,7 @@ namespace ImageSharp.PixelFormats
}
///
- public PixelOperations CreateBulkOperations() => new PixelOperations();
+ public PixelOperations CreatePixelOperations() => new PixelOperations();
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -117,9 +117,9 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void PackFromBytes(byte x, byte y, byte z, byte w)
+ public void PackFromRgba32(Rgba32 source)
{
- Vector4 vector = new Vector4(x, y, z, w);
+ Vector4 vector = source.ToUnscaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
@@ -129,68 +129,44 @@ namespace ImageSharp.PixelFormats
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzBytes(Span bytes, int startIndex)
+ public void ToRgb24(ref Rgb24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)MathF.Round(vector.X);
- bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
- bytes[startIndex + 2] = (byte)MathF.Round(vector.Z);
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = (byte)MathF.Round(vector.Z);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToXyzwBytes(Span bytes, int startIndex)
+ public void ToRgba32(ref Rgba32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- 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);
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = (byte)MathF.Round(vector.Z);
+ dest.A = (byte)MathF.Round(vector.W);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxBytes(Span bytes, int startIndex)
+ public void ToBgr24(ref Bgr24 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- bytes[startIndex] = (byte)MathF.Round(vector.Z);
- bytes[startIndex + 1] = (byte)MathF.Round(vector.Y);
- bytes[startIndex + 2] = (byte)MathF.Round(vector.X);
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = (byte)MathF.Round(vector.Z);
}
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ToZyxwBytes(Span bytes, int startIndex)
+ public void ToBgra32(ref Bgra32 dest)
{
- Vector4 vector = this.ToVector4();
- vector *= Half;
- vector += Round;
- vector += Half;
- vector += Round;
- vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
-
- 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);
+ Vector4 vector = this.ToScaledVector4();
+ dest.R = (byte)MathF.Round(vector.X);
+ dest.G = (byte)MathF.Round(vector.Y);
+ dest.B = (byte)MathF.Round(vector.Z);
+ dest.A = (byte)MathF.Round(vector.W);
}
///
@@ -241,5 +217,17 @@ namespace ImageSharp.PixelFormats
return word4 | word3 | word2 | word1;
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Vector4 ToScaledVector4()
+ {
+ Vector4 vector = this.ToVector4();
+ vector *= Half;
+ vector += Round;
+ vector += Half;
+ vector += Round;
+ vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
+ return vector;
+ }
}
}
diff --git a/src/ImageSharp/PixelFormats/PixelConversionExtensions.cs b/src/ImageSharp/PixelFormats/PixelConversionExtensions.cs
new file mode 100644
index 0000000000..1ea2628951
--- /dev/null
+++ b/src/ImageSharp/PixelFormats/PixelConversionExtensions.cs
@@ -0,0 +1,76 @@
+namespace ImageSharp.PixelFormats
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// Extension methods for copying single pixel data into byte Spans.
+ /// TODO: This utility class exists for legacy reasons. Need to do a lot of chore work to remove it (mostly in test classes).
+ ///
+ internal static class PixelConversionExtensions
+ {
+ ///
+ /// Expands the packed representation into a given byte array.
+ /// Output is expanded to X-> Y-> Z order. Equivalent to R-> G-> B in
+ ///
+ /// The pixel type.
+ /// The pixel to copy the data from.
+ /// The bytes to set the color in.
+ /// The starting index of the .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ToXyzBytes(this TPixel pixel, Span bytes, int startIndex)
+ where TPixel : struct, IPixel
+ {
+ ref Rgb24 dest = ref bytes.GetRgb24(startIndex);
+ pixel.ToRgb24(ref dest);
+ }
+
+ ///
+ /// Expands the packed representation into a given byte array.
+ /// Output is expanded to X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in
+ ///
+ /// The pixel type.
+ /// The pixel to copy the data from.
+ /// The bytes to set the color in.
+ /// The starting index of the .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ToXyzwBytes(this TPixel pixel, Span bytes, int startIndex)
+ where TPixel : struct, IPixel
+ {
+ ref Rgba32 dest = ref Unsafe.As(ref bytes[startIndex]);
+ pixel.ToRgba32(ref dest);
+ }
+
+ ///
+ /// Expands the packed representation into a given byte array.
+ /// Output is expanded to Z-> Y-> X order. Equivalent to B-> G-> R in
+ ///
+ /// The pixel type.
+ /// The pixel to copy the data from.
+ /// The bytes to set the color in.
+ /// The starting index of the .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ToZyxBytes(this TPixel pixel, Span bytes, int startIndex)
+ where TPixel : struct, IPixel
+ {
+ ref Bgr24 dest = ref Unsafe.As(ref bytes[startIndex]);
+ pixel.ToBgr24(ref dest);
+ }
+
+ ///
+ /// Expands the packed representation into a given byte array.
+ /// Output is expanded to Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in
+ ///
+ /// The pixel type.
+ /// The pixel to copy the data from.
+ /// The bytes to set the color in.
+ /// The starting index of the .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ToZyxwBytes(this TPixel pixel, Span bytes, int startIndex)
+ where TPixel : struct, IPixel
+ {
+ ref Bgra32 dest = ref Unsafe.As(ref bytes[startIndex]);
+ pixel.ToBgra32(ref dest);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
index 993a11232a..a62d14527a 100644
--- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
+++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
@@ -20,7 +20,7 @@ namespace ImageSharp.PixelFormats
///
/// Gets the global instance for the pixel type
///
- public static PixelOperations Instance { get; } = default(TPixel).CreateBulkOperations();
+ public static PixelOperations Instance { get; } = default(TPixel).CreatePixelOperations();
///
/// Bulk version of
@@ -30,8 +30,7 @@ namespace ImageSharp.PixelFormats
/// The number of pixels to convert.
internal virtual void PackFromVector4(Span sourceVectors, Span destColors, int count)
{
- Guard.MustBeSizedAtLeast(sourceVectors, count, nameof(sourceVectors));
- Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors));
+ GuardSpans(sourceVectors, nameof(sourceVectors), destColors, nameof(destColors), count);
ref Vector4 sourceRef = ref sourceVectors.DangerousGetPinnableReference();
ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
@@ -52,8 +51,7 @@ namespace ImageSharp.PixelFormats
/// The number of pixels to convert.
internal virtual void ToVector4(Span sourceColors, Span destVectors, int count)
{
- Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors));
- Guard.MustBeSizedAtLeast(destVectors, count, nameof(destVectors));
+ GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count);
ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref Vector4 destRef = ref destVectors.DangerousGetPinnableReference();
@@ -67,187 +65,25 @@ namespace ImageSharp.PixelFormats
}
///
- /// Bulk version of that converts data in .
+ /// Verifies that the given 'source' and 'dest' spans are at least of 'minLength' size.
+ /// Throwing an if the condition is not met.
///
- /// The to the source bytes.
- /// The to the destination colors.
- /// The number of pixels to convert.
- internal virtual void PackFromXyzBytes(Span sourceBytes, Span destColors, int count)
- {
- Guard.MustBeSizedAtLeast(sourceBytes, count * 3, nameof(sourceBytes));
- Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors));
-
- ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
- ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
-
- for (int i = 0; i < count; i++)
- {
- int i3 = i * 3;
- ref TPixel dp = ref Unsafe.Add(ref destRef, i);
- dp.PackFromBytes(
- Unsafe.Add(ref sourceRef, i3),
- Unsafe.Add(ref sourceRef, i3 + 1),
- Unsafe.Add(ref sourceRef, i3 + 2),
- 255);
- }
- }
-
- ///
- /// Bulk version of .
- ///
- /// The to the source colors.
- /// The to the destination bytes.
- /// The number of pixels to convert.
- internal virtual void ToXyzBytes(Span sourceColors, Span destBytes, int count)
- {
- Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors));
- Guard.MustBeSizedAtLeast(destBytes, count * 3, nameof(destBytes));
-
- ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference();
-
- for (int i = 0; i < count; i++)
- {
- ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
- sp.ToXyzBytes(destBytes, i * 3);
- }
- }
-
- ///
- /// Bulk version of that converts data in .
- ///
- /// The to the source bytes.
- /// The to the destination colors.
- /// The number of pixels to convert.
- internal virtual void PackFromXyzwBytes(Span sourceBytes, Span destColors, int count)
+ /// The source element type
+ /// The destination element type
+ /// The source span
+ /// The source parameter name
+ /// The destination span
+ /// The destination parameter name
+ /// The minimum length
+ protected internal static void GuardSpans(
+ Span source,
+ string sourceParamName,
+ Span dest,
+ string destParamName,
+ int minLength)
{
- Guard.MustBeSizedAtLeast(sourceBytes, count * 4, nameof(sourceBytes));
- Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors));
-
- ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
- ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
-
- for (int i = 0; i < count; i++)
- {
- int i4 = i * 4;
- ref TPixel dp = ref Unsafe.Add(ref destRef, i);
- dp.PackFromBytes(
- Unsafe.Add(ref sourceRef, i4),
- Unsafe.Add(ref sourceRef, i4 + 1),
- Unsafe.Add(ref sourceRef, i4 + 2),
- Unsafe.Add(ref sourceRef, i4 + 3));
- }
- }
-
- ///
- /// Bulk version of
- ///
- /// The to the source colors.
- /// The to the destination bytes.
- /// The number of pixels to convert.
- internal virtual void ToXyzwBytes(Span sourceColors, Span destBytes, int count)
- {
- Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors));
- Guard.MustBeSizedAtLeast(destBytes, count * 4, nameof(destBytes));
-
- ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference();
-
- for (int i = 0; i < count; i++)
- {
- ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
- sp.ToXyzwBytes(destBytes, i * 4);
- }
- }
-
- ///
- /// Bulk version of that converts data in .
- ///
- /// The to the source bytes.
- /// The to the destination colors.
- /// The number of pixels to convert.
- internal virtual void PackFromZyxBytes(Span sourceBytes, Span destColors, int count)
- {
- Guard.MustBeSizedAtLeast(sourceBytes, count * 3, nameof(sourceBytes));
- Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors));
-
- ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
- ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
-
- for (int i = 0; i < count; i++)
- {
- int i3 = i * 3;
- ref TPixel dp = ref Unsafe.Add(ref destRef, i);
- dp.PackFromBytes(
- Unsafe.Add(ref sourceRef, i3 + 2),
- Unsafe.Add(ref sourceRef, i3 + 1),
- Unsafe.Add(ref sourceRef, i3),
- 255);
- }
- }
-
- ///
- /// Bulk version of .
- ///
- /// The to the source colors.
- /// The to the destination bytes.
- /// The number of pixels to convert.
- internal virtual void ToZyxBytes(Span sourceColors, Span destBytes, int count)
- {
- Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors));
- Guard.MustBeSizedAtLeast(destBytes, count * 3, nameof(destBytes));
-
- ref TPixel sourceRef = ref sourceColors.DangerousGetPinnableReference();
-
- for (int i = 0; i < count; i++)
- {
- ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
- sp.ToZyxBytes(destBytes, i * 3);
- }
- }
-
- ///
- /// Bulk version of that converts data in .
- ///
- /// The to the source bytes.
- /// The to the destination colors.
- /// The number of pixels to convert.
- internal virtual void PackFromZyxwBytes(Span sourceBytes, Span destColors, int count)
- {
- Guard.MustBeSizedAtLeast(sourceBytes, count * 4, nameof(sourceBytes));
- Guard.MustBeSizedAtLeast(destColors, count, nameof(destColors));
-
- ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
- ref TPixel destRef = ref destColors.DangerousGetPinnableReference();
-
- for (int i = 0; i < count; i++)
- {
- int i4 = i * 4;
- ref TPixel dp = ref Unsafe.Add(ref destRef, i);
- dp.PackFromBytes(
- Unsafe.Add(ref sourceRef, i4 + 2),
- Unsafe.Add(ref sourceRef, i4 + 1),
- Unsafe.Add(ref sourceRef, i4),
- Unsafe.Add(ref sourceRef, i4 + 3));
- }
- }
-
- ///
- /// Bulk version of