diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs
index e4ef44564..b9f9b4600 100644
--- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs
+++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs
@@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
sourceRectangle,
this.options))
{
- amount.Span.Fill(this.options.BlendPercentage);
+ amount.Span.Fill(1f);
Parallel.For(
minY,
diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
index 3f48c4e26..796a13a5e 100644
--- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
+++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
@@ -15,6 +15,11 @@ namespace SixLabors.ImageSharp.Formats.Png
///
PngColorType PngColorType { get; }
+ ///
+ /// Gets the png filter method.
+ ///
+ PngFilterMethod PngFilterMethod { get; }
+
///
/// Gets the compression level 1-9.
/// Defaults to 6.
diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs
index 993dc6586..b39a6353e 100644
--- a/src/ImageSharp/Formats/Png/PngEncoder.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoder.cs
@@ -14,10 +14,15 @@ namespace SixLabors.ImageSharp.Formats.Png
public sealed class PngEncoder : IImageEncoder, IPngEncoderOptions
{
///
- /// Gets or sets the png color type
+ /// Gets or sets the png color type.
///
public PngColorType PngColorType { get; set; } = PngColorType.RgbWithAlpha;
+ ///
+ /// Gets or sets the png filter method.
+ ///
+ public PngFilterMethod PngFilterMethod { get; set; } = PngFilterMethod.Adaptive;
+
///
/// Gets or sets the compression level 1-9.
/// Defaults to 6.
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index b95e102c7..f17c9009a 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -46,6 +46,11 @@ namespace SixLabors.ImageSharp.Formats.Png
///
private readonly PngColorType pngColorType;
+ ///
+ /// The png filter method.
+ ///
+ private readonly PngFilterMethod pngFilterMethod;
+
///
/// The quantizer for reducing the color count.
///
@@ -145,6 +150,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
this.memoryManager = memoryManager;
this.pngColorType = options.PngColorType;
+ this.pngFilterMethod = options.PngFilterMethod;
this.compressionLevel = options.CompressionLevel;
this.gamma = options.Gamma;
this.quantizer = options.Quantizer;
@@ -272,7 +278,7 @@ namespace SixLabors.ImageSharp.Formats.Png
///
/// The pixel format.
/// The row span.
- private void CollecTPixelBytes(ReadOnlySpan rowSpan)
+ private void CollectTPixelBytes(ReadOnlySpan rowSpan)
where TPixel : struct, IPixel
{
if (this.bytesPerPixel == 4)
@@ -292,7 +298,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The row span.
/// The row.
- /// The
+ /// The
private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, int row)
where TPixel : struct, IPixel
{
@@ -307,11 +313,35 @@ namespace SixLabors.ImageSharp.Formats.Png
this.CollectGrayscaleBytes(rowSpan);
break;
default:
- this.CollecTPixelBytes(rowSpan);
+ this.CollectTPixelBytes(rowSpan);
break;
}
- return this.GetOptimalFilteredScanline();
+ switch (this.pngFilterMethod)
+ {
+ case PngFilterMethod.None:
+ NoneFilter.Encode(this.rawScanline.Span, this.result.Span);
+ return this.result;
+
+ case PngFilterMethod.Sub:
+ SubFilter.Encode(this.rawScanline.Span, this.sub.Span, this.bytesPerPixel, out int _);
+ return this.sub;
+
+ case PngFilterMethod.Up:
+ UpFilter.Encode(this.rawScanline.Span, this.previousScanline.Span, this.up.Span, out int _);
+ return this.up;
+
+ case PngFilterMethod.Average:
+ AverageFilter.Encode(this.rawScanline.Span, this.previousScanline.Span, this.average.Span, this.bytesPerPixel, out int _);
+ return this.average;
+
+ case PngFilterMethod.Paeth:
+ PaethFilter.Encode(this.rawScanline.Span, this.previousScanline.Span, this.paeth.Span, this.bytesPerPixel, out int _);
+ return this.paeth;
+
+ default:
+ return this.GetOptimalFilteredScanline();
+ }
}
///
diff --git a/src/ImageSharp/Formats/PngFilterMethod.cs b/src/ImageSharp/Formats/PngFilterMethod.cs
new file mode 100644
index 000000000..73c405625
--- /dev/null
+++ b/src/ImageSharp/Formats/PngFilterMethod.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats
+{
+ ///
+ /// Provides enumeration of available PNG filter methods.
+ ///
+ public enum PngFilterMethod
+ {
+ ///
+ /// With the None filter, the scanline is transmitted unmodified.
+ ///
+ None,
+
+ ///
+ /// The Sub filter transmits the difference between each byte and the value of the corresponding
+ /// byte of the prior pixel.
+ ///
+ Sub,
+
+ ///
+ /// The Up filter is just like the filter except that the pixel immediately above the current pixel,
+ /// rather than just to its left, is used as the predictor.
+ ///
+ Up,
+
+ ///
+ /// The Average filter uses the average of the two neighboring pixels (left and above) to predict the value of a pixel.
+ ///
+ Average,
+
+ ///
+ /// 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.
+ ///
+ Paeth,
+
+ ///
+ /// 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.
+ ///
+ Adaptive,
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Drawing/BlendedShapes.cs b/tests/ImageSharp.Tests/Drawing/BlendedShapes.cs
deleted file mode 100644
index c39b5bc34..000000000
--- a/tests/ImageSharp.Tests/Drawing/BlendedShapes.cs
+++ /dev/null
@@ -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
public string TestName { get; set; } = string.Empty;
- private string GetTestOutputFileNameImpl(string extension, string details, bool appendPixelTypeToFileName)
+ private string GetTestOutputFileNameImpl(
+ string extension,
+ string details,
+ bool appendPixelTypeToFileName,
+ bool appendSourceFileOrDescription)
{
- string fn = string.Empty;
-
if (string.IsNullOrWhiteSpace(extension))
{
extension = null;
}
- fn = Path.GetFileNameWithoutExtension(this.SourceFileOrDescription);
+ string fn = appendSourceFileOrDescription
+ ? Path.GetFileNameWithoutExtension(this.SourceFileOrDescription)
+ : "";
if (string.IsNullOrWhiteSpace(extension))
{
@@ -92,20 +96,24 @@ namespace SixLabors.ImageSharp.Tests
}
private static string Inv(FormattableString formattable) => System.FormattableString.Invariant(formattable);
-
+
///
/// Gets the recommended file name for the output of the test
///
/// The required extension
/// The settings modifying the output path
/// A boolean indicating whether to append the pixel type to output file name.
+ /// A boolean indicating whether to append to the test output file name.
/// The file test name
- public string GetTestOutputFileName(string extension = null, object testOutputDetails = null, bool appendPixelTypeToFileName = true)
+ public string GetTestOutputFileName(
+ string extension = null,
+ object testOutputDetails = null,
+ bool appendPixelTypeToFileName = true,
+ bool appendSourceFileOrDescription = true)
{
string detailsString = null;
- string s = testOutputDetails as string;
- if (s != null)
+ if (testOutputDetails is string s)
{
detailsString = s;
}
@@ -128,7 +136,12 @@ namespace SixLabors.ImageSharp.Tests
);
}
}
- return this.GetTestOutputFileNameImpl(extension, detailsString, appendPixelTypeToFileName);
+
+ return this.GetTestOutputFileNameImpl(
+ extension,
+ detailsString,
+ appendPixelTypeToFileName,
+ appendSourceFileOrDescription);
}
@@ -139,15 +152,22 @@ namespace SixLabors.ImageSharp.Tests
/// The image instance
/// The requested extension
/// Optional encoder
+ /// /// A boolean indicating whether to append to the test output file name.
public string SaveTestOutputFile(
Image image,
string extension = null,
IImageEncoder encoder = null,
object testOutputDetails = null,
- bool appendPixelTypeToFileName = true)
+ bool appendPixelTypeToFileName = true,
+ bool appendSourceFileOrDescription = true)
where TPixel : struct, IPixel
{
- string path = this.GetTestOutputFileName(extension, testOutputDetails, appendPixelTypeToFileName);
+ string path = this.GetTestOutputFileName(
+ extension,
+ testOutputDetails,
+ appendPixelTypeToFileName,
+ appendSourceFileOrDescription);
+
encoder = encoder ?? TestEnvironment.GetReferenceEncoder(path);
using (FileStream stream = File.OpenWrite(path))
@@ -161,9 +181,10 @@ namespace SixLabors.ImageSharp.Tests
int frameCount,
string extension = null,
object testOutputDetails = null,
- bool appendPixelTypeToFileName = true)
+ bool appendPixelTypeToFileName = true,
+ bool appendSourceFileOrDescription = true)
{
- string baseDir = this.GetTestOutputFileName("", testOutputDetails, appendPixelTypeToFileName);
+ string baseDir = this.GetTestOutputFileName("", testOutputDetails, appendPixelTypeToFileName, appendSourceFileOrDescription);
if (!Directory.Exists(baseDir))
{
@@ -211,10 +232,11 @@ namespace SixLabors.ImageSharp.Tests
internal string GetReferenceOutputFileName(
string extension,
object testOutputDetails,
- bool appendPixelTypeToFileName)
+ bool appendPixelTypeToFileName,
+ bool appendSourceFileOrDescription)
{
return TestEnvironment.GetReferenceOutputFileName(
- this.GetTestOutputFileName(extension, testOutputDetails, appendPixelTypeToFileName)
+ this.GetTestOutputFileName(extension, testOutputDetails, appendPixelTypeToFileName, appendSourceFileOrDescription)
);
}
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
index ee0382dbe..f37df48dc 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
@@ -61,12 +61,14 @@ namespace SixLabors.ImageSharp.Tests
/// Details to be concatenated to the test output file, describing the parameters of the test.
/// The extension
/// A boolean indicating whether to append the pixel type to the output file name.
+ /// A boolean indicating whether to append to the test output file name.
public static Image DebugSave(
this Image image,
ITestImageProvider provider,
object testOutputDetails = null,
string extension = "png",
- bool appendPixelTypeToFileName = true)
+ bool appendPixelTypeToFileName = true,
+ bool appendSourceFileOrDescription = true)
where TPixel : struct, IPixel
{
if (TestEnvironment.RunsOnCI)
@@ -79,7 +81,8 @@ namespace SixLabors.ImageSharp.Tests
image,
extension,
testOutputDetails: testOutputDetails,
- appendPixelTypeToFileName: appendPixelTypeToFileName);
+ appendPixelTypeToFileName: appendPixelTypeToFileName,
+ appendSourceFileOrDescription: appendSourceFileOrDescription);
return image;
}
@@ -210,7 +213,8 @@ namespace SixLabors.ImageSharp.Tests
object testOutputDetails = null,
string extension = "png",
bool grayscale = false,
- bool appendPixelTypeToFileName = true)
+ bool appendPixelTypeToFileName = true,
+ bool appendSourceFileOrDescription = true)
where TPixel : struct, IPixel
{
using (var firstFrameOnlyImage = new Image(image.Width, image.Height))
@@ -218,7 +222,8 @@ namespace SixLabors.ImageSharp.Tests
provider,
testOutputDetails,
extension,
- appendPixelTypeToFileName))
+ appendPixelTypeToFileName,
+ appendSourceFileOrDescription))
{
firstFrameOnlyImage.Frames.AddFrame(image.Frames.RootFrame);
firstFrameOnlyImage.Frames.RemoveFrame(0);
@@ -255,10 +260,15 @@ namespace SixLabors.ImageSharp.Tests
public static Image GetReferenceOutputImage(this ITestImageProvider provider,
object testOutputDetails = null,
string extension = "png",
- bool appendPixelTypeToFileName = true)
+ bool appendPixelTypeToFileName = true,
+ bool appendSourceFileOrDescription = true)
where TPixel : struct, IPixel
{
- string referenceOutputFile = provider.Utility.GetReferenceOutputFileName(extension, testOutputDetails, appendPixelTypeToFileName);
+ string referenceOutputFile = provider.Utility.GetReferenceOutputFileName(
+ extension,
+ testOutputDetails,
+ appendPixelTypeToFileName,
+ appendSourceFileOrDescription);
if (!File.Exists(referenceOutputFile))
{
@@ -336,13 +346,26 @@ namespace SixLabors.ImageSharp.Tests
Span expectedPixels)
where TPixel : struct, IPixel
{
- Span actual = image.GetPixelSpan();
+ Span actualPixels = image.GetPixelSpan();
- Assert.True(expectedPixels.Length == actual.Length, "Buffer sizes are not equal!");
+ Assert.True(expectedPixels.Length == actualPixels.Length, "Buffer sizes are not equal!");
for (int i = 0; i < expectedPixels.Length; i++)
{
- Assert.True(expectedPixels[i].Equals(actual[i]), $"Pixels are different on position {i}!");
+ Assert.True(expectedPixels[i].Equals(actualPixels[i]), $"Pixels are different on position {i}!");
+ }
+
+ return image;
+ }
+
+ public static Image ComparePixelBufferTo(this Image image, TPixel expectedPixel)
+ where TPixel : struct, IPixel
+ {
+ Span actualPixels = image.GetPixelSpan();
+
+ for (int i = 0; i < actualPixels.Length; i++)
+ {
+ Assert.True(expectedPixel.Equals(actualPixels[i]), $"Pixels are different on position {i}!");
}
return image;
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs
index 4f9a558d4..85729acd3 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs
@@ -147,6 +147,11 @@ namespace SixLabors.ImageSharp.Tests
/// The pixel types
internal static PixelTypes[] GetAllPixelTypes() => (PixelTypes[])Enum.GetValues(typeof(PixelTypes));
+ internal static TPixel GetPixelOfNamedColor(string colorName)
+ where TPixel : struct, IPixel
+ {
+ return (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null);
+ }
///
/// Utility for testing image processor extension methods: