Browse Source

Upstream fixes.

pull/2894/head
James Jackson-South 11 months ago
parent
commit
c573228b09
  1. 2
      src/ImageSharp/Formats/Cur/CurFrameMetadata.cs
  2. 6
      src/ImageSharp/Formats/Cur/CurMetadata.cs
  3. 5
      src/ImageSharp/Formats/FormatConnectingFrameMetadata.cs
  4. 5
      src/ImageSharp/Formats/FormatConnectingMetadata.cs
  5. 101
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  6. 26
      src/ImageSharp/Formats/Gif/GifFrameMetadata.cs
  7. 37
      src/ImageSharp/Formats/Gif/GifMetadata.cs
  8. 4
      src/ImageSharp/Formats/Ico/IcoFrameMetadata.cs
  9. 6
      src/ImageSharp/Formats/Ico/IcoMetadata.cs
  10. 16
      src/ImageSharp/Formats/Icon/IconEncoderCore.cs
  11. 3
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  12. 21
      src/ImageSharp/Formats/Png/PngMetadata.cs
  13. 10
      src/ImageSharp/Formats/Webp/Lossy/Vp8Decoder.cs
  14. 10
      src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs
  15. 35
      tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
  16. 12
      tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
  17. 5
      tests/ImageSharp.Tests/Formats/Icon/Cur/CurEncoderTests.cs
  18. 32
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
  19. 59
      tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
  20. 30
      tests/ImageSharp.Tests/TestImages.cs
  21. 91
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
  22. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop.gif/00.png
  23. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop.gif/01.png
  24. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop.gif/02.png
  25. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop.gif/03.png
  26. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop_interlaced.gif/00.png
  27. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop_interlaced.gif/01.png
  28. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop_interlaced.gif/02.png
  29. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop_interlaced.gif/03.png
  30. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_firstframerestoreprev_loop.gif/00.png
  31. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_firstframerestoreprev_loop.gif/01.png
  32. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_firstframerestoreprev_loop.gif/02.png
  33. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_firstframerestoreprev_loop.gif/03.png
  34. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_norestore_loop.gif/00.png
  35. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_norestore_loop.gif/01.png
  36. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_norestore_loop.gif/02.png
  37. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_norestore_loop.gif/03.png
  38. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_restoreprev_loop.gif/00.png
  39. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_restoreprev_loop.gif/01.png
  40. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_restoreprev_loop.gif/02.png
  41. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_restoreprev_loop.gif/03.png
  42. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_loop.gif/00.png
  43. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_loop.gif/01.png
  44. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_loop.gif/02.png
  45. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_loop.gif/03.png
  46. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Static_No_Animation_Rgba32_static_nontransparent.png
  47. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Static_No_Animation_Rgba32_static_transparent.png
  48. 4
      tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png
  49. 4
      tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/00.png
  50. 4
      tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/01.png
  51. 4
      tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/02.png
  52. 4
      tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/03.png
  53. 4
      tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/04.png
  54. 4
      tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/05.png
  55. 4
      tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/06.png
  56. 4
      tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png
  57. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/00.gif
  58. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/08.gif
  59. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/104.gif
  60. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/112.gif
  61. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/16.gif
  62. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/24.gif
  63. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/32.gif
  64. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/40.gif
  65. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/48.gif
  66. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/56.gif
  67. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/64.gif
  68. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/72.gif
  69. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/80.gif
  70. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/88.gif
  71. 3
      tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/96.gif
  72. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/00.png
  73. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/08.png
  74. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/104.png
  75. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/112.png
  76. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/16.png
  77. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/24.png
  78. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/32.png
  79. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/40.png
  80. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/48.png
  81. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/56.png
  82. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/64.png
  83. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/72.png
  84. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/80.png
  85. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/88.png
  86. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/96.png
  87. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_leo.gif/00.png
  88. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_leo.gif/08.png
  89. 3
      tests/Images/Input/Gif/animated_loop.gif
  90. 3
      tests/Images/Input/Gif/animated_loop_interlaced.gif
  91. 3
      tests/Images/Input/Gif/animated_transparent_firstframerestoreprev_loop.gif
  92. 3
      tests/Images/Input/Gif/animated_transparent_frame_norestore_loop.gif
  93. 3
      tests/Images/Input/Gif/animated_transparent_frame_restorebackground_loop.gif
  94. 3
      tests/Images/Input/Gif/animated_transparent_frame_restoreprev_loop.gif
  95. 3
      tests/Images/Input/Gif/animated_transparent_loop.gif
  96. 3
      tests/Images/Input/Gif/animated_transparent_restoreprev_loop.gif
  97. 3
      tests/Images/Input/Gif/static_nontransparent.gif
  98. 3
      tests/Images/Input/Gif/static_transparent.gif
  99. 3
      tests/Images/Input/Webp/alpha-blend-2.webp
  100. 3
      tests/Images/Input/Webp/alpha-blend-3.webp

2
src/ImageSharp/Formats/Cur/CurFrameMetadata.cs

@ -104,7 +104,6 @@ public class CurFrameMetadata : IFormatFrameMetadata<CurFrameMetadata>
Compression = compression,
EncodingWidth = ClampEncodingDimension(metadata.EncodingWidth),
EncodingHeight = ClampEncodingDimension(metadata.EncodingHeight),
ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null
};
}
@ -113,7 +112,6 @@ public class CurFrameMetadata : IFormatFrameMetadata<CurFrameMetadata>
=> new()
{
PixelTypeInfo = this.GetPixelTypeInfo(),
ColorTable = this.ColorTable,
EncodingWidth = this.EncodingWidth,
EncodingHeight = this.EncodingHeight
};

6
src/ImageSharp/Formats/Cur/CurMetadata.cs

@ -71,8 +71,7 @@ public class CurMetadata : IFormatMetadata<CurMetadata>
return new CurMetadata
{
BmpBitsPerPixel = bbpp,
Compression = compression,
ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null
Compression = compression
};
}
@ -145,8 +144,7 @@ public class CurMetadata : IFormatMetadata<CurMetadata>
EncodingType = this.Compression == IconFrameCompression.Bmp && this.BmpBitsPerPixel <= BmpBitsPerPixel.Bit8
? EncodingType.Lossy
: EncodingType.Lossless,
PixelTypeInfo = this.GetPixelTypeInfo(),
ColorTable = this.ColorTable
PixelTypeInfo = this.GetPixelTypeInfo()
};
/// <inheritdoc/>

5
src/ImageSharp/Formats/FormatConnectingFrameMetadata.cs

@ -15,11 +15,6 @@ public class FormatConnectingFrameMetadata
/// </summary>
public PixelTypeInfo? PixelTypeInfo { get; init; }
/// <summary>
/// Gets the frame color table if any.
/// </summary>
public ReadOnlyMemory<Color>? ColorTable { get; init; }
/// <summary>
/// Gets the frame color table mode.
/// </summary>

5
src/ImageSharp/Formats/FormatConnectingMetadata.cs

@ -28,11 +28,6 @@ public class FormatConnectingMetadata
/// </summary>
public PixelTypeInfo PixelTypeInfo { get; init; }
/// <summary>
/// Gets the shared color table if any.
/// </summary>
public ReadOnlyMemory<Color>? ColorTable { get; init; }
/// <summary>
/// Gets the shared color table mode.
/// </summary>

101
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -90,9 +90,9 @@ internal sealed class GifDecoderCore : ImageDecoderCore
private GifMetadata? gifMetadata;
/// <summary>
/// The background color used to fill the frame.
/// The background color index.
/// </summary>
private Color backgroundColor;
private byte backgroundColorIndex;
/// <summary>
/// Initializes a new instance of the <see cref="GifDecoderCore"/> class.
@ -115,11 +115,11 @@ internal sealed class GifDecoderCore : ImageDecoderCore
ImageFrame<TPixel>? previousFrame = null;
FrameDisposalMode? previousDisposalMode = null;
bool globalColorTableUsed = false;
Color backgroundColor = Color.Transparent;
try
{
this.ReadLogicalScreenDescriptorAndGlobalColorTable(stream);
TPixel backgroundPixel = this.backgroundColor.ToPixel<TPixel>();
// Loop though the respective gif parts and read the data.
int nextFlag = stream.ReadByte();
@ -132,7 +132,7 @@ internal sealed class GifDecoderCore : ImageDecoderCore
break;
}
globalColorTableUsed |= this.ReadFrame(stream, ref image, ref previousFrame, ref previousDisposalMode, backgroundPixel);
globalColorTableUsed |= this.ReadFrame(stream, ref image, ref previousFrame, ref previousDisposalMode, ref backgroundColor);
// Reset per-frame state.
this.imageDescriptor = default;
@ -442,14 +442,14 @@ internal sealed class GifDecoderCore : ImageDecoderCore
/// <param name="image">The image to decode the information to.</param>
/// <param name="previousFrame">The previous frame.</param>
/// <param name="previousDisposalMode">The previous frame disposal mode.</param>
/// <param name="backgroundPixel">The background color pixel.</param>
/// <param name="backgroundColor">The background color.</param>
/// <returns>Whether the frame has a global color table.</returns>
private bool ReadFrame<TPixel>(
BufferedReadStream stream,
ref Image<TPixel>? image,
ref ImageFrame<TPixel>? previousFrame,
ref FrameDisposalMode? previousDisposalMode,
TPixel backgroundPixel)
ref Color backgroundColor)
where TPixel : unmanaged, IPixel<TPixel>
{
this.ReadImageDescriptor(stream);
@ -471,7 +471,47 @@ internal sealed class GifDecoderCore : ImageDecoderCore
}
ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>(rawColorTable);
this.ReadFrameColors(stream, ref image, ref previousFrame, ref previousDisposalMode, colorTable, backgroundPixel);
// First frame
if (image is null)
{
if (this.backgroundColorIndex < colorTable.Length)
{
backgroundColor = Color.FromPixel(colorTable[this.backgroundColorIndex]);
}
else
{
backgroundColor = Color.Transparent;
}
if (this.graphicsControlExtension.TransparencyFlag)
{
backgroundColor = backgroundColor.WithAlpha(0);
}
}
this.ReadFrameColors(stream, ref image, ref previousFrame, ref previousDisposalMode, colorTable, backgroundColor.ToPixel<TPixel>());
// Update from newly decoded frame.
if (this.graphicsControlExtension.DisposalMethod != FrameDisposalMode.RestoreToPrevious)
{
if (this.backgroundColorIndex < colorTable.Length)
{
backgroundColor = Color.FromPixel(colorTable[this.backgroundColorIndex]);
}
else
{
backgroundColor = Color.Transparent;
}
// TODO: I don't understand why this is always set to alpha of zero.
// This should be dependent on the transparency flag of the graphics
// control extension. ImageMagick does the same.
// if (this.graphicsControlExtension.TransparencyFlag)
{
backgroundColor = backgroundColor.WithAlpha(0);
}
}
// Skip any remaining blocks
SkipBlock(stream);
@ -504,8 +544,9 @@ internal sealed class GifDecoderCore : ImageDecoderCore
bool transFlag = this.graphicsControlExtension.TransparencyFlag;
FrameDisposalMode disposalMethod = this.graphicsControlExtension.DisposalMethod;
ImageFrame<TPixel> currentFrame;
ImageFrame<TPixel>? restoreFrame = null;
if (previousFrame is null)
if (previousFrame is null && previousDisposalMode is null)
{
image = transFlag
? new Image<TPixel>(this.configuration, imageWidth, imageHeight, this.metadata)
@ -516,26 +557,42 @@ internal sealed class GifDecoderCore : ImageDecoderCore
}
else
{
// We create a clone of the frame and add it.
// We will overpaint the difference of pixels on the current frame to create a complete image.
// This ensures that we have enough pixel data to process without distortion. #2450
currentFrame = image!.Frames.AddFrame(previousFrame);
if (previousFrame != null)
{
currentFrame = image!.Frames.AddFrame(previousFrame);
}
else
{
currentFrame = image!.Frames.CreateFrame(backgroundPixel);
}
this.SetFrameMetadata(currentFrame.Metadata);
if (this.graphicsControlExtension.DisposalMethod == FrameDisposalMode.RestoreToPrevious)
{
restoreFrame = previousFrame;
}
if (previousDisposalMode == FrameDisposalMode.RestoreToBackground)
{
this.RestoreToBackground(currentFrame, backgroundPixel, transFlag);
}
}
Rectangle interest = Rectangle.Intersect(image.Bounds, new(descriptor.Left, descriptor.Top, descriptor.Width, descriptor.Height));
previousFrame = currentFrame;
if (this.graphicsControlExtension.DisposalMethod == FrameDisposalMode.RestoreToPrevious)
{
previousFrame = restoreFrame;
}
else
{
previousFrame = currentFrame;
}
previousDisposalMode = disposalMethod;
if (disposalMethod == FrameDisposalMode.RestoreToBackground)
{
this.restoreArea = interest;
this.restoreArea = Rectangle.Intersect(image.Bounds, new(descriptor.Left, descriptor.Top, descriptor.Width, descriptor.Height));
}
if (colorTable.Length == 0)
@ -814,19 +871,9 @@ internal sealed class GifDecoderCore : ImageDecoderCore
}
}
// If the global color table is present, we can set the background color
// otherwise we default to transparent to match browser behavior.
ReadOnlyMemory<Color>? table = this.gifMetadata.GlobalColorTable;
byte index = this.logicalScreenDescriptor.BackgroundColorIndex;
if (table is not null && index < table.Value.Length)
{
this.backgroundColor = table.Value.Span[index];
this.gifMetadata.BackgroundColorIndex = index;
}
else
{
this.backgroundColor = Color.Transparent;
}
this.backgroundColorIndex = index;
this.gifMetadata.BackgroundColorIndex = index;
}
private unsafe struct ScratchBuffer

26
src/ImageSharp/Formats/Gif/GifFrameMetadata.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Gif;
@ -77,34 +76,12 @@ public class GifFrameMetadata : IFormatFrameMetadata<GifFrameMetadata>
/// <inheritdoc />
public static GifFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata)
{
int index = -1;
const float background = 1f;
if (metadata.ColorTable.HasValue)
=> new()
{
ReadOnlySpan<Color> colorTable = metadata.ColorTable.Value.Span;
for (int i = 0; i < colorTable.Length; i++)
{
Vector4 vector = colorTable[i].ToScaledVector4();
if (vector.W < background)
{
index = i;
}
}
}
bool hasTransparency = index >= 0;
return new()
{
LocalColorTable = metadata.ColorTable,
ColorTableMode = metadata.ColorTableMode,
FrameDelay = (int)Math.Round(metadata.Duration.TotalMilliseconds / 10),
DisposalMode = metadata.DisposalMode,
HasTransparency = hasTransparency,
TransparencyIndex = hasTransparency ? unchecked((byte)index) : byte.MinValue,
};
}
/// <inheritdoc />
public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
@ -118,7 +95,6 @@ public class GifFrameMetadata : IFormatFrameMetadata<GifFrameMetadata>
return new()
{
ColorTable = this.LocalColorTable,
ColorTableMode = this.ColorTableMode,
Duration = TimeSpan.FromMilliseconds(this.FrameDelay * 10),
DisposalMode = this.DisposalMode,

37
src/ImageSharp/Formats/Gif/GifMetadata.cs

@ -71,32 +71,14 @@ public class GifMetadata : IFormatMetadata<GifMetadata>
/// <inheritdoc/>
public static GifMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
{
int index = 0;
Color background = metadata.BackgroundColor;
if (metadata.ColorTable.HasValue)
{
ReadOnlySpan<Color> colorTable = metadata.ColorTable.Value.Span;
for (int i = 0; i < colorTable.Length; i++)
{
if (background != colorTable[i])
{
continue;
}
index = i;
break;
}
}
return new()
=> new()
{
GlobalColorTable = metadata.ColorTable,
// Do not copy the color table or bit depth.
// This will lead to a mismatch when the image is comprised of frames
// extracted individually from a multi-frame image.
ColorTableMode = metadata.ColorTableMode,
RepeatCount = metadata.RepeatCount,
BackgroundColorIndex = (byte)Numerics.Clamp(index, 0, 255),
};
}
/// <inheritdoc/>
public PixelTypeInfo GetPixelTypeInfo()
@ -114,22 +96,13 @@ public class GifMetadata : IFormatMetadata<GifMetadata>
/// <inheritdoc/>
public FormatConnectingMetadata ToFormatConnectingMetadata()
{
bool global = this.ColorTableMode == FrameColorTableMode.Global;
Color color = global && this.GlobalColorTable.HasValue && this.GlobalColorTable.Value.Span.Length > this.BackgroundColorIndex
? this.GlobalColorTable.Value.Span[this.BackgroundColorIndex]
: Color.Transparent;
return new FormatConnectingMetadata()
=> new()
{
AnimateRootFrame = true,
ColorTable = global ? this.GlobalColorTable : null,
BackgroundColor = color,
ColorTableMode = this.ColorTableMode,
PixelTypeInfo = this.GetPixelTypeInfo(),
RepeatCount = this.RepeatCount,
};
}
/// <inheritdoc/>
public void AfterImageApply<TPixel>(Image<TPixel> destination)

4
src/ImageSharp/Formats/Ico/IcoFrameMetadata.cs

@ -96,8 +96,7 @@ public class IcoFrameMetadata : IFormatFrameMetadata<IcoFrameMetadata>
BmpBitsPerPixel = bbpp,
Compression = compression,
EncodingWidth = ClampEncodingDimension(metadata.EncodingWidth),
EncodingHeight = ClampEncodingDimension(metadata.EncodingHeight),
ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null
EncodingHeight = ClampEncodingDimension(metadata.EncodingHeight)
};
}
@ -106,7 +105,6 @@ public class IcoFrameMetadata : IFormatFrameMetadata<IcoFrameMetadata>
=> new()
{
PixelTypeInfo = this.GetPixelTypeInfo(),
ColorTable = this.ColorTable,
EncodingWidth = this.EncodingWidth,
EncodingHeight = this.EncodingHeight
};

6
src/ImageSharp/Formats/Ico/IcoMetadata.cs

@ -71,8 +71,7 @@ public class IcoMetadata : IFormatMetadata<IcoMetadata>
return new IcoMetadata
{
BmpBitsPerPixel = bbpp,
Compression = compression,
ColorTable = compression == IconFrameCompression.Bmp ? metadata.ColorTable : null
Compression = compression
};
}
@ -145,8 +144,7 @@ public class IcoMetadata : IFormatMetadata<IcoMetadata>
EncodingType = this.Compression == IconFrameCompression.Bmp && this.BmpBitsPerPixel <= BmpBitsPerPixel.Bit8
? EncodingType.Lossy
: EncodingType.Lossless,
PixelTypeInfo = this.GetPixelTypeInfo(),
ColorTable = this.ColorTable
PixelTypeInfo = this.GetPixelTypeInfo()
};
/// <inheritdoc/>

16
src/ImageSharp/Formats/Icon/IconEncoderCore.cs

@ -120,17 +120,17 @@ internal abstract class IconEncoderCore
this.entries = this.iconFileType switch
{
IconFileType.ICO =>
image.Frames.Select(i =>
[.. image.Frames.Select(i =>
{
IcoFrameMetadata metadata = i.Metadata.GetIcoMetadata();
return new EncodingFrameMetadata(metadata.Compression, metadata.BmpBitsPerPixel, metadata.ColorTable, metadata.ToIconDirEntry(i.Size));
}).ToArray(),
})],
IconFileType.CUR =>
image.Frames.Select(i =>
[.. image.Frames.Select(i =>
{
CurFrameMetadata metadata = i.Metadata.GetCurMetadata();
return new EncodingFrameMetadata(metadata.Compression, metadata.BmpBitsPerPixel, metadata.ColorTable, metadata.ToIconDirEntry(i.Size));
}).ToArray(),
})],
_ => throw new NotSupportedException(),
};
}
@ -149,9 +149,15 @@ internal abstract class IconEncoderCore
if (metadata.ColorTable is null)
{
int count = metadata.Entry.ColorCount;
if (count == 0)
{
count = 256;
}
return new WuQuantizer(new()
{
MaxColors = metadata.Entry.ColorCount
MaxColors = count
});
}

3
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -1570,7 +1570,8 @@ internal sealed class PngEncoderCore : IDisposable
}
else
{
// Don't use transparency threshold for quantization PNG can handle multiple transparent colors.
// Don't use the default transparency threshold for quantization as PNG can handle multiple transparent colors.
// We choose a value that is close to zero so that edge cases causes by lower bit depths for the alpha channel are handled correctly.
this.quantizer = new WuQuantizer(new QuantizerOptions { TransparencyThreshold = 0, MaxColors = ColorNumerics.GetColorCountForBitDepth(bitDepth) });
}
}

21
src/ImageSharp/Formats/Png/PngMetadata.cs

@ -93,25 +93,6 @@ public class PngMetadata : IFormatMetadata<PngMetadata>
/// <inheritdoc/>
public static PngMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
{
// Should the conversion be from a format that uses a 24bit palette entries (gif)
// we need to clone and adjust the color table to allow for transparency.
Color[]? colorTable = metadata.ColorTable?.ToArray();
if (colorTable != null)
{
for (int i = 0; i < colorTable.Length; i++)
{
ref Color c = ref colorTable[i];
if (c != metadata.BackgroundColor)
{
continue;
}
// Png treats background as fully empty
c = Color.Transparent;
break;
}
}
PngColorType color;
PixelColorType colorType = metadata.PixelTypeInfo.ColorType;
@ -152,7 +133,6 @@ public class PngMetadata : IFormatMetadata<PngMetadata>
{
ColorType = color,
BitDepth = bitDepth,
ColorTable = colorTable,
RepeatCount = metadata.RepeatCount,
};
}
@ -241,7 +221,6 @@ public class PngMetadata : IFormatMetadata<PngMetadata>
public FormatConnectingMetadata ToFormatConnectingMetadata()
=> new()
{
ColorTable = this.ColorTable,
ColorTableMode = FrameColorTableMode.Global,
PixelTypeInfo = this.GetPixelTypeInfo(),
RepeatCount = (ushort)Numerics.Clamp(this.RepeatCount, 0, ushort.MaxValue),

10
src/ImageSharp/Formats/Webp/Lossy/Vp8Decoder.cs

@ -69,11 +69,11 @@ internal class Vp8Decoder : IDisposable
this.YuvBuffer = memoryAllocator.Allocate<byte>((WebpConstants.Bps * 17) + (WebpConstants.Bps * 9) + extraY);
this.CacheY = memoryAllocator.Allocate<byte>((16 * this.CacheYStride) + extraY, AllocationOptions.Clean);
int cacheUvSize = (16 * this.CacheUvStride) + extraUv;
this.CacheU = memoryAllocator.Allocate<byte>(cacheUvSize, AllocationOptions.Clean);
this.CacheV = memoryAllocator.Allocate<byte>(cacheUvSize, AllocationOptions.Clean);
this.TmpYBuffer = memoryAllocator.Allocate<byte>((int)width, AllocationOptions.Clean);
this.TmpUBuffer = memoryAllocator.Allocate<byte>((int)width, AllocationOptions.Clean);
this.TmpVBuffer = memoryAllocator.Allocate<byte>((int)width, AllocationOptions.Clean);
this.CacheU = memoryAllocator.Allocate<byte>(cacheUvSize);
this.CacheV = memoryAllocator.Allocate<byte>(cacheUvSize);
this.TmpYBuffer = memoryAllocator.Allocate<byte>((int)width);
this.TmpUBuffer = memoryAllocator.Allocate<byte>((int)width);
this.TmpVBuffer = memoryAllocator.Allocate<byte>((int)width);
this.Pixels = memoryAllocator.Allocate<byte>((int)(width * height * 4), AllocationOptions.Clean);
#if DEBUG

10
src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs

@ -116,7 +116,7 @@ internal sealed class EuclideanPixelMap<TPixel> : IDisposable
}
// Now I have the index, pop it into the cache for next time
this.cache.Add(rgba, (byte)index);
this.cache.Add(rgba, (short)index);
match = Unsafe.Add(ref paletteRef, (uint)index);
return index;
@ -131,9 +131,11 @@ internal sealed class EuclideanPixelMap<TPixel> : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float DistanceSquared(Rgba32 a, Rgba32 b)
{
Vector4 va = new(a.R, a.G, a.B, a.A);
Vector4 vb = new(b.R, b.G, b.B, b.A);
return Vector4.DistanceSquared(va, vb);
float deltaR = a.R - b.R;
float deltaG = a.G - b.G;
float deltaB = a.B - b.B;
float deltaA = a.A - b.A;
return (deltaR * deltaR) + (deltaG * deltaG) + (deltaB * deltaB) + (deltaA * deltaA);
}
public void Dispose() => this.cache.Dispose();

35
tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs

@ -34,6 +34,41 @@ public class GifDecoderTests
image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact);
}
[Theory]
[WithFile(TestImages.Gif.AnimatedLoop, PixelTypes.Rgba32)]
[WithFile(TestImages.Gif.AnimatedLoopInterlaced, PixelTypes.Rgba32)]
public void Decode_Animated<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
image.DebugSaveMultiFrame(provider);
image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact);
}
[Theory]
[WithFile(TestImages.Gif.AnimatedTransparentNoRestore, PixelTypes.Rgba32)]
[WithFile(TestImages.Gif.AnimatedTransparentRestorePrevious, PixelTypes.Rgba32)]
[WithFile(TestImages.Gif.AnimatedTransparentLoop, PixelTypes.Rgba32)]
[WithFile(TestImages.Gif.AnimatedTransparentFirstFrameRestorePrev, PixelTypes.Rgba32)]
public void Decode_Animated_WithTransparency<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
image.DebugSaveMultiFrame(provider);
image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact);
}
[Theory]
[WithFile(TestImages.Gif.StaticNontransparent, PixelTypes.Rgba32)]
[WithFile(TestImages.Gif.StaticTransparent, PixelTypes.Rgba32)]
public void Decode_Static_No_Animation<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
image.DebugSave(provider);
image.CompareFirstFrameToReferenceOutput(ImageComparer.Exact, provider);
}
[Theory]
[WithFile(TestImages.Gif.Issues.Issue2450_A, PixelTypes.Rgba32)]
[WithFile(TestImages.Gif.Issues.Issue2450_B, PixelTypes.Rgba32)]

