mirror of https://github.com/SixLabors/ImageSharp
13 changed files with 484 additions and 179 deletions
@ -0,0 +1,46 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats |
|||
{ |
|||
/// <summary>
|
|||
/// Provides enumeration of available PNG filter methods.
|
|||
/// </summary>
|
|||
public enum PngFilterMethod |
|||
{ |
|||
/// <summary>
|
|||
/// With the None filter, the scanline is transmitted unmodified.
|
|||
/// </summary>
|
|||
None, |
|||
|
|||
/// <summary>
|
|||
/// The Sub filter transmits the difference between each byte and the value of the corresponding
|
|||
/// byte of the prior pixel.
|
|||
/// </summary>
|
|||
Sub, |
|||
|
|||
/// <summary>
|
|||
/// The Up filter is just like the <see cref="Sub"/> filter except that the pixel immediately above the current pixel,
|
|||
/// rather than just to its left, is used as the predictor.
|
|||
/// </summary>
|
|||
Up, |
|||
|
|||
/// <summary>
|
|||
/// The Average filter uses the average of the two neighboring pixels (left and above) to predict the value of a pixel.
|
|||
/// </summary>
|
|||
Average, |
|||
|
|||
/// <summary>
|
|||
/// The Paeth filter computes a simple linear function of the three neighboring pixels (left, above, upper left),
|
|||
/// then chooses as predictor the neighboring pixel closest to the computed value.
|
|||
/// </summary>
|
|||
Paeth, |
|||
|
|||
/// <summary>
|
|||
/// Computes the output scanline using all five filters, and selects the filter that gives the smallest sum of
|
|||
/// absolute values of outputs.
|
|||
/// This method usually outperforms any single fixed filter choice.
|
|||
/// </summary>
|
|||
Adaptive, |
|||
} |
|||
} |
|||
@ -1,92 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Drawing; |
|||
using SixLabors.Primitives; |
|||
using Xunit; |
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Drawing |
|||
{ |
|||
using SixLabors.ImageSharp.Processing; |
|||
|
|||
public class BlendedShapes |
|||
{ |
|||
public static IEnumerable<object[]> modes = ((PixelBlenderMode[])Enum.GetValues(typeof(PixelBlenderMode))) |
|||
.Select(x => new object[] { x }); |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void DrawBlendedValues<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (var img = provider.GetImage()) |
|||
{ |
|||
var scaleX = (img.Width / 100); |
|||
var scaleY = (img.Height / 100); |
|||
img.Mutate(x => x |
|||
.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY)) |
|||
.Fill(new GraphicsOptions(true) { BlenderMode = mode }, NamedColors<TPixel>.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY) |
|||
)); |
|||
img.DebugSave(provider, new { mode }); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void DrawBlendedValues_transparent<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (var img = provider.GetImage()) |
|||
{ |
|||
var scaleX = (img.Width / 100); |
|||
var scaleY = (img.Height / 100); |
|||
img.Mutate(x => x.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate(x => x.Fill(new GraphicsOptions(true) { BlenderMode = mode }, NamedColors<TPixel>.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); |
|||
img.Mutate(x => x.Fill(new GraphicsOptions(true) { BlenderMode = mode }, NamedColors<TPixel>.Transparent, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); |
|||
img.DebugSave(provider, new { mode }); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void DrawBlendedValues_transparent50Percent<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (var img = provider.GetImage()) |
|||
{ |
|||
var scaleX = (img.Width / 100); |
|||
var scaleY = (img.Height / 100); |
|||
img.Mutate(x => x.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0 * scaleX, 40, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate(x => x.Fill(new GraphicsOptions(true) { BlenderMode = mode }, NamedColors<TPixel>.HotPink, new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); |
|||
var c = NamedColors<TPixel>.Red.ToVector4(); |
|||
c.W *= 0.5f; |
|||
TPixel pixel = default(TPixel); |
|||
pixel.PackFromVector4(c); |
|||
|
|||
img.Mutate(x => x.Fill(new GraphicsOptions(true) { BlenderMode = mode }, pixel, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); |
|||
img.DebugSave(provider, new { mode }); |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void DrawBlendedValues_doldidEllips<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (var img = provider.GetImage()) |
|||
{ |
|||
var scaleX = (img.Width / 100); |
|||
var scaleY = (img.Height / 100); |
|||
img.Mutate(x => x.Fill(NamedColors<TPixel>.DarkBlue, new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate(x => x.Fill(new GraphicsOptions(true) { BlenderMode = mode }, NamedColors<TPixel>.Black, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); |
|||
img.DebugSave(provider, new { mode }); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,79 +1,164 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Processing.Drawing; |
|||
using SixLabors.ImageSharp.Processing.Overlays; |
|||
using SixLabors.ImageSharp.Primitives; |
|||
using SixLabors.ImageSharp.Processing.Drawing.Brushes; |
|||
using SixLabors.Shapes; |
|||
using Xunit; |
|||
// ReSharper disable InconsistentNaming
|
|||
|
|||
namespace SixLabors.ImageSharp.Tests.Drawing |
|||
{ |
|||
public class FillSolidBrushTests : FileTestBase |
|||
|
|||
|
|||
[GroupOutput("Drawing")] |
|||
public class FillSolidBrushTests |
|||
{ |
|||
[Fact] |
|||
public void ImageShouldBeFloodFilledWithColorOnDefaultBackground() |
|||
[Theory] |
|||
[WithBlankImages(1, 1, PixelTypes.Rgba32)] |
|||
[WithBlankImages(7, 4, PixelTypes.Rgba32)] |
|||
[WithBlankImages(16, 7, PixelTypes.Rgba32)] |
|||
[WithBlankImages(33, 32, PixelTypes.Rgba32)] |
|||
[WithBlankImages(400, 500, PixelTypes.Rgba32)] |
|||
public void DoesNotDependOnSize<TPixel>(TestImageProvider<TPixel> provider) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
string path = TestEnvironment.CreateOutputDirectory("Fill", "SolidBrush"); |
|||
using (var image = new Image<Rgba32>(500, 500)) |
|||
using (Image<TPixel> image = provider.GetImage()) |
|||
{ |
|||
image.Mutate(x => x.Fill(Rgba32.HotPink)); |
|||
image.Save($"{path}/DefaultBack.png"); |
|||
|
|||
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) |
|||
{ |
|||
Assert.Equal(Rgba32.HotPink, sourcePixels[9, 9]); |
|||
TPixel color = NamedColors<TPixel>.HotPink; |
|||
image.Mutate(c => c.Fill(color)); |
|||
|
|||
Assert.Equal(Rgba32.HotPink, sourcePixels[199, 149]); |
|||
} |
|||
image.DebugSave(provider, appendPixelTypeToFileName: false); |
|||
image.ComparePixelBufferTo(color); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void ImageShouldBeFloodFilledWithColor() |
|||
[Theory] |
|||
[WithBlankImages(16, 16, PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector)] |
|||
public void DoesNotDependOnSinglePixelType<TPixel>(TestImageProvider<TPixel> provider) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
string path = TestEnvironment.CreateOutputDirectory("Fill", "SolidBrush"); |
|||
using (var image = new Image<Rgba32>(500, 500)) |
|||
using (Image<TPixel> image = provider.GetImage()) |
|||
{ |
|||
image.Mutate(x => x |
|||
.BackgroundColor(Rgba32.Blue) |
|||
.Fill(Rgba32.HotPink)); |
|||
image.Save($"{path}/Simple.png"); |
|||
TPixel color = NamedColors<TPixel>.HotPink; |
|||
image.Mutate(c => c.Fill(color)); |
|||
|
|||
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) |
|||
{ |
|||
Assert.Equal(Rgba32.HotPink, sourcePixels[9, 9]); |
|||
|
|||
Assert.Equal(Rgba32.HotPink, sourcePixels[199, 149]); |
|||
} |
|||
image.DebugSave(provider, appendSourceFileOrDescription: false); |
|||
image.ComparePixelBufferTo(color); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void ImageShouldBeFloodFilledWithColorOpacity() |
|||
[Theory] |
|||
[WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, "Blue")] |
|||
[WithSolidFilledImages(16, 16, "Yellow", PixelTypes.Rgba32, "Khaki")] |
|||
public void WhenColorIsOpaque_OverridePreviousColor<TPixel>(TestImageProvider<TPixel> provider, string newColorName) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
string path = TestEnvironment.CreateOutputDirectory("Fill", "SolidBrush"); |
|||
using (var image = new Image<Rgba32>(500, 500)) |
|||
using (Image<TPixel> image = provider.GetImage()) |
|||
{ |
|||
var color = new Rgba32(Rgba32.HotPink.R, Rgba32.HotPink.G, Rgba32.HotPink.B, 150); |
|||
TPixel color = TestUtils.GetPixelOfNamedColor<TPixel>(newColorName); |
|||
image.Mutate(c => c.Fill(color)); |
|||
|
|||
image.DebugSave(provider, newColorName, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); |
|||
image.ComparePixelBufferTo(color); |
|||
} |
|||
} |
|||
|
|||
public static readonly TheoryData<bool, string, float, PixelBlenderMode, float> BlendData = |
|||
new TheoryData<bool, string, float, PixelBlenderMode, float>() |
|||
{ |
|||
{ false, "Blue", 0.5f, PixelBlenderMode.Normal, 1.0f }, |
|||
{ false, "Blue", 1.0f, PixelBlenderMode.Normal, 0.5f }, |
|||
{ false, "Green", 0.5f, PixelBlenderMode.Normal, 0.3f }, |
|||
{ false, "HotPink", 0.8f, PixelBlenderMode.Normal, 0.8f }, |
|||
|
|||
{ false, "Blue", 0.5f, PixelBlenderMode.Multiply, 1.0f }, |
|||
{ false, "Blue", 1.0f, PixelBlenderMode.Multiply, 0.5f }, |
|||
{ false, "Green", 0.5f, PixelBlenderMode.Multiply, 0.3f }, |
|||
{ false, "HotPink", 0.8f, PixelBlenderMode.Multiply, 0.8f }, |
|||
|
|||
{ false, "Blue", 0.5f, PixelBlenderMode.Add, 1.0f }, |
|||
{ false, "Blue", 1.0f, PixelBlenderMode.Add, 0.5f }, |
|||
{ false, "Green", 0.5f, PixelBlenderMode.Add, 0.3f }, |
|||
{ false, "HotPink", 0.8f, PixelBlenderMode.Add, 0.8f }, |
|||
|
|||
image.Mutate(x => x |
|||
.BackgroundColor(Rgba32.Blue) |
|||
.Fill(color)); |
|||
image.Save($"{path}/Opacity.png"); |
|||
{ true, "Blue", 0.5f, PixelBlenderMode.Normal, 1.0f }, |
|||
{ true, "Blue", 1.0f, PixelBlenderMode.Normal, 0.5f }, |
|||
{ true, "Green", 0.5f, PixelBlenderMode.Normal, 0.3f }, |
|||
{ true, "HotPink", 0.8f, PixelBlenderMode.Normal, 0.8f }, |
|||
|
|||
//shift background color towards forground color by the opacity amount
|
|||
var mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f)); |
|||
{ true, "Blue", 0.5f, PixelBlenderMode.Multiply, 1.0f }, |
|||
{ true, "Blue", 1.0f, PixelBlenderMode.Multiply, 0.5f }, |
|||
{ true, "Green", 0.5f, PixelBlenderMode.Multiply, 0.3f }, |
|||
{ true, "HotPink", 0.8f, PixelBlenderMode.Multiply, 0.8f }, |
|||
|
|||
{ true, "Blue", 0.5f, PixelBlenderMode.Add, 1.0f }, |
|||
{ true, "Blue", 1.0f, PixelBlenderMode.Add, 0.5f }, |
|||
{ true, "Green", 0.5f, PixelBlenderMode.Add, 0.3f }, |
|||
{ true, "HotPink", 0.8f, PixelBlenderMode.Add, 0.8f }, |
|||
}; |
|||
|
|||
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) |
|||
[Theory] |
|||
[WithSolidFilledImages(nameof(BlendData), 16, 16, "Red", PixelTypes.Rgba32)] |
|||
public void BlendFillColorOverBackround<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
bool triggerFillRegion, |
|||
string newColorName, |
|||
float alpha, |
|||
PixelBlenderMode blenderMode, |
|||
float blendPercentage) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
var vec = TestUtils.GetPixelOfNamedColor<RgbaVector>(newColorName).ToVector4(); |
|||
vec.W = alpha; |
|||
|
|||
TPixel fillColor = default; |
|||
fillColor.PackFromVector4(vec); |
|||
|
|||
using (Image<TPixel> image = provider.GetImage()) |
|||
{ |
|||
TPixel bgColor = image[0, 0]; |
|||
|
|||
var options = new GraphicsOptions(false) |
|||
{ |
|||
BlenderMode = blenderMode, |
|||
BlendPercentage = blendPercentage |
|||
}; |
|||
|
|||
if (triggerFillRegion) |
|||
{ |
|||
var region = new ShapeRegion(new RectangularPolygon(0, 0, 16, 16)); |
|||
|
|||
image.Mutate(c => c.Fill(options, new SolidBrush<TPixel>(fillColor), region)); |
|||
} |
|||
else |
|||
{ |
|||
Assert.Equal(mergedColor, sourcePixels[9, 9]); |
|||
Assert.Equal(mergedColor, sourcePixels[199, 149]); |
|||
image.Mutate(c => c.Fill(options, new SolidBrush<TPixel>(fillColor))); |
|||
} |
|||
|
|||
var testOutputDetails = new |
|||
{ |
|||
triggerFillRegion = triggerFillRegion, |
|||
newColorName = newColorName, |
|||
alpha = alpha, |
|||
blenderMode = blenderMode, |
|||
blendPercentage = blendPercentage |
|||
}; |
|||
|
|||
image.DebugSave( |
|||
provider, |
|||
testOutputDetails, |
|||
appendPixelTypeToFileName: false, |
|||
appendSourceFileOrDescription: false); |
|||
|
|||
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(blenderMode); |
|||
TPixel expectedPixel = blender.Blend(bgColor, fillColor, blendPercentage); |
|||
|
|||
image.ComparePixelBufferTo(expectedPixel); |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,154 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Processing.Drawing; |
|||
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; |
|||
using SixLabors.Primitives; |
|||
using Xunit; |
|||
|
|||
// ReSharper disable InconsistentNaming
|
|||
namespace SixLabors.ImageSharp.Tests.Drawing |
|||
{ |
|||
[GroupOutput("Drawing")] |
|||
public class SolidFillBlendedShapesTests |
|||
{ |
|||
public static IEnumerable<object[]> modes = |
|||
((PixelBlenderMode[])Enum.GetValues(typeof(PixelBlenderMode))).Select(x => new object[] { x }); |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendHotPinkRect<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = img.Width / 100; |
|||
int scaleY = img.Height / 100; |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
NamedColors<TPixel>.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY) |
|||
) |
|||
.Fill(new GraphicsOptions(true) { BlenderMode = mode }, |
|||
NamedColors<TPixel>.HotPink, |
|||
new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY)) |
|||
); |
|||
|
|||
VerifyImage(provider, mode, img); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = img.Width / 100; |
|||
int scaleY = img.Height / 100; |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
NamedColors<TPixel>.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { BlenderMode = mode }, |
|||
NamedColors<TPixel>.HotPink, |
|||
new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { BlenderMode = mode }, |
|||
NamedColors<TPixel>.Transparent, |
|||
new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) |
|||
); |
|||
|
|||
VerifyImage(provider, mode, img); |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse<TPixel>( |
|||
TestImageProvider<TPixel> provider, |
|||
PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = (img.Width / 100); |
|||
int scaleY = (img.Height / 100); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
NamedColors<TPixel>.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { BlenderMode = mode }, |
|||
NamedColors<TPixel>.HotPink, |
|||
new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); |
|||
var c = NamedColors<TPixel>.Red.ToVector4(); |
|||
c.W *= 0.5f; |
|||
var pixel = default(TPixel); |
|||
pixel.PackFromVector4(c); |
|||
|
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { BlenderMode = mode }, |
|||
pixel, |
|||
new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) |
|||
); |
|||
|
|||
VerifyImage(provider, mode, img); ; |
|||
} |
|||
} |
|||
|
|||
[Theory] |
|||
[WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] |
|||
public void _1DarkBlueRect_2BlendBlackEllipse<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (Image<TPixel> img = provider.GetImage()) |
|||
{ |
|||
int scaleX = (img.Width / 100); |
|||
int scaleY = (img.Height / 100); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
NamedColors<TPixel>.DarkBlue, |
|||
new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); |
|||
img.Mutate( |
|||
x => x.Fill( |
|||
new GraphicsOptions(true) { BlenderMode = mode }, |
|||
NamedColors<TPixel>.Black, |
|||
new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); |
|||
|
|||
VerifyImage(provider, mode, img); |
|||
} |
|||
} |
|||
|
|||
private static void VerifyImage<TPixel>(TestImageProvider<TPixel> provider, PixelBlenderMode mode, Image<TPixel> img) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
img.DebugSave( |
|||
provider, |
|||
new { mode }, |
|||
appendPixelTypeToFileName: false, |
|||
appendSourceFileOrDescription: false); |
|||
|
|||
var comparer = ImageComparer.TolerantPercentage(0.01f, 3); |
|||
img.CompareFirstFrameToReferenceOutput(comparer, |
|||
provider, |
|||
new { mode }, |
|||
appendPixelTypeToFileName: false, |
|||
appendSourceFileOrDescription: false); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue