public void Encode_8BitColor_WithOctreeQuantizer <TPixel>(TestImageProvider <TPixel> provider) where TPixel : unmanaged, IPixel <TPixel> { if (!TestEnvironment.Is64BitProcess) { return; } using (Image <TPixel> image = provider.GetImage()) { var encoder = new BmpEncoder { BitsPerPixel = BmpBitsPerPixel.Pixel8, Quantizer = new OctreeQuantizer() }; string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "bmp", encoder, appendPixelTypeToFileName: false); // Use the default decoder to test our encoded image. This verifies the content. // We do not verify the reference image though as some are invalid. IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); using (var referenceImage = Image.Load <TPixel>(actualOutputFile, referenceDecoder)) { referenceImage.CompareToReferenceOutput( ImageComparer.TolerantPercentage(0.01f), provider, extension: "bmp", appendPixelTypeToFileName: false, decoder: new MagickReferenceDecoder(false)); } } }
public void TextPositioningIsRobust <TPixel>(TestImageProvider <TPixel> provider, string fontName) where TPixel : struct, IPixel <TPixel> { Font font = CreateFont(fontName, 30); string text = Repeat("Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!\n", 20); var textOptions = new TextGraphicsOptions(true) { WrapTextWidth = 1000 }; string details = fontName.Replace(" ", ""); // Based on the reported 0.1755% difference with AccuracyMultiple = 8 // We should avoid quality regressions leading to higher difference! var comparer = ImageComparer.TolerantPercentage(0.2f); provider.RunValidatingProcessorTest( x => x.DrawText(textOptions, text, font, Color.Black, new PointF(10, 50)), details, comparer, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); }
public void WorksWithDifferentConfigurations <TPixel>( TestImageProvider <TPixel> provider, string brushImage, PixelColorBlendingMode mode, float opacity) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage()) using (var blend = Image.Load <TPixel>(TestFile.Create(brushImage).Bytes)) { var size = new Size(image.Width * 3 / 4, image.Height * 3 / 4); var position = new Point(image.Width / 8, image.Height / 8); blend.Mutate(x => x.Resize(size.Width, size.Height, KnownResamplers.Bicubic)); image.Mutate(x => x.DrawImage(blend, position, mode, opacity)); FormattableString testInfo = $"{System.IO.Path.GetFileNameWithoutExtension(brushImage)}-{mode}-{opacity}"; var encoder = new PngEncoder(); if (provider.PixelType == PixelTypes.Rgba64) { encoder.BitDepth = PngBitDepth.Bit16; } image.DebugSave(provider, testInfo, encoder: encoder); image.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.01f), provider, testInfo); } }
public void FillPolygon_Concave <TPixel>(TestImageProvider <TPixel> provider, bool reverse) where TPixel : unmanaged, IPixel <TPixel> { var points = new 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) }; if (reverse) { Array.Reverse(points); } Color color = Color.LightGreen; provider.RunValidatingProcessorTest( c => c.FillPolygon(color, points), testOutputDetails: $"Reverse({reverse})", comparer: ImageComparer.TolerantPercentage(0.01f), appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); }
public void DrawTransformed <TPixel>(TestImageProvider <TPixel> provider) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage()) using (var blend = Image.Load <TPixel>(TestFile.Create(TestImages.Bmp.Car).Bytes)) { AffineTransformBuilder builder = new AffineTransformBuilder() .AppendRotationDegrees(45F) .AppendScale(new SizeF(.25F, .25F)) .AppendTranslation(new PointF(10, 10)); // Apply a background color so we can see the translation. blend.Mutate(x => x.Transform(builder)); blend.Mutate(x => x.BackgroundColor(Color.HotPink)); // Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2); image.Mutate(x => x.DrawImage(blend, position, .75F)); image.DebugSave(provider, appendSourceFileOrDescription: false, appendPixelTypeToFileName: false); image.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.002f), provider, appendSourceFileOrDescription: false, appendPixelTypeToFileName: false); } }
public void LargeGeoJson_Mississippi_Lines(TestImageProvider <Rgba32> provider, int pixelOffset) { string jsonContent = File.ReadAllText(TestFile.GetInputFileFullPath(TestImages.GeoJson.States)); FeatureCollection features = JsonConvert.DeserializeObject <FeatureCollection>(jsonContent); Feature missisipiGeom = features.Features.Single(f => (string)f.Properties["NAME"] == "Mississippi"); Matrix3x2 transform = Matrix3x2.CreateTranslation(-87, -54) * Matrix3x2.CreateScale(60, 60) * Matrix3x2.CreateTranslation(pixelOffset, pixelOffset); IReadOnlyList <PointF[]> points = PolygonFactory.GetGeoJsonPoints(missisipiGeom, transform); using Image <Rgba32> image = provider.GetImage(); foreach (PointF[] loop in points) { image.Mutate(c => c.DrawLines(Color.White, 1.0f, loop)); } // Very strict tolerance, since the image is sparse (relaxed on .NET Framework) ImageComparer comparer = TestEnvironment.IsFramework ? ImageComparer.TolerantPercentage(1e-3f) : ImageComparer.TolerantPercentage(1e-7f); string details = $"PixelOffset({pixelOffset})"; image.DebugSave(provider, details, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); image.CompareToReferenceOutput(comparer, provider, testOutputDetails: details, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); }
public void FillPolygon_Complex <TPixel>(TestImageProvider <TPixel> provider, bool reverse, IntersectionRule intersectionRule) where TPixel : unmanaged, IPixel <TPixel> { PointF[] contour = PolygonFactory.CreatePointArray((20, 20), (80, 20), (80, 80), (20, 80)); PointF[] hole = PolygonFactory.CreatePointArray((40, 40), (40, 60), (60, 60), (60, 40)); if (reverse) { Array.Reverse(contour); Array.Reverse(hole); } var polygon = new ComplexPolygon( new Path(new LinearLineSegment(contour)), new Path(new LinearLineSegment(hole))); provider.RunValidatingProcessorTest( c => { c.SetShapeOptions(new ShapeOptions() { IntersectionRule = intersectionRule }); c.Fill(Color.White, polygon); }, testOutputDetails: $"Reverse({reverse})_IntersectionRule({intersectionRule})", comparer: ImageComparer.TolerantPercentage(0.01f), appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); }
public void InBox <TPixel>(TestImageProvider <TPixel> provider, int levels, int brushSize) where TPixel : unmanaged, IPixel <TPixel> { provider.RunRectangleConstrainedValidatingProcessorTest( (x, rect) => x.OilPaint(levels, brushSize, rect), $"{levels}-{brushSize}", ImageComparer.TolerantPercentage(0.01F)); }
public void LargeGeoJson_States_Fill(TestImageProvider <Rgba32> provider) { using Image <Rgba32> image = this.FillGeoJsonPolygons(provider, TestImages.GeoJson.States, 16, new Vector2(60), new Vector2(0, -1000)); var comparer = ImageComparer.TolerantPercentage(0.001f); image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); image.CompareToReferenceOutput(comparer, provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); }
public void Resize_WorksWithAllResamplers <TPixel>( TestImageProvider <TPixel> provider, string samplerName, float?ratio, int?specificDestWidth, int?specificDestHeight) where TPixel : struct, IPixel <TPixel> { IResampler sampler = TestUtils.GetResampler(samplerName); // NeirestNeighbourResampler is producing slightly different results With classic .NET framework on 32bit // most likely because of differences in numeric behavior. // The difference is well visible when comparing output for // Resize_WorksWithAllResamplers_TestPattern301x1180_NearestNeighbor-300x480.png // TODO: Should we investigate this? bool allowHigherInaccuracy = !TestEnvironment.Is64BitProcess && string.IsNullOrEmpty(TestEnvironment.NetCoreVersion) && sampler is NearestNeighborResampler; var comparer = ImageComparer.TolerantPercentage(allowHigherInaccuracy ? 0.3f : 0.017f); // Let's make the working buffer size non-default: provider.Configuration.WorkingBufferSizeHintInBytes = 16 * 1024 * SizeOfVector4; provider.RunValidatingProcessorTest( ctx => { SizeF newSize; string destSizeInfo; if (ratio.HasValue) { newSize = ctx.GetCurrentSize() * ratio.Value; destSizeInfo = ratio.Value.ToString(System.Globalization.CultureInfo.InvariantCulture); } else { if (!specificDestWidth.HasValue || !specificDestHeight.HasValue) { throw new InvalidOperationException( "invalid dimensional input for Resize_WorksWithAllResamplers!"); } newSize = new SizeF(specificDestWidth.Value, specificDestHeight.Value); destSizeInfo = $"{newSize.Width}x{newSize.Height}"; } FormattableString testOutputDetails = $"{samplerName}-{destSizeInfo}"; ctx.Apply( img => img.DebugSave( provider, $"{testOutputDetails}-ORIGINAL", appendPixelTypeToFileName: false)); ctx.Resize((Size)newSize, sampler, false); return(testOutputDetails); }, comparer, appendPixelTypeToFileName: false); }
public void EncodeBaseline_WorksWithDiscontiguousBuffers <TPixel>(TestImageProvider <TPixel> provider, JpegSubsample subsample) where TPixel : unmanaged, IPixel <TPixel> { ImageComparer comparer = subsample == JpegSubsample.Ratio444 ? ImageComparer.TolerantPercentage(0.1f) : ImageComparer.TolerantPercentage(5f); provider.LimitAllocatorBufferCapacity().InBytesSqrt(200); TestJpegEncoderCore(provider, subsample, 100, JpegColorType.YCbCr, comparer); }
public void FillPolygon_StarCircle(TestImageProvider <Rgba32> provider) { var circle = new EllipsePolygon(32, 32, 30); var star = new Star(32, 32, 7, 10, 27); IPath shape = circle.Clip(star); provider.RunValidatingProcessorTest( c => c.Fill(Color.White, shape), comparer: ImageComparer.TolerantPercentage(0.01f), appendSourceFileOrDescription: false, appendPixelTypeToFileName: false); }
public void FullImage <TPixel>(TestImageProvider <TPixel> provider, int levels, int brushSize) where TPixel : unmanaged, IPixel <TPixel> { provider.RunValidatingProcessorTest( x => { x.OilPaint(levels, brushSize); return($"{levels}-{brushSize}"); }, ImageComparer.TolerantPercentage(0.01F), appendPixelTypeToFileName: false); }
public static void RunValidatingProcessorTestOnWrappedMemoryImage <TPixel>( this TestImageProvider <TPixel> provider, Action <IImageProcessingContext> process, object testOutputDetails = null, ImageComparer comparer = null, string useReferenceOutputFrom = null, bool appendPixelTypeToFileName = true, bool appendSourceFileOrDescription = true) where TPixel : unmanaged, IPixel <TPixel> { if (comparer == null) { comparer = ImageComparer.TolerantPercentage(0.001f); } using (Image <TPixel> image0 = provider.GetImage()) { Assert.True(image0.DangerousTryGetSinglePixelMemory(out Memory <TPixel> imageMem)); Span <TPixel> imageSpan = imageMem.Span; var mmg = TestMemoryManager <TPixel> .CreateAsCopyOf(imageSpan); using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) { image1.Mutate(process); image1.DebugSave( provider, testOutputDetails, appendPixelTypeToFileName: appendPixelTypeToFileName, appendSourceFileOrDescription: appendSourceFileOrDescription); // TODO: Investigate the cause of pixel inaccuracies under Linux if (TestEnvironment.IsWindows) { string testNameBackup = provider.Utility.TestName; if (useReferenceOutputFrom != null) { provider.Utility.TestName = useReferenceOutputFrom; } image1.CompareToReferenceOutput( comparer, provider, testOutputDetails, appendPixelTypeToFileName: appendPixelTypeToFileName, appendSourceFileOrDescription: appendSourceFileOrDescription); provider.Utility.TestName = testNameBackup; } } } }
public void DiffusionFilter_ShouldNotDependOnSinglePixelType <TPixel>(TestImageProvider <TPixel> provider) where TPixel : struct, IPixel <TPixel> { if (SkipAllDitherTests) { return; } // Increased tolerance because of compatibility issues on .NET 4.6.2: var comparer = ImageComparer.TolerantPercentage(1f); provider.RunValidatingProcessorTest(x => x.Diffuse(DefaultErrorDiffuser, 0.5f), comparer: comparer); }
public void Encode_4Bit_WithV4Header_Works <TPixel>( TestImageProvider <TPixel> provider, BmpBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel <TPixel> { // Oddly the difference only happens locally but we'll not test for that. // I suspect the issue is with the reference codec. ImageComparer comparer = TestEnvironment.IsFramework ? ImageComparer.TolerantPercentage(0.0161F) : ImageComparer.Exact; TestBmpEncoderCore(provider, bitsPerPixel, supportTransparency: true, customComparer: comparer); }
public void Resize_WorksWithAllResamplers <TPixel>(TestImageProvider <TPixel> provider, string name, IResampler sampler, float ratio) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage()) { SizeF newSize = image.Size() * ratio; image.Mutate(x => x.Resize((Size)newSize, sampler, false)); FormattableString details = $"{name}-{ratio.ToString(System.Globalization.CultureInfo.InvariantCulture)}"; image.DebugSave(provider, details); image.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.005f), provider, details); } }
public void BmpDecoder_CanDecodeBitfields_WithUnusualBitmasks <TPixel>(TestImageProvider <TPixel> provider) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage(new BmpDecoder())) { image.DebugSave(provider); // Choosing large tolerance of 6.1 here, because for some reason with the MagickReferenceDecoder the alpha channel // seems to be wrong. This bitmap has an alpha channel of two bits. In many cases this alpha channel has a value of 3, // which should be remapped to 255 for RGBA32, but the magick decoder has a value of 191 set. // The total difference without the alpha channel is still: 0.0204% // Exporting the image as PNG with GIMP yields to the same result as the imagesharp implementation. image.CompareToOriginal(provider, ImageComparer.TolerantPercentage(6.1f), new MagickReferenceDecoder()); } }
public void WorkingBufferSizeHintInBytes_IsAppliedCorrectly <TPixel>( TestImageProvider <TPixel> provider, int workingBufferLimitInRows) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> image0 = provider.GetImage()) { Size destSize = image0.Size() / 4; var configuration = Configuration.CreateDefaultInstance(); int workingBufferSizeHintInBytes = workingBufferLimitInRows * destSize.Width * SizeOfVector4; var allocator = new TestMemoryAllocator(); configuration.MemoryAllocator = allocator; configuration.WorkingBufferSizeHintInBytes = workingBufferSizeHintInBytes; var verticalKernelMap = ResizeKernelMap.Calculate( KnownResamplers.Bicubic, destSize.Height, image0.Height, Configuration.Default.MemoryAllocator); int minimumWorkerAllocationInBytes = verticalKernelMap.MaxDiameter * 2 * destSize.Width * SizeOfVector4; verticalKernelMap.Dispose(); using (Image <TPixel> image = image0.Clone(configuration)) { image.Mutate(x => x.Resize(destSize, KnownResamplers.Bicubic, false)); image.DebugSave( provider, testOutputDetails: workingBufferLimitInRows, appendPixelTypeToFileName: false); image.CompareToReferenceOutput( ImageComparer.TolerantPercentage(0.001f), provider, testOutputDetails: workingBufferLimitInRows, appendPixelTypeToFileName: false); Assert.NotEmpty(allocator.AllocationLog); int maxAllocationSize = allocator.AllocationLog.Where( e => e.ElementType == typeof(Vector4)).Max(e => e.LengthInBytes); Assert.True(maxAllocationSize <= Math.Max(workingBufferSizeHintInBytes, minimumWorkerAllocationInBytes)); } } }
public void DetectEdges_IsNotBoundToSinglePixelType <TPixel>(TestImageProvider <TPixel> provider) where TPixel : unmanaged, IPixel <TPixel> { // James: // I think our comparison is not accurate enough (nor can be) for RgbaVector. // The image pixels are identical according to BeyondCompare. ImageComparer comparer = typeof(TPixel) == typeof(RgbaVector) ? ImageComparer.TolerantPercentage(1f) : OpaqueComparer; using (Image <TPixel> image = provider.GetImage()) { image.Mutate(x => x.DetectEdges()); image.DebugSave(provider); image.CompareToReferenceOutput(comparer, provider); } }
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); }
public void FontShapesAreRenderedCorrectly_LargeText <TPixel>( TestImageProvider <TPixel> provider) where TPixel : unmanaged, IPixel <TPixel> { Font font = CreateFont("OpenSans-Regular.ttf", 36); var sb = new StringBuilder(); string str = Repeat(" ", 78) + "THISISTESTWORDSTHISISTESTWORDSTHISISTESTWORDSTHISISTESTWORDSTHISISTESTWORDS"; sb.Append(str); string newLines = Repeat(Environment.NewLine, 80); sb.Append(newLines); for (int i = 0; i < 10; i++) { sb.AppendLine(str); } var textOptions = new TextGraphicsOptions { TextOptions = { ApplyKerning = true, VerticalAlignment = VerticalAlignment.Top, HorizontalAlignment = HorizontalAlignment.Left, } }; var color = Color.Black; // Based on the reported 0.0270% difference with AccuracyMultiple = 8 // We should avoid quality regressions leading to higher difference! var comparer = ImageComparer.TolerantPercentage(0.03f); provider.VerifyOperation( comparer, img => { img.Mutate(c => c.DrawText(textOptions, sb.ToString(), font, color, new PointF(10, 1))); }, false, false); }
public void AntialiasingIsAntialiased <TPixel>(TestImageProvider <TPixel> provider) where TPixel : unmanaged, IPixel <TPixel> { Font font36 = TestFontUtilities.GetFont(TestFonts.OpenSans, 20); var textOpt = new TextOptions(font36) { Dpi = 96, Origin = new PointF(0, 0) }; var comparer = ImageComparer.TolerantPercentage(0.001f); provider.RunValidatingProcessorTest( x => x .SetGraphicsOptions(o => o.Antialias = false) .DrawText(textOpt, "Hello, World!", Color.Black), comparer: comparer); }
public void CommonDitherers_WorkWithDiscoBuffers <TPixel>( TestImageProvider <TPixel> provider, string name) where TPixel : struct, IPixel <TPixel> { IDither dither = TestUtils.GetDither(name); if (SkipAllDitherTests) { return; } provider.RunBufferCapacityLimitProcessorTest( 41, c => c.Dither(dither), name, ImageComparer.TolerantPercentage(0.001f)); }
public void ImageShouldApplyBinaryMaxChromaThresholdFilter <TPixel>(TestImageProvider <TPixel> provider, float value) where TPixel : unmanaged, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage()) { image.Mutate(x => x.BinaryThreshold(value, BinaryThresholdColorComponent.MaxChroma)); image.DebugSave(provider, value); if (!TestEnvironment.Is64BitProcess && TestEnvironment.IsFramework) { var comparer = ImageComparer.TolerantPercentage(0.0004F); image.CompareToReferenceOutput(comparer, provider, value.ToString("0.00", NumberFormatInfo.InvariantInfo)); } else { image.CompareToReferenceOutput(ImageComparer.Exact, provider, value.ToString("0.00", NumberFormatInfo.InvariantInfo)); } } }
public void DrawImageOfDifferentPixelType <TPixel>(TestImageProvider <TPixel> provider) where TPixel : struct, IPixel <TPixel> { byte[] brushData = TestFile.Create(TestImages.Png.Ducky).Bytes; using (Image <TPixel> image = provider.GetImage()) using (Image brushImage = provider.PixelType == PixelTypes.Rgba32 ? (Image)Image.Load <Bgra32>(brushData) : Image.Load <Rgba32>(brushData)) { image.Mutate(c => c.DrawImage(brushImage, 0.5f)); image.DebugSave(provider, appendSourceFileOrDescription: false); image.CompareToReferenceOutput( ImageComparer.TolerantPercentage(0.01f), provider, appendSourceFileOrDescription: false); } }
/// <summary> /// Same as <see cref="RunValidatingProcessorTest{TPixel}"/> but with an additional <see cref="Rectangle"/> parameter passed to 'process' /// </summary> internal static void RunRectangleConstrainedValidatingProcessorTest <TPixel>( this TestImageProvider <TPixel> provider, Action <IImageProcessingContext <TPixel>, Rectangle> process, object testOutputDetails = null, ImageComparer comparer = null) where TPixel : struct, IPixel <TPixel> { if (comparer == null) { comparer = ImageComparer.TolerantPercentage(0.001f); } using (Image <TPixel> image = provider.GetImage()) { var bounds = new Rectangle(image.Width / 4, image.Width / 4, image.Width / 2, image.Height / 2); image.Mutate(x => process(x, bounds)); image.DebugSave(provider, testOutputDetails); image.CompareToReferenceOutput(comparer, provider, testOutputDetails); } }
private static void VerifyImage <TPixel>( TestImageProvider <TPixel> provider, PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, Image <TPixel> img) where TPixel : unmanaged, IPixel <TPixel> { img.DebugSave( provider, new { composition, blending }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); var comparer = ImageComparer.TolerantPercentage(0.01f, 3); img.CompareFirstFrameToReferenceOutput(comparer, provider, new { composition, blending }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); }
public void ImageBlendingMatchesSvgSpecExamples <TPixel>(TestImageProvider <TPixel> provider, PixelColorBlendingMode mode) where TPixel : struct, IPixel <TPixel> { using (Image <TPixel> background = provider.GetImage()) using (var source = Image.Load <TPixel>(TestFile.Create(TestImages.Png.Ducky).Bytes)) { background.Mutate(x => x.DrawImage(source, mode, 1F)); background.DebugSave( provider, new { mode = mode }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); var comparer = ImageComparer.TolerantPercentage(0.01F); background.CompareToReferenceOutput(comparer, provider, new { mode = mode }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); } }
public void FillTriangleWithGreyscale <TPixel>(TestImageProvider <TPixel> provider) where TPixel : unmanaged, IPixel <TPixel> => provider.VerifyOperation( ImageComparer.TolerantPercentage(0.02f), image => { PointF[] points = { new PointF(10, 0), new PointF(20, 20), new PointF(0, 20) }; var c1 = default(Rgba32); var c2 = default(Rgba32); var c3 = default(Rgba32); new HalfSingle(-1).ToRgba32(ref c1); new HalfSingle(0).ToRgba32(ref c2); new HalfSingle(1).ToRgba32(ref c3); Color[] colors = { new Color(c1), new Color(c2), new Color(c3) }; var brush = new PathGradientBrush(points, colors); image.Mutate(x => x.Fill(brush)); image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); });