12
tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs

@ -422,12 +422,18 @@ public class GifEncoderTests
[Theory]
[WithFile(TestImages.Gif.Issues.Issue2866, PixelTypes.Rgba32)]
public void GifEncoder_CanDecode_Issue2866<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
public void GifEncoder_CanDecode_AndEncode_Issue2866<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
// image.DebugSaveMultiFrame(provider);
// Save the image for visual inspection.
provider.Utility.SaveTestOutputFile(image, "gif", new GifEncoder(), "animated");
// Now compare the debug output with the reference output.
// We do this because the gif encoding is lossy and encoding will lead to differences in the 10s of percent.
// From the unencoded image, we can see that the image is visually the same.
static bool Predicate(int i, int _) => i % 8 == 0; // Image has many frames, only compare a selection of them.
image.CompareDebugOutputToReferenceOutputMultiFrame(provider, ImageComparer.Exact, extension: "gif", predicate: Predicate);
}
}

5
tests/ImageSharp.Tests/Formats/Icon/Cur/CurEncoderTests.cs

@ -4,6 +4,7 @@
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Cur;
using SixLabors.ImageSharp.Formats.Ico;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using static SixLabors.ImageSharp.Tests.TestImages.Cur;
@ -49,8 +50,8 @@ public class CurEncoderTests
using Image<TPixel> encoded = Image.Load<TPixel>(memStream);
encoded.DebugSaveMultiFrame(provider);
// Despite preservation of the palette. The process can still be lossy
encoded.CompareToOriginalMultiFrame(provider, ImageComparer.TolerantPercentage(.23f), IcoDecoder.Instance);
// Color palettes are not preserved when transcoding.
encoded.CompareToOriginalMultiFrame(provider, ImageComparer.TolerantPercentage(.05F), IcoDecoder.Instance);
for (int i = 0; i < image.Frames.Count; i++)
{

32
tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

@ -442,40 +442,42 @@ public partial class PngEncoderTests
}
[Theory]
[WithFile(TestImages.Gif.Leo, PixelTypes.Rgba32, 0.613F)]
[WithFile(TestImages.Gif.Issues.Issue2866, PixelTypes.Rgba32, 1.06F)]
public void Encode_AnimatedFormatTransform_FromGif<TPixel>(TestImageProvider<TPixel> provider, float percentage)
[WithFile(TestImages.Gif.Leo, PixelTypes.Rgba32)]
[WithFile(TestImages.Gif.Issues.Issue2866, PixelTypes.Rgba32)]
public void Encode_AnimatedFormatTransform_FromGif<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
if (TestEnvironment.RunsOnCI)
if (TestEnvironment.RunsOnCI && !TestEnvironment.IsWindows)
{
return;
}
using Image<TPixel> image = provider.GetImage(GifDecoder.Instance);
// Save the image for visual inspection.
provider.Utility.SaveTestOutputFile(image, "png", PngEncoder, "animated");
// Now compare the debug output with the reference output.
// We do this because the transcoding encoding is lossy and encoding will lead to differences.
// From the unencoded image, we can see that the image is visually the same.
static bool Predicate(int i, int _) => i % 8 == 0; // Image has many frames, only compare a selection of them.
image.CompareDebugOutputToReferenceOutputMultiFrame(provider, ImageComparer.Exact, extension: "png", encoder: PngEncoder, predicate: Predicate);
// Now save the image and load it again to compare the metadata.
using MemoryStream memStream = new();
image.Save(memStream, PngEncoder);
memStream.Position = 0;
image.DebugSave(provider: provider, extension: "png", encoder: PngEncoder);
using Image<TPixel> output = Image.Load<TPixel>(memStream);
// TODO: Find a better way to compare.
// The image has been visually checked but the coarse cache used by the palette quantizer
// can lead to minor differences between frames.
ImageComparer.TolerantPercentage(percentage).VerifySimilarity(output, image);
using Image<TPixel> encoded = Image.Load<TPixel>(memStream);
GifMetadata gif = image.Metadata.GetGifMetadata();
PngMetadata png = output.Metadata.GetPngMetadata();
PngMetadata png = encoded.Metadata.GetPngMetadata();
Assert.Equal(gif.RepeatCount, png.RepeatCount);
for (int i = 0; i < image.Frames.Count; i++)
{
GifFrameMetadata gifF = image.Frames[i].Metadata.GetGifMetadata();
PngFrameMetadata pngF = output.Frames[i].Metadata.GetPngMetadata();
PngFrameMetadata pngF = encoded.Frames[i].Metadata.GetPngMetadata();
Assert.Equal(gifF.FrameDelay, (int)(pngF.FrameDelay.ToDouble() * 100));

59
tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs

@ -8,6 +8,8 @@ using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
@ -110,6 +112,63 @@ public class WebpEncoderTests
}
}
[Theory]
// [WithFile(AlphaBlend, PixelTypes.Rgba32)]
// [WithFile(AlphaBlend2, PixelTypes.Rgba32)]
[WithFile(AlphaBlend3, PixelTypes.Rgba32)]
// [WithFile(AlphaBlend4, PixelTypes.Rgba32)]
public void Encode_AlphaBlended<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
WebpEncoder encoder = new()
{
FileFormat = WebpFileFormatType.Lossless
};
QuantizerOptions options = new()
{
TransparencyThreshold = 128 / 255F
};
// First save as gif to gif using different quantizers with default options.
// Alpha thresholding is 64/255F.
GifEncoder gifEncoder = new()
{
Quantizer = new OctreeQuantizer(options)
};
provider.Utility.SaveTestOutputFile(image, "gif", gifEncoder, "octree");
gifEncoder = new GifEncoder()
{
Quantizer = new WuQuantizer(options)
};
provider.Utility.SaveTestOutputFile(image, "gif", gifEncoder, "wu");
// Now clone and quantize the image using the same quantizers without alpha thresholding and save as webp.
options = new()
{
TransparencyThreshold = 0
};
using Image<TPixel> cloned1 = image.Clone();
cloned1.Mutate(c => c.Quantize(new OctreeQuantizer(options)));
provider.Utility.SaveTestOutputFile(cloned1, "webp", encoder, "octree");
using Image<TPixel> cloned2 = image.Clone();
cloned2.Mutate(c => c.Quantize(new WuQuantizer(options)));
provider.Utility.SaveTestOutputFile(cloned2, "webp", encoder, "wu");
// Now blend the images with a blue background and save as webp.
using Image<Rgba32> background1 = new(image.Width, image.Height, Color.White.ToPixel<Rgba32>());
background1.Mutate(c => c.DrawImage(cloned1, 1));
provider.Utility.SaveTestOutputFile(background1, "webp", encoder, "octree-blended");
using Image<Rgba32> background2 = new(image.Width, image.Height, Color.White.ToPixel<Rgba32>());
background2.Mutate(c => c.DrawImage(cloned2, 1));
provider.Utility.SaveTestOutputFile(background2, "webp", encoder, "wu-blended");
}
[Theory]
[WithFile(TestImages.Png.APng, PixelTypes.Rgba32)]
public void Encode_AnimatedFormatTransform_FromPng<TPixel>(TestImageProvider<TPixel> provider)

