Browse Source

remove usage of Span<T> from public api surface

af/merge-core
Scott Williams 9 years ago
parent
commit
70e734a2d4
  1. 4
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  2. 8
      src/ImageSharp.Drawing/Paths/ShapeRegion.cs
  3. 5
      src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
  4. 5
      src/ImageSharp.Drawing/Region.cs
  5. 2
      src/ImageSharp/Advanced/ImageExtensions.cs
  6. 66
      src/ImageSharp/Image/Image.LoadPixelData.cs
  7. 2
      src/ImageSharp/Image/ImageExtensions.cs
  8. 4
      tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs
  9. 12
      tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs

4
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -37,8 +37,8 @@
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" /> <ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="SixLabors.Shapes.Text" Version="0.1.0-alpha0019" /> <PackageReference Include="SixLabors.Shapes.Text" Version="0.1.0-alpha0020" />
<PackageReference Include="SixLabors.Shapes" Version="0.1.0-alpha0019" /> <PackageReference Include="SixLabors.Shapes" Version="0.1.0-alpha0020" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004"> <PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
<PrivateAssets>All</PrivateAssets> <PrivateAssets>All</PrivateAssets>
</PackageReference> </PackageReference>

8
src/ImageSharp.Drawing/Paths/ShapeRegion.cs

