Browse Source

FillPolygonTests

af/merge-core
Anton Firszov 7 years ago
parent
commit
ba92b1c755
  1. 14
      src/ImageSharp/Color/Color.Conversions.cs
  2. 12
      src/ImageSharp/Color/Color.cs
  3. 11
      tests/ImageSharp.Tests/Color/ColorTests.cs
  4. 155
      tests/ImageSharp.Tests/Drawing/FillPolygonTests.cs
  5. 3
      tests/ImageSharp.Tests/Drawing/RecolorImageTests.cs
  6. 240
      tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs
  7. 2
      tests/Images/External

14
src/ImageSharp/Color/Color.Conversions.cs

@ -117,6 +117,13 @@ namespace SixLabors.ImageSharp
/// <returns>The <see cref="Color"/>.</returns>
public static implicit operator Color(Bgr24 source) => new Color(source);
/// <summary>
/// Converts an <see cref="Vector4"/> to <see cref="Color"/>.
/// </summary>
/// <param name="source">The <see cref="Vector4"/>.</param>
/// <returns>The <see cref="Color"/>.</returns>
public static explicit operator Color(Vector4 source) => new Color(source);
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Rgba64"/>.
/// </summary>
@ -158,5 +165,12 @@ namespace SixLabors.ImageSharp
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Bgr24"/>.</returns>
public static implicit operator Bgr24(Color color) => color.data.ToBgr24();
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Vector4"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static explicit operator Vector4(Color color) => color.data.ToVector4();
}
}

12
src/ImageSharp/Color/Color.cs

@ -94,6 +94,18 @@ namespace SixLabors.ImageSharp
return new Color(rgba);
}
/// <summary>
/// Alters the alpha channel of the color, returning a new instance.
/// </summary>
/// <param name="alpha">The new value of alpha [0..1].</param>
/// <returns>The color having it's alpha channel altered.</returns>
public Color WithAlpha(float alpha)
{
Vector4 v = (Vector4)this;
v.W = alpha;
return new Color(v);
}
/// <summary>
/// Gets the hexadecimal representation of the color instance in rrggbbaa form.
/// </summary>

11
tests/ImageSharp.Tests/Color/ColorTests.cs