30
tests/ImageSharp.Tests/TestImages.cs

@ -508,6 +508,31 @@ public static class TestImages
public const string Bit18RGBCube = "Gif/18-bit_RGB_Cube.gif";
public const string Global256NoTrans = "Gif/global-256-no-trans.gif";
// Test images from: https://github.com/peterdn/gif-test-suite.git
// Animated gif with 4 frames, looping forever, no transparency.
public const string AnimatedLoop = "Gif/animated_loop.gif";
// Animated gif with 4 frames, interlaced, looping forever, no transparency.
public const string AnimatedLoopInterlaced = "Gif/animated_loop_interlaced.gif";
// Transparent gif with 4 frames, loops forever.
public const string AnimatedTransparentLoop = "Gif/animated_transparent_loop.gif";
// Transparent gif with 4 frames, loops forever, first frame restore previous.
public const string AnimatedTransparentFirstFrameRestorePrev = "Gif/animated_transparent_firstframerestoreprev_loop.gif";
// Transparent gif with 4 transparent frames, loops forever, no dispose
public const string AnimatedTransparentNoRestore = "Gif/animated_transparent_frame_norestore_loop.gif";
// Transparent gif with 4 transparent frames, loops forever, restore previous.
public const string AnimatedTransparentRestorePrevious = "Gif/animated_transparent_frame_restoreprev_loop.gif";
// Static gif with no animation, no transparency.
public const string StaticNontransparent = "Gif/static_nontransparent.gif";
// Static transparent gif with no animation.
public const string StaticTransparent = "Gif/static_transparent.gif";
// Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite
public const string ZeroSize = "Gif/image-zero-size.gif";
public const string ZeroHeight = "Gif/image-zero-height.gif";
@ -833,6 +858,11 @@ public static class TestImages
public const string Issue2801 = "Webp/issues/Issue2801.webp";
public const string Issue2866 = "Webp/issues/Issue2866.webp";
}
public const string AlphaBlend = "Webp/alpha-blend.webp";
public const string AlphaBlend2 = "Webp/alpha-blend-2.webp";
public const string AlphaBlend3 = "Webp/alpha-blend-3.webp";
public const string AlphaBlend4 = "Webp/alpha-blend-4.webp";
}
public static class Tiff

