Skip to content

Commit

Permalink
Fix alpha blending and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
JimBobSquarePants committed Oct 30, 2023
1 parent 56588d3 commit 66f444d
Show file tree
Hide file tree
Showing 58 changed files with 302 additions and 104 deletions.
174 changes: 105 additions & 69 deletions src/ImageSharp/Formats/Png/PngDecoderCore.cs

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion src/ImageSharp/ImageFrameCollection{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.

using System.Collections;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;

Expand Down
26 changes: 19 additions & 7 deletions tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ public partial class PngDecoderTests
{ TestImages.Png.Rgba64Bpp, typeof(Image<Rgba64>) },
};

public static readonly string[] MultiFrameTestFiles =
{
//TestImages.Png.APng,

Check warning on line 83 in tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

View workflow job for this annotation

GitHub Actions / Build (false, ubuntu-latest, net6.0, 6.0.x, -x64, false)

Check warning on line 83 in tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

View workflow job for this annotation

GitHub Actions / Build (false, windows-latest, net6.0, 6.0.x, -x64, false)

Check warning on line 83 in tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

View workflow job for this annotation

GitHub Actions / Build (false, windows-latest, net7.0, 7.0.x, true, -x64, false)

//TestImages.Png.SplitIDatZeroLength,

Check warning on line 84 in tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

View workflow job for this annotation

GitHub Actions / Build (false, ubuntu-latest, net6.0, 6.0.x, -x64, false)

Check warning on line 84 in tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

View workflow job for this annotation

GitHub Actions / Build (false, windows-latest, net6.0, 6.0.x, -x64, false)

Check warning on line 84 in tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

View workflow job for this annotation

GitHub Actions / Build (false, windows-latest, net7.0, 7.0.x, true, -x64, false)

//TestImages.Png.DisposeNone,

Check warning on line 85 in tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

View workflow job for this annotation

GitHub Actions / Build (false, ubuntu-latest, net6.0, 6.0.x, -x64, false)

//TestImages.Png.DisposeBackground,

Check warning on line 86 in tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

View workflow job for this annotation

GitHub Actions / Build (false, ubuntu-latest, net6.0, 6.0.x, -x64, false)

//TestImages.Png.DisposeBackgroundRegion,

Check warning on line 87 in tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

View workflow job for this annotation

GitHub Actions / Build (false, ubuntu-latest, net6.0, 6.0.x, -x64, false)

//TestImages.Png.DisposePreviousFirst,
//TestImages.Png.DisposeBackgroundBeforeRegion,
TestImages.Png.BlendOverMultiple
};

[Theory]
[MemberData(nameof(PixelFormatRange))]
public void Decode_NonGeneric_CreatesCorrectImageType(string path, Type type)
Expand Down Expand Up @@ -107,16 +119,16 @@ public void Decode<TPixel>(TestImageProvider<TPixel> provider)
}

[Theory]
[WithFile(TestImages.Png.APng, PixelTypes.Rgba32)]
public void Decode_APng<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
[WithFileCollection(nameof(MultiFrameTestFiles), PixelTypes.Rgba32)]
public void Decode_VerifyAllFrames<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance);

Assert.Equal(5, image.Frames.Count);

// TODO: Assertations.
// MagickReferenceDecoder cannot decode APNGs (Though ImageMagick can, we likely need to update our mapping implementation)
// Some images have many frames, only compare a selection of them.
static bool Predicate(int i, int _) => i <= 8 || i % 8 == 0;
image.DebugSaveMultiFrame(provider, predicate: Predicate);
image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact, predicate: Predicate);
}

[Theory]
Expand Down
12 changes: 11 additions & 1 deletion tests/ImageSharp.Tests/TestImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,17 @@ public static class Png
public const string TestPattern31x31 = "Png/testpattern31x31.png";
public const string TestPattern31x31HalfTransparent = "Png/testpattern31x31-halftransparent.png";
public const string XmpColorPalette = "Png/xmp-colorpalette.png";
public const string APng = "Png/apng.png";

// Animated
// https://philip.html5.org/tests/apng/tests.html
public const string APng = "Png/animated/apng.png";
public const string SplitIDatZeroLength = "Png/animated/4-split-idat-zero-length.png";
public const string DisposeNone = "Png/animated/7-dispose-none.png";
public const string DisposeBackground = "Png/animated/8-dispose-background.png";
public const string DisposeBackgroundBeforeRegion = "Png/animated/14-dispose-background-before-region.png";
public const string DisposeBackgroundRegion = "Png/animated/15-dispose-background-region.png";
public const string DisposePreviousFirst = "Png/animated/12-dispose-prev-first.png";
public const string BlendOverMultiple = "Png/animated/21-blend-over-multiple.png";

// Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html
public const string Filter0 = "Png/filter0.png";
Expand Down
28 changes: 9 additions & 19 deletions tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public class ImagingTestCaseUtility
return path;
}

public IEnumerable<string> GetTestOutputFileNamesMultiFrame(
public IEnumerable<(int Index, string FileName)> GetTestOutputFileNamesMultiFrame(
int frameCount,
string extension = null,
object testOutputDetails = null,
Expand All @@ -201,11 +201,11 @@ public class ImagingTestCaseUtility
continue;
}

yield return $"{baseDir}/{i:D2}.{extension}";
yield return (i, $"{baseDir}/{i:D2}.{extension}");
}
}

public string[] SaveTestOutputFileMultiFrame<TPixel>(
public (int Index, string FileName)[] SaveTestOutputFileMultiFrame<TPixel>(
Image<TPixel> image,
string extension = "png",
IImageEncoder encoder = null,
Expand All @@ -216,27 +216,17 @@ public class ImagingTestCaseUtility
{
encoder ??= TestEnvironment.GetReferenceEncoder($"foo.{extension}");

string[] files = this.GetTestOutputFileNamesMultiFrame(
(int Index, string FileName)[] files = this.GetTestOutputFileNamesMultiFrame(
image.Frames.Count,
extension,
testOutputDetails,
appendPixelTypeToFileName,
predicate: predicate).ToArray();

for (int i = 0; i < image.Frames.Count; i++)
foreach ((int Index, string FileName) file in files)
{
if (predicate != null && !predicate(i, image.Frames.Count))
{
continue;
}

if (i >= files.Length)
{
break;
}

using Image<TPixel> frameImage = image.Frames.CloneFrame(i);
string filePath = files[i];
using Image<TPixel> frameImage = image.Frames.CloneFrame(file.Index);
string filePath = file.FileName;
using FileStream stream = File.OpenWrite(filePath);
frameImage.Save(stream, encoder);
}
Expand All @@ -252,14 +242,14 @@ public class ImagingTestCaseUtility
=> TestEnvironment.GetReferenceOutputFileName(
this.GetTestOutputFileName(extension, testOutputDetails, appendPixelTypeToFileName, appendSourceFileOrDescription));

public string[] GetReferenceOutputFileNamesMultiFrame(
public (int Index, string FileName)[] GetReferenceOutputFileNamesMultiFrame(
int frameCount,
string extension,
object testOutputDetails,
bool appendPixelTypeToFileName = true,
Func<int, int, bool> predicate = null)
=> this.GetTestOutputFileNamesMultiFrame(frameCount, extension, testOutputDetails, appendPixelTypeToFileName, predicate: predicate)
.Select(TestEnvironment.GetReferenceOutputFileName).ToArray();
.Select(x => (x.Index, TestEnvironment.GetReferenceOutputFileName(x.FileName))).ToArray();

internal void Init(string typeName, string methodName, string outputSubfolderName)
{
Expand Down
7 changes: 4 additions & 3 deletions tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ public static class TestImageExtensions
Func<int, int, bool> predicate = null)
where TPixel : unmanaged, IPixel<TPixel>
{
string[] frameFiles = provider.Utility.GetReferenceOutputFileNamesMultiFrame(
(int Index, string FileName)[] frameFiles = provider.Utility.GetReferenceOutputFileNamesMultiFrame(
frameCount,
extension,
testOutputDetails,
Expand All @@ -345,10 +345,11 @@ public static class TestImageExtensions

List<Image<TPixel>> temporaryFrameImages = new();

IImageDecoder decoder = TestEnvironment.GetReferenceDecoder(frameFiles[0]);
IImageDecoder decoder = TestEnvironment.GetReferenceDecoder(frameFiles[0].FileName);

foreach (string path in frameFiles)
for (int i = 0; i < frameFiles.Length; i++)
{
string path = frameFiles[i].FileName;
if (!File.Exists(path))
{
throw new FileNotFoundException("Reference output file missing: " + path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,13 @@ public void SaveTestOutputFileMultiFrame<TPixel>(TestImageProvider<TPixel> provi
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
string[] files = provider.Utility.SaveTestOutputFileMultiFrame(image);
(int Index, string FileName)[] files = provider.Utility.SaveTestOutputFileMultiFrame(image);

Assert.True(files.Length > 2);
foreach (string path in files)
foreach ((int Index, string FileName) file in files)
{
this.Output.WriteLine(path);
Assert.True(File.Exists(path));
this.Output.WriteLine(file.FileName);
Assert.True(File.Exists(file.FileName));
}
}

Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions tests/Images/Input/Png/animated/12-dispose-prev-first.png
3 changes: 3 additions & 0 deletions tests/Images/Input/Png/animated/21-blend-over-multiple.png
3 changes: 3 additions & 0 deletions tests/Images/Input/Png/animated/4-split-idat-zero-length.png
3 changes: 3 additions & 0 deletions tests/Images/Input/Png/animated/7-dispose-none.png
3 changes: 3 additions & 0 deletions tests/Images/Input/Png/animated/8-dispose-background.png
File renamed without changes

0 comments on commit 66f444d

Please sign in to comment.