@ -13,6 +13,17 @@ namespace SixLabors.ImageSharp.Tests
{
public partial class ColorTests
{
[Fact]
public void WithAlpha()
{
Color c1 = Color.FromRgba(111, 222, 55, 255);
Color c2 = c1.WithAlpha(0.5f);
Rgba32 expected = new Rgba32(111, 222, 55, 128);
Assert.Equal(expected, (Rgba32)c2);
}
[Fact]
public void Equality_WhenTrue()
{

155
tests/ImageSharp.Tests/Drawing/FillPolygonTests.cs

@ -0,0 +1,155 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.Shapes;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Drawing
{
[GroupOutput("Drawing")]
public class FillPolygonTests
{
[Theory]
[WithBasicTestPatternImages(250, 350, PixelTypes.Rgba32, "White", 1f, true)]
[WithBasicTestPatternImages(250, 350, PixelTypes.Rgba32, "White", 0.6f, true)]
[WithBasicTestPatternImages(250, 350, PixelTypes.Rgba32, "White", 1f, false)]
[WithBasicTestPatternImages(250, 350, PixelTypes.Bgr24, "Yellow", 1f, true)]
public void FillPolygon_Solid<TPixel>(TestImageProvider<TPixel> provider, string colorName, float alpha, bool antialias)
where TPixel : struct, IPixel<TPixel>
{
SixLabors.Primitives.PointF[] simplePath =
{
new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300)
};
Color color = TestUtils.GetColorByName(colorName).WithAlpha(alpha);
GraphicsOptions options = new GraphicsOptions(antialias);
string aa = antialias ? "" : "_NoAntialias";
FormattableString outputDetails = $"{colorName}_A{alpha}{aa}";
provider.RunValidatingProcessorTest(
c => c.FillPolygon(options, color.ToPixel<TPixel>(), simplePath),
outputDetails,
appendSourceFileOrDescription: false);
}
[Theory]
[WithBasicTestPatternImages(200, 200, PixelTypes.Rgba32)]
public void FillPolygon_Concave<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
var points = new SixLabors.Primitives.PointF[]
{
new Vector2(8, 8),
new Vector2(64, 8),
new Vector2(64, 64),
new Vector2(120, 64),
new Vector2(120, 120),
new Vector2(8, 120)
};
Color color = Color.LightGreen;
provider.RunValidatingProcessorTest(
c => c.FillPolygon(color.ToPixel<TPixel>(), points),
appendSourceFileOrDescription: false,
appendPixelTypeToFileName: false);
}
[Theory]
[WithBasicTestPatternImages(250, 350, PixelTypes.Rgba32)]
public void FillPolygon_Pattern<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
SixLabors.Primitives.PointF[] simplePath =
{
new Vector2(10, 10), new Vector2(200, 150), new Vector2(50, 300)
};
Color color = Color.Yellow;
var brush = Brushes.Horizontal(color.ToPixel<TPixel>());
provider.RunValidatingProcessorTest(
c => c.FillPolygon(brush, simplePath),
appendSourceFileOrDescription: false);
}
[Theory]
[WithBasicTestPatternImages(250, 350, PixelTypes.Rgba32, TestImages.Png.Ducky)]
[WithBasicTestPatternImages(250, 350, PixelTypes.Rgba32, TestImages.Bmp.Car)]
public void FillPolygon_ImageBrush<TPixel>(TestImageProvider<TPixel> provider, string brushImageName)
where TPixel : struct, IPixel<TPixel>
{
SixLabors.Primitives.PointF[] simplePath =
{
new Vector2(10, 10), new Vector2(200, 50), new Vector2(50, 200)
};
using (Image<TPixel> brushImage = Image.Load<TPixel>(TestFile.Create(brushImageName).Bytes))
{
var brush = new ImageBrush<TPixel>(brushImage);
provider.RunValidatingProcessorTest(
c => c.FillPolygon(brush, simplePath),
System.IO.Path.GetFileNameWithoutExtension(brushImageName),
appendSourceFileOrDescription: false);
}
}
[Theory]
[WithBasicTestPatternImages(250, 250, PixelTypes.Rgba32)]
public void Fill_RectangularPolygon<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
var polygon = new SixLabors.Shapes.RectangularPolygon(10, 10, 190, 140);
Color color = Color.White;
provider.RunValidatingProcessorTest(
c => c.Fill(color.ToPixel<TPixel>(), polygon),
appendSourceFileOrDescription: false);
}
[Theory]
[WithBasicTestPatternImages(200, 200, PixelTypes.Rgba32, 3, 50, 0f)]
[WithBasicTestPatternImages(200, 200, PixelTypes.Rgba32, 3, 60, 20f)]
[WithBasicTestPatternImages(200, 200, PixelTypes.Rgba32, 3, 60, -180f)]
[WithBasicTestPatternImages(200, 200, PixelTypes.Rgba32, 5, 70, 0f)]
[WithBasicTestPatternImages(200, 200, PixelTypes.Rgba32, 7, 80, -180f)]
public void Fill_RegularPolygon<TPixel>(TestImageProvider<TPixel> provider, int vertices, float radius, float angleDeg)
where TPixel : struct, IPixel<TPixel>
{
float angle = GeometryUtilities.DegreeToRadian(angleDeg);
var polygon = new RegularPolygon(100, 100, vertices, radius, angle);
Color color = Color.Yellow;
FormattableString testOutput = $"V({vertices})_R({radius})_Ang({angleDeg})";
provider.RunValidatingProcessorTest(
c => c.Fill(color.ToPixel<TPixel>(), polygon),
testOutput,
appendSourceFileOrDescription: false,
appendPixelTypeToFileName: false);
}
[Theory]
[WithBasicTestPatternImages(200, 200, PixelTypes.Rgba32)]
public void Fill_EllipsePolygon<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
var polygon = new EllipsePolygon(100, 100, 80, 120);
Color color = Color.Azure;
provider.RunValidatingProcessorTest(
c => c.Fill(color.ToPixel<TPixel>(), polygon),
appendSourceFileOrDescription: false,
appendPixelTypeToFileName: false);
}
}
}

3
tests/ImageSharp.Tests/Drawing/RecolorImageTests.cs

@ -6,9 +6,10 @@ using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.Primitives;
using Xunit;
namespace SixLabors.ImageSharp.Tests
namespace SixLabors.ImageSharp.Tests.Drawing
{
[GroupOutput("Drawing")]
public class RecolorImageTests

240
tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs

@ -1,240 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.Shapes;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Drawing
{
public class SolidPolygonTests : FileTestBase
{
[Fact]
public void ImageShouldBeOverlayedByFilledPolygon()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
SixLabors.Primitives.PointF[] simplePath = {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.FillPolygon(new GraphicsOptions(true), Rgba32.HotPink, simplePath));
image.Save($"{path}/Simple.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
Assert.Equal(Rgba32.HotPink, sourcePixels[81, 145]);
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledPolygonWithPattern()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
var simplePath = new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(
x => x.FillPolygon(new GraphicsOptions(true), Brushes.Horizontal(Rgba32.HotPink), simplePath));
image.Save($"{path}/Pattern.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
Assert.Equal(Rgba32.HotPink, sourcePixels[81, 145]);
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledPolygonNoAntialias()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
var simplePath = new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.FillPolygon(
new GraphicsOptions(false),
Rgba32.HotPink,
simplePath));
image.Save($"{path}/Simple_NoAntialias.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
Assert.True(Rgba32.HotPink == sourcePixels[11, 11], "[11, 11] wrong");
Assert.True(Rgba32.HotPink == sourcePixels[199, 149], "[199, 149] wrong");
Assert.True(Rgba32.HotPink == sourcePixels[50, 50], "[50, 50] wrong");
Assert.True(Rgba32.Blue == sourcePixels[2, 2], "[2, 2] wrong");
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledPolygonImage()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
var simplePath = new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
using (Image<Rgba32> brushImage = TestFile.Create(TestImages.Bmp.Car).CreateRgba32Image())
using (var image = new Image<Rgba32>(500, 500))
{
var brush = new ImageBrush<Rgba32>(brushImage);
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.FillPolygon(brush, simplePath));
image.Save($"{path}/Image.png");
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledPolygonOpacity()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
var simplePath = new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(200, 150),
new Vector2(50, 300)
};
var color = new Rgba32(Rgba32.HotPink.R, Rgba32.HotPink.G, Rgba32.HotPink.B, 150);
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.FillPolygon(color, simplePath));
image.Save($"{path}/Opacity.png");
//shift background color towards forground color by the opacity amount
var mergedColor = new Rgba32(
Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f));
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
Assert.Equal(Rgba32.Blue, sourcePixels[2, 2]);
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledRectangle()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
using (var image = new Image<Rgba32>(500, 500))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.Fill(
Rgba32.HotPink,
new SixLabors.Shapes.RectangularPolygon(10, 10, 190, 140)));
image.Save($"{path}/Rectangle.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
Assert.Equal(Rgba32.HotPink, sourcePixels[11, 11]);
Assert.Equal(Rgba32.HotPink, sourcePixels[198, 10]);
Assert.Equal(Rgba32.HotPink, sourcePixels[10, 50]);
Assert.Equal(Rgba32.HotPink, sourcePixels[50, 50]);
Assert.Equal(Rgba32.Blue, sourcePixels[2, 2]);
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledTriangle()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
using (var image = new Image<Rgba32>(100, 100))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(
x => x.Fill(Rgba32.HotPink, new RegularPolygon(50, 50, 3, 30)));
image.Save($"{path}/Triangle.png");
Buffer2D<Rgba32> sourcePixels = image.GetRootFramePixelBuffer();
Assert.Equal(Rgba32.Blue, sourcePixels[30, 65]);
Assert.Equal(Rgba32.HotPink, sourcePixels[50, 50]);
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledSeptagon()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
var config = Configuration.CreateDefaultInstance();
config.MaxDegreeOfParallelism = 1;
using (var image = new Image<Rgba32>(config, 100, 100))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x.Fill(Rgba32.HotPink,
new RegularPolygon(50, 50, 7, 30, -(float)Math.PI)));
image.Save($"{path}/Septagon.png");
}
}
[Fact]
public void ImageShouldBeOverlayedByFilledEllipse()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
var config = Configuration.CreateDefaultInstance();
config.MaxDegreeOfParallelism = 1;
using (var image = new Image<Rgba32>(config, 100, 100))
{
image.Mutate(x => x.BackgroundColor(Rgba32.Blue));
image.Mutate(x => x
.Fill(Rgba32.HotPink, new EllipsePolygon(50, 50, 30, 50)
.Rotate((float)(Math.PI / 3))));
image.Save($"{path}/ellipse.png");
}
}
[Fact]
public void ImageShouldBeOverlayedBySquareWithCornerClipped()
{
string path = TestEnvironment.CreateOutputDirectory("Drawing", "FilledPolygons");
var config = Configuration.CreateDefaultInstance();
config.MaxDegreeOfParallelism = 1;
using (var image = new Image<Rgba32>(config, 200, 200))
{
image.Mutate(x => x
.Fill(Rgba32.Blue)
.FillPolygon(Rgba32.HotPink, new SixLabors.Primitives.PointF[]
{
new Vector2( 8, 8 ),
new Vector2( 64, 8 ),
new Vector2( 64, 64 ),
new Vector2( 120, 64 ),
new Vector2( 120, 120 ),
new Vector2( 8, 120 )
}));
image.Save($"{path}/clipped-corner.png");
}
}
}
}

2
tests/Images/External

@ -1 +1 @@
Subproject commit 5036d47ec2393d90efb6f3864d828e2e4381947f
Subproject commit 0edeb078b9d9f9c8be016ca514a3a625c4768bd6
Loading…
Cancel
Save