91
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -107,6 +107,7 @@ public static class TestImageExtensions
ITestImageProvider provider,
object testOutputDetails = null,
string extension = "png",
IImageEncoder encoder = null,
bool appendPixelTypeToFileName = true,
Func<int, int, bool> predicate = null)
where TPixel : unmanaged, IPixel<TPixel>
@ -119,6 +120,7 @@ public static class TestImageExtensions
provider.Utility.SaveTestOutputFileMultiFrame(
image,
extension,
encoder: encoder,
testOutputDetails: testOutputDetails,
appendPixelTypeToFileName: appendPixelTypeToFileName,
predicate: predicate);
@ -277,6 +279,47 @@ public static class TestImageExtensions
return image;
}
public static Image<TPixel> CompareDebugOutputToReferenceOutputMultiFrame<TPixel>(
this Image<TPixel> image,
ITestImageProvider provider,
ImageComparer comparer,
object testOutputDetails = null,
string extension = "png",
IImageEncoder encoder = null,
bool appendPixelTypeToFileName = true,
Func<int, int, bool> predicate = null)
where TPixel : unmanaged, IPixel<TPixel>
{
image.DebugSaveMultiFrame(
provider,
testOutputDetails,
extension,
encoder,
appendPixelTypeToFileName,
predicate: predicate);
using (Image<TPixel> debugImage = GetDebugOutputImageMultiFrame<TPixel>(
provider,
image.Frames.Count,
testOutputDetails,
extension,
appendPixelTypeToFileName,
predicate: predicate))
using (Image<TPixel> referenceImage = GetReferenceOutputImageMultiFrame<TPixel>(
provider,
image.Frames.Count,
testOutputDetails,
extension,
appendPixelTypeToFileName,
predicate: predicate))
{
comparer.VerifySimilarity(referenceImage, debugImage);
}
return image;
}
public static Image<TPixel> CompareToReferenceOutputMultiFrame<TPixel>(
this Image<TPixel> image,
ITestImageProvider provider,
@ -375,6 +418,54 @@ public static class TestImageExtensions
return result;
}
public static Image<TPixel> GetDebugOutputImageMultiFrame<TPixel>(
this ITestImageProvider provider,
int frameCount,
object testOutputDetails = null,
string extension = "png",
bool appendPixelTypeToFileName = true,
Func<int, int, bool> predicate = null)
where TPixel : unmanaged, IPixel<TPixel>
{
(int Index, string FileName)[] frameFiles = [.. provider.Utility.GetTestOutputFileNamesMultiFrame(
frameCount,
extension,
testOutputDetails,
appendPixelTypeToFileName,
predicate: predicate)];
List<Image<TPixel>> temporaryFrameImages = [];
IImageDecoder decoder = TestEnvironment.GetReferenceDecoder(frameFiles[0].FileName);
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);
}
using FileStream stream = File.OpenRead(path);
Image<TPixel> tempImage = decoder.Decode<TPixel>(DecoderOptions.Default, stream);
temporaryFrameImages.Add(tempImage);
}
Image<TPixel> firstTemp = temporaryFrameImages[0];
Image<TPixel> result = new(firstTemp.Width, firstTemp.Height);
foreach (Image<TPixel> fi in temporaryFrameImages)
{
result.Frames.AddFrame(fi.Frames.RootFrame);
fi.Dispose();
}
// Remove the initial empty frame:
result.Frames.RemoveFrame(0);
return result;
}
public static IEnumerable<ImageSimilarityReport> GetReferenceOutputSimilarityReports<TPixel>(
this Image<TPixel> image,
ITestImageProvider provider,

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop.gif/00.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0b980fb1927a70f88bd26b039c54e4ea20a6a1ad68aacd6f1a68a46eb1997a29
size 1180

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop.gif/01.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4006374b88ff4c4ed665333608a19e693fc083ae72beb71850d0e39ad45c9943
size 1144

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop.gif/02.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1f5054e1e464c9e9fc999eec00b9949a6dc256ee062e9910b5718b6d4658661a
size 1303

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop.gif/03.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:49e8bcbcc5dc63fbd555f90a52b4e111cfc058f3adba2ca9c52dec966dbbae8f
size 1371

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop_interlaced.gif/00.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0b980fb1927a70f88bd26b039c54e4ea20a6a1ad68aacd6f1a68a46eb1997a29
size 1180

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop_interlaced.gif/01.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4006374b88ff4c4ed665333608a19e693fc083ae72beb71850d0e39ad45c9943
size 1144

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop_interlaced.gif/02.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1f5054e1e464c9e9fc999eec00b9949a6dc256ee062e9910b5718b6d4658661a
size 1303

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_Rgba32_animated_loop_interlaced.gif/03.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:49e8bcbcc5dc63fbd555f90a52b4e111cfc058f3adba2ca9c52dec966dbbae8f
size 1371

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_firstframerestoreprev_loop.gif/00.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:18b60d2066cb53d41988da37b8c521ddcb5355b995320a8413b95522a0492140
size 687

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_firstframerestoreprev_loop.gif/01.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:30ff7708250c5f02dc02d74238d398b319d8fc6c071178f32f82a17e3b637afd
size 542

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_firstframerestoreprev_loop.gif/02.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d21f4576486692122b6ee719d75883849f65ddb07f632ea1c62b42651c289688
size 591

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_firstframerestoreprev_loop.gif/03.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:88db68f2d59301b8ff9326143455a03c94cb616220f6e8e3832f13effe0c09bc
size 545

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_norestore_loop.gif/00.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:18b60d2066cb53d41988da37b8c521ddcb5355b995320a8413b95522a0492140
size 687

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_norestore_loop.gif/01.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:034b0b6b94c13fbef8c44d650daa07362f113aae6600d63230a3f96e29b16dec
size 790

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_norestore_loop.gif/02.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f4b3684db6e3df52a9eb520d562b51b54632e897e9e39bff5ce904ae00799f2f
size 924

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_norestore_loop.gif/03.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6e33c564f55b653a693105612949401002014821abaecaf654c96d0f2b5d59b4
size 962

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_restoreprev_loop.gif/00.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:18b60d2066cb53d41988da37b8c521ddcb5355b995320a8413b95522a0492140
size 687

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_restoreprev_loop.gif/01.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:034b0b6b94c13fbef8c44d650daa07362f113aae6600d63230a3f96e29b16dec
size 790

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_restoreprev_loop.gif/02.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a4f4eb12da36cd43c620aa5ad1c793bb6eb8431c61d2cc1b77c1118f35a741cc
size 876

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_frame_restoreprev_loop.gif/03.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:15bf02e06c6819d74a0a79cbfc5c86913c248a8812ff0ec613c0e747a000241b
size 789

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_loop.gif/00.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:18b60d2066cb53d41988da37b8c521ddcb5355b995320a8413b95522a0492140
size 687

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_loop.gif/01.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:01f389a2e93023f3132927a9565c04c8c1f827e36111ebe682177adecc3a27ee
size 774

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_loop.gif/02.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:00ef57db2fef89112ac7d1808afb6803612c6a20fc589166be6d6b7007c46400
size 946

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Animated_WithTransparency_Rgba32_animated_transparent_loop.gif/03.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:deafa4d4f8fd84489c061ca1042c2ad9e655fff3b6419248cfb35fa4ea40d9e6
size 1000

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Static_No_Animation_Rgba32_static_nontransparent.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0b980fb1927a70f88bd26b039c54e4ea20a6a1ad68aacd6f1a68a46eb1997a29
size 1180

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_Static_No_Animation_Rgba32_static_transparent.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:18b60d2066cb53d41988da37b8c521ddcb5355b995320a8413b95522a0492140
size 687

4
tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ff67035f78690321c29a4e15c8de7c55bcb3260d667dbd9bced15de6b626fca1
size 148499
oid sha256:a0e1677baade797de1eaec390f2e475865d24de8bd344edddbb3fce200d6bcb0
size 135418

4
tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/00.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:800d1ec2d7c7c99d449db1f49ef202cf18214016eae65ebc4216d6f4b1f4d328
size 537
oid sha256:473c5629d7a9f8b3d6c809e8ede40f8fd38e90beddf71851b352c726fc0570d6
size 534

4
tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/01.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:94dcd97831b16165f3331e429d72d7ef546e04038cab754c7918f9cf535ff30a
size 542
oid sha256:4b9b9f856c0347b460f824d6b027b343c65c67a29360793181c9a29a76f9002b
size 538

4
tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/02.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ec1a589a8fae1b17a82b70a9583ea2ee012a476b1fa8fdba27fee2b7ce0403b2
size 540
oid sha256:74b8015c60d215808b1d663ae4af956d1454414206ba21326ad35b8952b0cab6
size 534

4
tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/03.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0c8751f4fafd5c56066dbb8d64a3890fc420a3bd66881a55e309ba274b6d14e4
size 542
oid sha256:8dacb6a468d3cdc94613d56264ddf34d3649846edf33619fc13b9522fcf982d6
size 539

4
tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/04.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b78516c9874cb15de4c4b98ed307e8105d962fc6bfa7aa3490b2c7e13b455a2d
size 544
oid sha256:8af74db6e01928ad54444fa122e4b87929741052c85abe9c0ffc998adffcbdfc
size 542

4
tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/05.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0c8751f4fafd5c56066dbb8d64a3890fc420a3bd66881a55e309ba274b6d14e4
size 542
oid sha256:8dacb6a468d3cdc94613d56264ddf34d3649846edf33619fc13b9522fcf982d6
size 539

4
tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/06.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ec1a589a8fae1b17a82b70a9583ea2ee012a476b1fa8fdba27fee2b7ce0403b2
size 540
oid sha256:74b8015c60d215808b1d663ae4af956d1454414206ba21326ad35b8952b0cab6
size 534

4
tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5016a323018f09e292165ad5392d82dcbad5e79c2b6b93aff3322dffff80b309
size 126
oid sha256:c816ca1e58d14361b84ba47454e4cbf4d3e4d29dfb7827756eb52ef2604f297c
size 161

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/00.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e738470c04121376b42937f0a72eed3f068bc32bdc788cc0d5877bc7f705f419
size 67611

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/08.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:33b9244a09ed3b7bb17dfcbb694cbacc4f7de8ce6ffd7d7f7c35d424a6e8b2c5
size 58696

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/104.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:380f86015751a8445eb706d99001efe96633c62dd183c22303e732d036175dff
size 86095

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/112.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ae0f80bbc03fc35be4622df85f13f8fe7aec2d981424d9ca6dce88bd23ff2dad
size 59015

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/16.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:696ef2d76fe8ae8a32f0299b668b0cf537c1ffe5ac3ca4b418499f03ca134d89
size 70345

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/24.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1dbd382f6f7b71f4cdffe61c01f0ab04523423576bad6195f8950ff7758792a2
size 67153

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/32.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a2942af218c05b29b4f5a8eb9117c8dea4dcf61b33e1ade3cfa6ba47a0d71f6c
size 68007

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/40.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:45872e2361fc445d956abd5de454ad42bcdb8ade69742b032c865978e41cb477
size 73531

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/48.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:432af0fd8df68724f2faa3fc90dc751ff15a7e45604e20f3737d1902c64a913e
size 72024

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/56.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:aab6a8c7892d8449ad8915f414689019684f99d3f011ddb82f722037b35a70c0
size 77189

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/64.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b93da4e1ab6ed01c561d5b565c078ff8752f7b16b78c733b658237977b1e4689
size 78172

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/72.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a8b426203cd6b6b5f4b97a5213a8a04da66056e3b238be3407751a43b365e11b
size 71198

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/80.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d47400e426792c550afb2797b68e41e3ce04409dde627e0f74c39f216a951f22
size 83675

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/88.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d11ae15a30005e335d2f84f2749573fc59d88d2f1c415cfea2126b47e3dac60b
size 91647

3
tests/Images/External/ReferenceOutput/GifEncoderTests/GifEncoder_CanDecode_AndEncode_Issue2866_Rgba32_issue_2866.gif/96.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6410a7792823ad1c5d5f0fcaed388b362498f1bbd57175b70165e0ce3542662c
size 99183

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/00.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0840e31b83f0f9621e2c98cb784881f88c882f7b558aef889eb2511a893af585
size 63955

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/08.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c674fe70b76d6763215620680f7f24bc3113c3ee98eeb9f9e9572ccd8825c61f
size 68053

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/104.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e46346d886acf62b3d742d6df9ddd9226afd2a4184be045e00724cf0ab4c25b4
size 77343

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/112.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9a647f174ac31570a3e42c472fa888dadcd5117e6f8300ef35b21ed2cff5bd6c
size 65959

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/16.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:951a034bae41acdcbd202d1d8624609bf4a47edbcd94806e4993b0a610fb767e
size 74231

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/24.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ce790490566b7d908e6372746a264b0d207e3b8f906fddf020e68e0b5effd757
size 75693

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/32.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5aea5c9671a91101081287426e57c07fb56c1f072f582bd2f135705c114239f8
size 79474

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/40.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:100d85d20cf39ed4b8f70a7c3a23c5ef857899e3830a7869437eb38819dbe309
size 77200

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/48.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c48b5e76c80649d42c58043d6afaebf872b69031e12af0554847afc167379d9e
size 77420

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/56.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e98364b6e9e913a56e95aace2ac07890e1d4f8a31e44b5195cac0779e9ed75bb
size 75433

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/64.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:53a1c8c9653da218d6f49837a7d5b8623568eb629670d0026e056fb1f13ca52e
size 77402

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/72.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:06f1d36cede878377ef7731ac2530d3cd489fdb09308794315da7b62a48ec667
size 73840

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/80.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3ace97f772679993cb35dc0630d4431019a7e885cd397db98d2b0d91a6c984db
size 81863

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/88.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a1fa4b08ec93e17cfa9906ca6f447da651f469aad3615cc5ae08f4080784c096
size 86317

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_issue_2866.gif/96.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f9e6fd785ab0ef4e75adbf4697d7cb04873a95d01a5fb5197090e87061aa3430
size 88729

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_leo.gif/00.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bf499248f2cdb443d12998c45cad8fcfee04e0febb21965980815aa910bc34ab
size 23945

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Encode_AnimatedFormatTransform_FromGif_Rgba32_leo.gif/08.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0ecf0666ca8b0ef16cf0e6147aea4b76af76f62777a62ea02edcf5cf5a309d8b
size 29721

3
tests/Images/Input/Gif/animated_loop.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a8750149c953e9e910472684158c07a2cb551c1f7e95744ab48db1a67f63f342
size 873

3
tests/Images/Input/Gif/animated_loop_interlaced.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c2bc2f895f03092b1c26381a32b5dd5838aacd3331e07f7e4dae55d5cbb4e149
size 878

3
tests/Images/Input/Gif/animated_transparent_firstframerestoreprev_loop.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6b0cf18d386dc979fcf853d6a9adac673a2709a8751d31a94930199dededa25f
size 536

3
tests/Images/Input/Gif/animated_transparent_frame_norestore_loop.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ad7359801fa6ed89fb041de1e88faea856b1028d9f477fdc4eda774df6e5f1ce
size 685

3
tests/Images/Input/Gif/animated_transparent_frame_restorebackground_loop.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:12254f22eeee9eac6babbfbfb34b6ae9302342454fd6677e8c7c9937656cc127
size 685

3
tests/Images/Input/Gif/animated_transparent_frame_restoreprev_loop.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0cdfba6efea653bb94ede6edd0577ba6af1f7c130307b94903dd94f0f8bbc4f9
size 685

3
tests/Images/Input/Gif/animated_transparent_loop.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3297987894ba27c2acc6a5c447c3d3a52cc169447b451409535decccc1743e55
size 536

3
tests/Images/Input/Gif/animated_transparent_restoreprev_loop.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9418561ef2f2307456bb068ecc1a9d5aa02da5e314e7aadd722985e27503926b
size 536

3
tests/Images/Input/Gif/static_nontransparent.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d0a5e1b2f0c5c1763eb950a1d92c5317f048875e04e88dca7f1a966552c2774c
size 678

3
tests/Images/Input/Gif/static_transparent.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f73f56bbe2206bd1cd8a4625b6a4d61506214b37b61ff3e8194e2030b28abca5
size 341

3
tests/Images/Input/Webp/alpha-blend-2.webp

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b07a49ab8b3af82fa123faf897ec537cd26d57175b1d6301b617372c06432899
size 1580484

3
tests/Images/Input/Webp/alpha-blend-3.webp

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b7244a2cfb42285a196fc7846c49da65fac47e5b85f735bc07b131707c8a2d46
size 948

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save