@ -42,18 +42,18 @@ namespace SixLabors.ImageSharp.Drawing
public override Rectangle Bounds { get; } public override Rectangle Bounds { get; }
/// <inheritdoc/> /// <inheritdoc/>
public override int Scan(float y, Span<float> buffer) public override int Scan(float y, float[] buffer, int offset)
{ {
var start = new PointF(this.Bounds.Left - 1, y); var start = new PointF(this.Bounds.Left - 1, y);
var end = new PointF(this.Bounds.Right + 1, y); var end = new PointF(this.Bounds.Right + 1, y);
using (var innerBuffer = new Buffer<PointF>(buffer.Length)) using (var innerBuffer = new Buffer<PointF>(buffer.Length))
{ {
var span = innerBuffer.Span; PointF[] array = innerBuffer.Array;
int count = this.Shape.FindIntersections(start, end, span); int count = this.Shape.FindIntersections(start, end, array, offset);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
buffer[i] = span[i].X; buffer[i] = array[i].X;
} }
return count; return count;

5
src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs

@ -93,7 +93,6 @@ namespace SixLabors.ImageSharp.Drawing.Processors
using (BrushApplicator<TPixel> applicator = this.Brush.CreateApplicator(source, rect, this.Options)) using (BrushApplicator<TPixel> applicator = this.Brush.CreateApplicator(source, rect, this.Options))
{ {
float[] buffer = arrayPool.Rent(maxIntersections); float[] buffer = arrayPool.Rent(maxIntersections);
Span<float> bufferSpan = buffer.AsSpan().Slice(0, maxIntersections);
int scanlineWidth = maxX - minX; int scanlineWidth = maxX - minX;
using (var scanline = new Buffer<float>(scanlineWidth)) using (var scanline = new Buffer<float>(scanlineWidth))
{ {
@ -117,14 +116,14 @@ namespace SixLabors.ImageSharp.Drawing.Processors
float subpixelFractionPoint = subpixelFraction / subpixelCount; float subpixelFractionPoint = subpixelFraction / subpixelCount;
for (float subPixel = (float)y; subPixel < y + 1; subPixel += subpixelFraction) for (float subPixel = (float)y; subPixel < y + 1; subPixel += subpixelFraction)
{ {
int pointsFound = region.Scan(subPixel, bufferSpan); int pointsFound = region.Scan(subPixel, buffer, 0);
if (pointsFound == 0) if (pointsFound == 0)
{ {
// nothing on this line skip // nothing on this line skip
continue; continue;
} }
QuickSort(bufferSpan.Slice(0, pointsFound)); QuickSort(buffer.AsSpan().Slice(0, pointsFound));
for (int point = 0; point < pointsFound; point += 2) for (int point = 0; point < pointsFound; point += 2)
{ {

5
src/ImageSharp.Drawing/Region.cs

@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Drawing
/// Gets the bounding box that entirely surrounds this region. /// Gets the bounding box that entirely surrounds this region.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This should always contains all possible points returned from <see cref="Scan(float, Span{float})"/>. /// This should always contains all possible points returned from <see cref="Scan(float, float[], int)"/>.
/// </remarks> /// </remarks>
public abstract Rectangle Bounds { get; } public abstract Rectangle Bounds { get; }
@ -29,7 +29,8 @@ namespace SixLabors.ImageSharp.Drawing
/// </summary> /// </summary>
/// <param name="y">The position along the y axis to find intersections.</param> /// <param name="y">The position along the y axis to find intersections.</param>
/// <param name="buffer">The buffer.</param> /// <param name="buffer">The buffer.</param>
/// <param name="offset">The point in the buffer to start setting offset.</param>
/// <returns>The number of intersections found.</returns> /// <returns>The number of intersections found.</returns>
public abstract int Scan(float y, Span<float> buffer); public abstract int Scan(float y, float[] buffer, int offset);
} }
} }

2
src/ImageSharp/Advanced/ImageExtensions.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Advanced
/// <summary> /// <summary>
/// Extension methods over Image{TPixel} /// Extension methods over Image{TPixel}
/// </summary> /// </summary>
public static partial class ImageExtensions internal static partial class ImageExtensions
{ {
/// <summary> /// <summary>
/// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. /// Gets the representation of the pixels as an area of contiguous memory in the given pixel format.

66
src/ImageSharp/Image/Image.LoadPixelData.cs

@ -25,7 +25,19 @@ namespace SixLabors.ImageSharp
/// <param name="height">The height of the final image.</param> /// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> LoadPixelData<TPixel>(Span<TPixel> data, int width, int height) public static Image<TPixel> LoadPixelData<TPixel>(TPixel[] data, int width, int height)
where TPixel : struct, IPixel<TPixel>
=> LoadPixelData(Configuration.Default, data, width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the raw <typeparamref name="TPixel"/> data.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
private static Image<TPixel> LoadPixelData<TPixel>(Span<TPixel> data, int width, int height)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> LoadPixelData(Configuration.Default, data, width, height); => LoadPixelData(Configuration.Default, data, width, height);
@ -37,7 +49,19 @@ namespace SixLabors.ImageSharp
/// <param name="height">The height of the final image.</param> /// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> LoadPixelData<TPixel>(Span<byte> data, int width, int height) public static Image<TPixel> LoadPixelData<TPixel>(byte[] data, int width, int height)
where TPixel : struct, IPixel<TPixel>
=> LoadPixelData<TPixel>(Configuration.Default, data, width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array in <typeparamref name="TPixel"/> format.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
private static Image<TPixel> LoadPixelData<TPixel>(Span<byte> data, int width, int height)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> LoadPixelData<TPixel>(Configuration.Default, data, width, height); => LoadPixelData<TPixel>(Configuration.Default, data, width, height);
@ -50,7 +74,20 @@ namespace SixLabors.ImageSharp
/// <param name="height">The height of the final image.</param> /// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> LoadPixelData<TPixel>(Configuration config, Span<byte> data, int width, int height) public static Image<TPixel> LoadPixelData<TPixel>(Configuration config, byte[] data, int width, int height)
where TPixel : struct, IPixel<TPixel>
=> LoadPixelData(config, new Span<byte>(data).NonPortableCast<byte, TPixel>(), width, height);
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array in <typeparamref name="TPixel"/> format.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
private static Image<TPixel> LoadPixelData<TPixel>(Configuration config, Span<byte> data, int width, int height)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> LoadPixelData(config, data.NonPortableCast<byte, TPixel>(), width, height); => LoadPixelData(config, data.NonPortableCast<byte, TPixel>(), width, height);
@ -63,7 +100,28 @@ namespace SixLabors.ImageSharp
/// <param name="height">The height of the final image.</param> /// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> LoadPixelData<TPixel>(Configuration config, Span<TPixel> data, int width, int height) public static Image<TPixel> LoadPixelData<TPixel>(Configuration config, TPixel[] data, int width, int height)
where TPixel : struct, IPixel<TPixel>
{
int count = width * height;
Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data));
var image = new Image<TPixel>(config, width, height);
SpanHelper.Copy(data, image.GetPixelSpan(), count);
return image;
}
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the raw <typeparamref name="TPixel"/> data.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The Span containing the image Pixel data.</param>
/// <param name="width">The width of the final image.</param>
/// <param name="height">The height of the final image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
private static Image<TPixel> LoadPixelData<TPixel>(Configuration config, Span<TPixel> data, int width, int height)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int count = width * height; int count = width * height;

2
src/ImageSharp/Image/ImageExtensions.cs

@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp
/// <param name="source">The source image</param> /// <param name="source">The source image</param>
/// <param name="buffer">The buffer to save the raw pixel data to.</param> /// <param name="buffer">The buffer to save the raw pixel data to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception> /// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SavePixelData<TPixel>(this Image<TPixel> source, Span<byte> buffer) internal static void SavePixelData<TPixel>(this Image<TPixel> source, byte[] buffer)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<byte> byteBuffer = source.GetPixelSpan().AsBytes(); Span<byte> byteBuffer = source.GetPixelSpan().AsBytes();

4
tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs

@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing
Image<Rgba32> img = new Image<Rgba32>(1, 1); Image<Rgba32> img = new Image<Rgba32>(1, 1);
processor.Apply(img, bounds); processor.Apply(img, bounds);
region.Verify(x => x.Scan(It.IsAny<float>(), It.IsAny<Span<float>>()), Times.Exactly(4)); region.Verify(x => x.Scan(It.IsAny<float>(), It.IsAny<float[]>(), It.IsAny<int>()), Times.Exactly(4));
} }
[Fact] [Fact]
@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing
region.Setup(x => x.Bounds).Returns(bounds); region.Setup(x => x.Bounds).Returns(bounds);
region.Setup(x => x.MaxIntersections).Returns(10); region.Setup(x => x.MaxIntersections).Returns(10);
region.Setup(x => x.Scan(It.IsAny<float>(), It.IsAny<Span<float>>())) region.Setup(x => x.Scan(It.IsAny<float>(), It.IsAny<float[]>(), It.IsAny<int>()))
.Returns<float, Span<float>>((y, span) => .Returns<float, Span<float>>((y, span) =>
{ {
if (y < 5) if (y < 5)

12
tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs

@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
int yToScan = 10; int yToScan = 10;
ShapeRegion region = new ShapeRegion(pathMock.Object); ShapeRegion region = new ShapeRegion(pathMock.Object);
pathMock.Setup(x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<Span<PointF>>())) pathMock.Setup(x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<PointF[]>(), It.IsAny<int>()))
.Callback<PointF, PointF, Span<PointF>>((s, e, b) => { .Callback<PointF, PointF, Span<PointF>>((s, e, b) => {
Assert.Equal(yToScan, s.Y); Assert.Equal(yToScan, s.Y);
Assert.Equal(yToScan, e.Y); Assert.Equal(yToScan, e.Y);
@ -84,9 +84,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
Assert.True(e.X > bounds.Right); Assert.True(e.X > bounds.Right);
}).Returns(0); }).Returns(0);
int i = region.Scan(yToScan, new float[0]); int i = region.Scan(yToScan, new float[0], 0);
pathMock.Verify(x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<Span<PointF>>()), Times.Once); pathMock.Verify(x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<PointF[]>(), It.IsAny<int>()), Times.Once);
} }
[Fact] [Fact]
@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
int yToScan = 10; int yToScan = 10;
ShapeRegion region = new ShapeRegion(pathMock.Object); ShapeRegion region = new ShapeRegion(pathMock.Object);
pathMock.Setup(x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<Span<PointF>>())) pathMock.Setup(x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<PointF[]>(), It.IsAny<int>()))
.Callback<PointF, PointF, Span<PointF>>((s, e, b) => { .Callback<PointF, PointF, Span<PointF>>((s, e, b) => {
Assert.Equal(yToScan, s.Y); Assert.Equal(yToScan, s.Y);
Assert.Equal(yToScan, e.Y); Assert.Equal(yToScan, e.Y);
@ -103,9 +103,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
Assert.True(e.X > bounds.Right); Assert.True(e.X > bounds.Right);
}).Returns(0); }).Returns(0);
int i = region.Scan(yToScan, new float[0]); int i = region.Scan(yToScan, new float[0], 0);
pathMock.Verify(x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<Span<PointF>>()), Times.Once); pathMock.Verify(x => x.FindIntersections(It.IsAny<PointF>(), It.IsAny<PointF>(), It.IsAny<PointF[]>(), It.IsAny<int>()), Times.Once);
} }
[Fact] [Fact]

Loading…
Cancel
Save