Browse Source

Merge branch 'main' into main

qoi
Luis Alfredo Figueroa Bracamontes 3 years ago
committed by GitHub
parent
commit
4a494c7dcf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  2. 16
      src/ImageSharp/Formats/Pbm/BinaryDecoder.cs
  3. 40
      src/ImageSharp/Formats/Pbm/BinaryEncoder.cs
  4. 20
      src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs
  5. 1
      src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
  6. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs
  7. 10
      src/ImageSharp/Primitives/LongRational.cs
  8. 162
      src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs
  9. 59
      src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs
  10. 132
      src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
  11. 4
      src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs
  12. 2
      tests/Directory.Build.targets
  13. 20
      tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs
  14. 67
      tests/ImageSharp.Tests/Drawing/DrawImageTests.cs
  15. 24
      tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs
  16. 1
      tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs
  17. 6
      tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs
  18. 2
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
  19. 64
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
  20. 1
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  21. 8
      tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedMemoryPoolTests.Trim.cs
  22. 45
      tests/ImageSharp.Tests/Numerics/RationalTests.cs
  23. 12
      tests/ImageSharp.Tests/TestImages.cs
  24. 4
      tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png
  25. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png
  26. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png
  27. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png
  28. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png
  29. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png
  30. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png
  31. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png
  32. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png
  33. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png
  34. 4
      tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png
  35. 3
      tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2447_A.png
  36. 3
      tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2447_B.png
  37. 3
      tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2447_C.png
  38. 3
      tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_issue2477.png
  39. 3
      tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png
  40. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png
  41. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png
  42. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png
  43. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png
  44. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png
  45. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png
  46. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png
  47. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png
  48. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png
  49. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png
  50. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png
  51. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png
  52. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png
  53. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png
  54. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png
  55. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png
  56. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png
  57. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png
  58. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png
  59. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png
  60. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png
  61. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png
  62. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png
  63. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png
  64. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png
  65. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png
  66. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png
  67. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png
  68. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png
  69. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png
  70. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png
  71. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png
  72. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png
  73. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png
  74. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png
  75. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png
  76. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png
  77. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png
  78. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png
  79. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png
  80. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png
  81. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png
  82. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png
  83. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png
  84. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png
  85. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png
  86. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png
  87. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png
  88. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png
  89. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png
  90. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png
  91. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png
  92. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png
  93. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png
  94. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png
  95. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png
  96. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png
  97. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png
  98. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png
  99. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png
  100. 4
      tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png

2
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -668,7 +668,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals
if (quantizedPixelRow.Length % 8 != 0) if (quantizedPixelRow.Length % 8 != 0)
{ {
int startIdx = quantizedPixelRow.Length - 7; int startIdx = quantizedPixelRow.Length - (quantizedPixelRow.Length % 8);
endIdx = quantizedPixelRow.Length; endIdx = quantizedPixelRow.Length;
Write1BitPalette(stream, startIdx, endIdx, quantizedPixelRow); Write1BitPalette(stream, startIdx, endIdx, quantizedPixelRow);
} }

16
src/ImageSharp/Formats/Pbm/BinaryDecoder.cs

@ -152,7 +152,6 @@ internal class BinaryDecoder
{ {
int width = pixels.Width; int width = pixels.Width;
int height = pixels.Height; int height = pixels.Height;
int startBit = 0;
MemoryAllocator allocator = configuration.MemoryAllocator; MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner<L8> row = allocator.Allocate<L8>(width); using IMemoryOwner<L8> row = allocator.Allocate<L8>(width);
Span<L8> rowSpan = row.GetSpan(); Span<L8> rowSpan = row.GetSpan();
@ -162,23 +161,12 @@ internal class BinaryDecoder
for (int x = 0; x < width;) for (int x = 0; x < width;)
{ {
int raw = stream.ReadByte(); int raw = stream.ReadByte();
int bit = startBit; int stopBit = Math.Min(8, width - x);
startBit = 0; for (int bit = 0; bit < stopBit; bit++)
for (; bit < 8; bit++)
{ {
bool bitValue = (raw & (0x80 >> bit)) != 0; bool bitValue = (raw & (0x80 >> bit)) != 0;
rowSpan[x] = bitValue ? black : white; rowSpan[x] = bitValue ? black : white;
x++; x++;
if (x == width)
{
startBit = (bit + 1) & 7; // Round off to below 8.
if (startBit != 0)
{
stream.Seek(-1, System.IO.SeekOrigin.Current);
}
break;
}
} }
} }

40
src/ImageSharp/Formats/Pbm/BinaryEncoder.cs

@ -33,10 +33,14 @@ internal class BinaryEncoder
{ {
WriteGrayscale(configuration, stream, image); WriteGrayscale(configuration, stream, image);
} }
else else if (componentType == PbmComponentType.Short)
{ {
WriteWideGrayscale(configuration, stream, image); WriteWideGrayscale(configuration, stream, image);
} }
else
{
throw new ImageFormatException("Component type not supported for Grayscale PBM.");
}
} }
else if (colorType == PbmColorType.Rgb) else if (colorType == PbmColorType.Rgb)
{ {
@ -44,14 +48,25 @@ internal class BinaryEncoder
{ {
WriteRgb(configuration, stream, image); WriteRgb(configuration, stream, image);
} }
else else if (componentType == PbmComponentType.Short)
{ {
WriteWideRgb(configuration, stream, image); WriteWideRgb(configuration, stream, image);
} }
else
{
throw new ImageFormatException("Component type not supported for Color PBM.");
}
} }
else else
{ {
WriteBlackAndWhite(configuration, stream, image); if (componentType == PbmComponentType.Bit)
{
WriteBlackAndWhite(configuration, stream, image);
}
else
{
throw new ImageFormatException("Component type not supported for Black & White PBM.");
}
} }
} }
@ -164,8 +179,6 @@ internal class BinaryEncoder
using IMemoryOwner<L8> row = allocator.Allocate<L8>(width); using IMemoryOwner<L8> row = allocator.Allocate<L8>(width);
Span<L8> rowSpan = row.GetSpan(); Span<L8> rowSpan = row.GetSpan();
int previousValue = 0;
int startBit = 0;
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
Span<TPixel> pixelSpan = pixelBuffer.DangerousGetRowSpan(y); Span<TPixel> pixelSpan = pixelBuffer.DangerousGetRowSpan(y);
@ -177,8 +190,9 @@ internal class BinaryEncoder
for (int x = 0; x < width;) for (int x = 0; x < width;)
{ {
int value = previousValue; int value = 0;
for (int i = startBit; i < 8; i++) int stopBit = Math.Min(8, width - x);
for (int i = 0; i < stopBit; i++)
{ {
if (rowSpan[x].PackedValue < 128) if (rowSpan[x].PackedValue < 128)
{ {
@ -186,19 +200,9 @@ internal class BinaryEncoder
} }
x++; x++;
if (x == width)
{
previousValue = value;
startBit = (i + 1) & 7; // Round off to below 8.
break;
}
} }
if (startBit == 0) stream.WriteByte((byte)value);
{
stream.WriteByte((byte)value);
previousValue = 0;
}
} }
} }
} }

20
src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6BitReader.cs

@ -125,13 +125,29 @@ internal sealed class T6BitReader : T4BitReader
if (value == Len7Code0000000.Code) if (value == Len7Code0000000.Code)
{ {
this.Code = Len7Code0000000; this.Code = Len7Code0000000;
return false;
// We do not support Extensions1D codes, but some encoders (scanner from epson) write a premature EOL code,
// which at this point cannot be distinguished from the marker, because we read the data bit by bit.
// Read the next 5 bit, if its a EOL code return true, indicating its the end of the image.
if (this.ReadValue(5) == 1)
{
return true;
}
throw new NotSupportedException("ccitt extensions 1D codes are not supported.");
} }
if (value == Len7Code0000001.Code) if (value == Len7Code0000001.Code)
{ {
this.Code = Len7Code0000001; this.Code = Len7Code0000001;
return false;
// Same as above, we do not support Extensions2D codes, but it could be a EOL instead.
if (this.ReadValue(5) == 1)
{
return true;
}
throw new NotSupportedException("ccitt extensions 2D codes are not supported.");
} }
if (value == Len7Code0000011.Code) if (value == Len7Code0000011.Code)

1
src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs

@ -44,6 +44,7 @@ internal static class HorizontalPredictor
UndoRgb24Bit(pixelBytes, width); UndoRgb24Bit(pixelBytes, width);
break; break;
case TiffColorType.Rgba8888: case TiffColorType.Rgba8888:
case TiffColorType.Cmyk:
UndoRgba32Bit(pixelBytes, width); UndoRgba32Bit(pixelBytes, width);
break; break;
case TiffColorType.Rgb161616: case TiffColorType.Rgb161616:

2
src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs

@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.PixelFormats;
/// <summary> /// <summary>
/// Packed pixel type containing three 16-bit unsigned normalized values ranging from 0 to 635535. /// Packed pixel type containing three 16-bit unsigned normalized values ranging from 0 to 65535.
/// <para> /// <para>
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para> /// </para>

10
src/ImageSharp/Primitives/LongRational.cs

@ -131,6 +131,11 @@ internal readonly struct LongRational : IEquatable<LongRational>
/// <param name="bestPrecision">Whether to use the best possible precision when parsing the value.</param> /// <param name="bestPrecision">Whether to use the best possible precision when parsing the value.</param>
public static LongRational FromDouble(double value, bool bestPrecision) public static LongRational FromDouble(double value, bool bestPrecision)
{ {
if (value == 0.0)
{
return new LongRational(0, 1);
}
if (double.IsNaN(value)) if (double.IsNaN(value))
{ {
return new LongRational(0, 0); return new LongRational(0, 0);
@ -201,11 +206,6 @@ internal readonly struct LongRational : IEquatable<LongRational>
return this; return this;
} }
if (this.Numerator == 0)
{
return new LongRational(0, 0);
}
if (this.Numerator == this.Denominator) if (this.Numerator == this.Denominator)
{ {
return new LongRational(1, 1); return new LongRational(1, 1);

162
src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs

@ -15,277 +15,277 @@ public static class DrawImageExtensions
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
float opacity) float opacity)
{ {
GraphicsOptions options = source.GetGraphicsOptions(); GraphicsOptions options = source.GetGraphicsOptions();
return DrawImage(source, image, options.ColorBlendingMode, options.AlphaCompositionMode, opacity); return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity);
} }
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="rectangle">The rectangle structure that specifies the portion of the image to draw.</param> /// <param name="foregroundRectangle">The rectangle structure that specifies the portion of the image to draw.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Rectangle rectangle, Rectangle foregroundRectangle,
float opacity) float opacity)
{ {
GraphicsOptions options = source.GetGraphicsOptions(); GraphicsOptions options = source.GetGraphicsOptions();
return DrawImage(source, image, rectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity); return DrawImage(source, foreground, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity);
} }
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="colorBlending">The color blending mode.</param> /// <param name="colorBlending">The color blending mode.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
float opacity) float opacity)
=> DrawImage(source, image, Point.Empty, colorBlending, opacity); => DrawImage(source, foreground, Point.Empty, colorBlending, opacity);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="rectangle">The rectangle structure that specifies the portion of the image to draw.</param> /// <param name="foregroundRectangle">The rectangle structure that specifies the portion of the image to draw.</param>
/// <param name="colorBlending">The color blending mode.</param> /// <param name="colorBlending">The color blending mode.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Rectangle rectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
float opacity) float opacity)
=> DrawImage(source, image, rectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity); => DrawImage(source, foreground, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="colorBlending">The color blending mode.</param> /// <param name="colorBlending">The color blending mode.</param>
/// <param name="alphaComposition">The alpha composition mode.</param> /// <param name="alphaComposition">The alpha composition mode.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition, PixelAlphaCompositionMode alphaComposition,
float opacity) float opacity)
=> DrawImage(source, image, Point.Empty, colorBlending, alphaComposition, opacity); => DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="rectangle">The rectangle structure that specifies the portion of the image to draw.</param> /// <param name="foregroundRectangle">The rectangle structure that specifies the portion of the image to draw.</param>
/// <param name="colorBlending">The color blending mode.</param> /// <param name="colorBlending">The color blending mode.</param>
/// <param name="alphaComposition">The alpha composition mode.</param> /// <param name="alphaComposition">The alpha composition mode.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Rectangle rectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition, PixelAlphaCompositionMode alphaComposition,
float opacity) float opacity)
=> DrawImage(source, image, Point.Empty, rectangle, colorBlending, alphaComposition, opacity); => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, alphaComposition, opacity);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="options">The options, including the blending type and blending amount.</param> /// <param name="options">The options, including the blending type and blending amount.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
GraphicsOptions options) GraphicsOptions options)
=> DrawImage(source, image, Point.Empty, options); => DrawImage(source, foreground, Point.Empty, options);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="rectangle">The rectangle structure that specifies the portion of the image to draw.</param> /// <param name="foregroundRectangle">The rectangle structure that specifies the portion of the image to draw.</param>
/// <param name="options">The options, including the blending type and blending amount.</param> /// <param name="options">The options, including the blending type and blending amount.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Rectangle rectangle, Rectangle foregroundRectangle,
GraphicsOptions options) GraphicsOptions options)
=> DrawImage(source, image, Point.Empty, rectangle, options); => DrawImage(source, foreground, Point.Empty, foregroundRectangle, options);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="location">The location on the currenty processing image at which to draw.</param> /// <param name="backgroundLocation">The location on the currently processing image at which to draw.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Point location, Point backgroundLocation,
float opacity) float opacity)
{ {
GraphicsOptions options = source.GetGraphicsOptions(); GraphicsOptions options = source.GetGraphicsOptions();
return DrawImage(source, image, location, options.ColorBlendingMode, options.AlphaCompositionMode, opacity); return DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, opacity);
} }
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="location">The location on the currenty processing image at which to draw.</param> /// <param name="backgroundLocation">The location on the currently processing image at which to draw.</param>
/// <param name="rectangle">The rectangle structure that specifies the portion of the image to draw.</param> /// <param name="foregroundRectangle">The rectangle structure that specifies the portion of the image to draw.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Point location, Point backgroundLocation,
Rectangle rectangle, Rectangle foregroundRectangle,
float opacity) float opacity)
{ {
GraphicsOptions options = source.GetGraphicsOptions(); GraphicsOptions options = source.GetGraphicsOptions();
return DrawImage(source, image, location, rectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity); return DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity);
} }
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="location">The location on the currenty processing image at which to draw.</param> /// <param name="backgroundLocation">The location on the currently processing image at which to draw.</param>
/// <param name="colorBlending">The color blending to apply.</param> /// <param name="colorBlending">The color blending to apply.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Point location, Point backgroundLocation,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
float opacity) float opacity)
=> DrawImage(source, image, location, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity); => DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="location">The location on the currenty processing image at which to draw.</param> /// <param name="backgroundLocation">The location on the currently processing image at which to draw.</param>
/// <param name="rectangle">The rectangle structure that specifies the portion of the image to draw.</param> /// <param name="foregroundRectangle">The rectangle structure that specifies the portion of the image to draw.</param>
/// <param name="colorBlending">The color blending to apply.</param> /// <param name="colorBlending">The color blending to apply.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Point location, Point backgroundLocation,
Rectangle rectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
float opacity) float opacity)
=> DrawImage(source, image, location, rectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity); => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="location">The location on the currenty processing image at which to draw.</param> /// <param name="backgroundLocation">The location on the currently processing image at which to draw.</param>
/// <param name="options">The options containing the blend mode and opacity.</param> /// <param name="options">The options containing the blend mode and opacity.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Point location, Point backgroundLocation,
GraphicsOptions options) GraphicsOptions options)
=> DrawImage(source, image, location, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage); => DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="location">The location on the currenty processing image at which to draw.</param> /// <param name="backgroundLocation">The location on the currently processing image at which to draw.</param>
/// <param name="rectangle">The rectangle structure that specifies the portion of the image to draw.</param> /// <param name="foregroundRectangle">The rectangle structure that specifies the portion of the image to draw.</param>
/// <param name="options">The options containing the blend mode and opacity.</param> /// <param name="options">The options containing the blend mode and opacity.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Point location, Point backgroundLocation,
Rectangle rectangle, Rectangle foregroundRectangle,
GraphicsOptions options) GraphicsOptions options)
=> DrawImage(source, image, location, rectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage); => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="location">The location on the currenty processing image at which to draw.</param> /// <param name="backgroundLocation">The location on the currently processing image at which to draw.</param>
/// <param name="colorBlending">The color blending to apply.</param> /// <param name="colorBlending">The color blending to apply.</param>
/// <param name="alphaComposition">The alpha composition mode.</param> /// <param name="alphaComposition">The alpha composition mode.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Point location, Point backgroundLocation,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition, PixelAlphaCompositionMode alphaComposition,
float opacity) float opacity)
=> source.ApplyProcessor(new DrawImageProcessor(image, location, colorBlending, alphaComposition, opacity)); => source.ApplyProcessor(new DrawImageProcessor(foreground, backgroundLocation, foreground.Bounds, colorBlending, alphaComposition, opacity));
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The current image processing context.</param> /// <param name="source">The current image processing context.</param>
/// <param name="image">The image to draw on the currently processing image.</param> /// <param name="foreground">The image to draw on the currently processing image.</param>
/// <param name="location">The location on the currenty processing image at which to draw.</param> /// <param name="backgroundLocation">The location on the currently processing image at which to draw.</param>
/// <param name="rectangle">The rectangle structure that specifies the portion of the image to draw.</param> /// <param name="foregroundRectangle">The rectangle structure that specifies the portion of the image to draw.</param>
/// <param name="colorBlending">The color blending to apply.</param> /// <param name="colorBlending">The color blending to apply.</param>
/// <param name="alphaComposition">The alpha composition mode.</param> /// <param name="alphaComposition">The alpha composition mode.</param>
/// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to draw. Must be between 0 and 1.</param>
/// <returns>The <see cref="IImageProcessingContext"/>.</returns> /// <returns>The <see cref="IImageProcessingContext"/>.</returns>
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image image, Image foreground,
Point location, Point backgroundLocation,
Rectangle rectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition, PixelAlphaCompositionMode alphaComposition,
float opacity) => float opacity) =>
source.ApplyProcessor( source.ApplyProcessor(
new DrawImageProcessor(image, location, colorBlending, alphaComposition, opacity), new DrawImageProcessor(foreground, backgroundLocation, foregroundRectangle, colorBlending, alphaComposition, opacity),
rectangle); foregroundRectangle);
} }

59
src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs

@ -14,20 +14,41 @@ public class DrawImageProcessor : IImageProcessor
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor"/> class. /// Initializes a new instance of the <see cref="DrawImageProcessor"/> class.
/// </summary> /// </summary>
/// <param name="image">The image to blend.</param> /// <param name="foreground">The image to blend.</param>
/// <param name="location">The location to draw the blended image.</param> /// <param name="backgroundLocation">The location to draw the foreground image on the background.</param>
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param> /// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param> /// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend.</param> /// <param name="opacity">The opacity of the image to blend.</param>
public DrawImageProcessor( public DrawImageProcessor(
Image image, Image foreground,
Point location, Point backgroundLocation,
PixelColorBlendingMode colorBlendingMode, PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode, PixelAlphaCompositionMode alphaCompositionMode,
float opacity) float opacity)
: this(foreground, backgroundLocation, foreground.Bounds, colorBlendingMode, alphaCompositionMode, opacity)
{ {
this.Image = image; }
this.Location = location;
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor"/> class.
/// </summary>
/// <param name="foreground">The image to blend.</param>
/// <param name="backgroundLocation">The location to draw the foreground image on the background.</param>
/// <param name="foregroundRectangle">The rectangular portion of the foreground image to draw.</param>
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend.</param>
public DrawImageProcessor(
Image foreground,
Point backgroundLocation,
Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode,
float opacity)
{
this.ForeGround = foreground;
this.BackgroundLocation = backgroundLocation;
this.ForegroundRectangle = foregroundRectangle;
this.ColorBlendingMode = colorBlendingMode; this.ColorBlendingMode = colorBlendingMode;
this.AlphaCompositionMode = alphaCompositionMode; this.AlphaCompositionMode = alphaCompositionMode;
this.Opacity = opacity; this.Opacity = opacity;
@ -36,12 +57,17 @@ public class DrawImageProcessor : IImageProcessor
/// <summary> /// <summary>
/// Gets the image to blend. /// Gets the image to blend.
/// </summary> /// </summary>
public Image Image { get; } public Image ForeGround { get; }
/// <summary>
/// Gets the location to draw the foreground image on the background.
/// </summary>
public Point BackgroundLocation { get; }
/// <summary> /// <summary>
/// Gets the location to draw the blended image. /// Gets the rectangular portion of the foreground image to draw.
/// </summary> /// </summary>
public Point Location { get; } public Rectangle ForegroundRectangle { get; }
/// <summary> /// <summary>
/// Gets the blending mode to use when drawing the image. /// Gets the blending mode to use when drawing the image.
@ -62,8 +88,8 @@ public class DrawImageProcessor : IImageProcessor
public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>(Configuration configuration, Image<TPixelBg> source, Rectangle sourceRectangle) public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>(Configuration configuration, Image<TPixelBg> source, Rectangle sourceRectangle)
where TPixelBg : unmanaged, IPixel<TPixelBg> where TPixelBg : unmanaged, IPixel<TPixelBg>
{ {
ProcessorFactoryVisitor<TPixelBg> visitor = new(configuration, this, source, sourceRectangle); ProcessorFactoryVisitor<TPixelBg> visitor = new(configuration, this, source);
this.Image.AcceptVisitor(visitor); this.ForeGround.AcceptVisitor(visitor);
return visitor.Result!; return visitor.Result!;
} }
@ -73,14 +99,15 @@ public class DrawImageProcessor : IImageProcessor
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly DrawImageProcessor definition; private readonly DrawImageProcessor definition;
private readonly Image<TPixelBg> source; private readonly Image<TPixelBg> source;
private readonly Rectangle sourceRectangle;
public ProcessorFactoryVisitor(Configuration configuration, DrawImageProcessor definition, Image<TPixelBg> source, Rectangle sourceRectangle) public ProcessorFactoryVisitor(
Configuration configuration,
DrawImageProcessor definition,
Image<TPixelBg> source)
{ {
this.configuration = configuration; this.configuration = configuration;
this.definition = definition; this.definition = definition;
this.source = source; this.source = source;
this.sourceRectangle = sourceRectangle;
} }
public IImageProcessor<TPixelBg>? Result { get; private set; } public IImageProcessor<TPixelBg>? Result { get; private set; }
@ -91,8 +118,8 @@ public class DrawImageProcessor : IImageProcessor
this.configuration, this.configuration,
image, image,
this.source, this.source,
this.sourceRectangle, this.definition.BackgroundLocation,
this.definition.Location, this.definition.ForegroundRectangle,
this.definition.ColorBlendingMode, this.definition.ColorBlendingMode,
this.definition.AlphaCompositionMode, this.definition.AlphaCompositionMode,
this.definition.Opacity); this.definition.Opacity);

132
src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs

@ -21,36 +21,42 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixelBg, TPixelFg}"/> class. /// Initializes a new instance of the <see cref="DrawImageProcessor{TPixelBg, TPixelFg}"/> class.
/// </summary> /// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="image">The foreground <see cref="Image{TPixelFg}"/> to blend with the currently processing image.</param> /// <param name="foregroundImage">The foreground <see cref="Image{TPixelFg}"/> to blend with the currently processing image.</param>
/// <param name="source">The source <see cref="Image{TPixelBg}"/> for the current processor instance.</param> /// <param name="backgroundImage">The source <see cref="Image{TPixelBg}"/> for the current processor instance.</param>
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param> /// <param name="backgroundLocation">The location to draw the blended image.</param>
/// <param name="location">The location to draw the blended image.</param> /// <param name="foregroundRectangle">The source area to process for the current processor instance.</param>
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param> /// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param> /// <param name="alphaCompositionMode">The alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
public DrawImageProcessor( public DrawImageProcessor(
Configuration configuration, Configuration configuration,
Image<TPixelFg> image, Image<TPixelFg> foregroundImage,
Image<TPixelBg> source, Image<TPixelBg> backgroundImage,
Rectangle sourceRectangle, Point backgroundLocation,
Point location, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlendingMode, PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode, PixelAlphaCompositionMode alphaCompositionMode,
float opacity) float opacity)
: base(configuration, source, sourceRectangle) : base(configuration, backgroundImage, backgroundImage.Bounds)
{ {
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.Image = image; this.ForegroundImage = foregroundImage;
this.ForegroundRectangle = foregroundRectangle;
this.Opacity = opacity; this.Opacity = opacity;
this.Blender = PixelOperations<TPixelBg>.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); this.Blender = PixelOperations<TPixelBg>.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode);
this.Location = location; this.BackgroundLocation = backgroundLocation;
} }
/// <summary> /// <summary>
/// Gets the image to blend /// Gets the image to blend
/// </summary> /// </summary>
public Image<TPixelFg> Image { get; } public Image<TPixelFg> ForegroundImage { get; }
/// <summary>
/// Gets the rectangular portion of the foreground image to draw.
/// </summary>
public Rectangle ForegroundRectangle { get; }
/// <summary> /// <summary>
/// Gets the opacity of the image to blend /// Gets the opacity of the image to blend
@ -65,43 +71,57 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
/// <summary> /// <summary>
/// Gets the location to draw the blended image /// Gets the location to draw the blended image
/// </summary> /// </summary>
public Point Location { get; } public Point BackgroundLocation { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixelBg> source) protected override void OnFrameApply(ImageFrame<TPixelBg> source)
{ {
Rectangle sourceRectangle = this.SourceRectangle; // Align the bounds so that both the source and targets are the same width and height for blending.
Configuration configuration = this.Configuration; // We ensure that negative locations are subtracted from both bounds so that foreground images can partially overlap.
Rectangle foregroundRectangle = this.ForegroundRectangle;
Image<TPixelFg> targetImage = this.Image;
PixelBlender<TPixelBg> blender = this.Blender;
int locationY = this.Location.Y;
// Align start/end positions. // Sanitize the location so that we don't try and sample outside the image.
Rectangle bounds = targetImage.Bounds; int left = this.BackgroundLocation.X;
int top = this.BackgroundLocation.Y;
int minX = Math.Max(this.Location.X, sourceRectangle.X); if (this.BackgroundLocation.X < 0)
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Right); {
int targetX = minX - this.Location.X; foregroundRectangle.Width += this.BackgroundLocation.X;
left = 0;
int minY = Math.Max(this.Location.Y, sourceRectangle.Y); }
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom);
int width = maxX - minX;
Rectangle workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); if (this.BackgroundLocation.Y < 0)
{
foregroundRectangle.Height += this.BackgroundLocation.Y;
top = 0;
}
// Not a valid operation because rectangle does not overlap with this image. int width = foregroundRectangle.Width;
if (workingRect.Width <= 0 || workingRect.Height <= 0) int height = foregroundRectangle.Height;
if (width <= 0 || height <= 0)
{ {
throw new ImageProcessingException( // Nothing to do, return.
"Cannot draw image because the source image does not overlap the target image."); return;
} }
DrawImageProcessor<TPixelBg, TPixelFg>.RowOperation operation = new(source.PixelBuffer, targetImage.Frames.RootFrame.PixelBuffer, blender, configuration, minX, width, locationY, targetX, this.Opacity); // Sanitize the dimensions so that we don't try and sample outside the image.
foregroundRectangle = Rectangle.Intersect(foregroundRectangle, this.ForegroundImage.Bounds);
Rectangle backgroundRectangle = Rectangle.Intersect(new(left, top, width, height), this.SourceRectangle);
Configuration configuration = this.Configuration;
DrawImageProcessor<TPixelBg, TPixelFg>.RowOperation operation =
new(
configuration,
source.PixelBuffer,
this.ForegroundImage.Frames.RootFrame.PixelBuffer,
backgroundRectangle,
foregroundRectangle,
this.Blender,
this.Opacity);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
configuration, configuration,
workingRect, new(0, 0, foregroundRectangle.Width, foregroundRectangle.Height),
in operation); in operation);
} }
@ -110,36 +130,30 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
/// </summary> /// </summary>
private readonly struct RowOperation : IRowOperation private readonly struct RowOperation : IRowOperation
{ {
private readonly Buffer2D<TPixelBg> source; private readonly Buffer2D<TPixelBg> background;
private readonly Buffer2D<TPixelFg> target; private readonly Buffer2D<TPixelFg> foreground;
private readonly PixelBlender<TPixelBg> blender; private readonly PixelBlender<TPixelBg> blender;
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly int minX; private readonly Rectangle foregroundRectangle;
private readonly int width; private readonly Rectangle backgroundRectangle;
private readonly int locationY;
private readonly int targetX;
private readonly float opacity; private readonly float opacity;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowOperation( public RowOperation(
Buffer2D<TPixelBg> source,
Buffer2D<TPixelFg> target,
PixelBlender<TPixelBg> blender,
Configuration configuration, Configuration configuration,
int minX, Buffer2D<TPixelBg> background,
int width, Buffer2D<TPixelFg> foreground,
int locationY, Rectangle backgroundRectangle,
int targetX, Rectangle foregroundRectangle,
PixelBlender<TPixelBg> blender,
float opacity) float opacity)
{ {
this.source = source;
this.target = target;
this.blender = blender;
this.configuration = configuration; this.configuration = configuration;
this.minX = minX; this.background = background;
this.width = width; this.foreground = foreground;
this.locationY = locationY; this.backgroundRectangle = backgroundRectangle;
this.targetX = targetX; this.foregroundRectangle = foregroundRectangle;
this.blender = blender;
this.opacity = opacity; this.opacity = opacity;
} }
@ -147,8 +161,8 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y) public void Invoke(int y)
{ {
Span<TPixelBg> background = this.source.DangerousGetRowSpan(y).Slice(this.minX, this.width); Span<TPixelBg> background = this.background.DangerousGetRowSpan(y + this.backgroundRectangle.Top).Slice(this.backgroundRectangle.Left, this.backgroundRectangle.Width);
Span<TPixelFg> foreground = this.target.DangerousGetRowSpan(y - this.locationY).Slice(this.targetX, this.width); Span<TPixelFg> foreground = this.foreground.DangerousGetRowSpan(y + this.foregroundRectangle.Top).Slice(this.foregroundRectangle.Left, this.foregroundRectangle.Width);
this.blender.Blend<TPixelFg>(this.configuration, background, background, foreground, this.opacity); this.blender.Blend<TPixelFg>(this.configuration, background, background, foreground, this.opacity);
} }
} }

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

@ -149,13 +149,13 @@ internal sealed class EuclideanPixelMap<TPixel> : IDisposable
/// The granularity of the cache has been determined based upon the current /// The granularity of the cache has been determined based upon the current
/// suite of test images and provides the lowest possible memory usage while /// suite of test images and provides the lowest possible memory usage while
/// providing enough match accuracy. /// providing enough match accuracy.
/// Entry count is currently limited to 1185921 entries (2371842 bytes ~2.26MB). /// Entry count is currently limited to 2335905 entries (4671810 bytes ~4.45MB).
/// </para> /// </para>
/// </remarks> /// </remarks>
private unsafe struct ColorDistanceCache : IDisposable private unsafe struct ColorDistanceCache : IDisposable
{ {
private const int IndexBits = 5; private const int IndexBits = 5;
private const int IndexAlphaBits = 5; private const int IndexAlphaBits = 6;
private const int IndexCount = (1 << IndexBits) + 1; private const int IndexCount = (1 << IndexBits) + 1;
private const int IndexAlphaCount = (1 << IndexAlphaBits) + 1; private const int IndexAlphaCount = (1 << IndexAlphaBits) + 1;
private const int RgbShift = 8 - IndexBits; private const int RgbShift = 8 - IndexBits;

2
tests/Directory.Build.targets

@ -30,7 +30,7 @@
<PackageReference Update="PhotoSauce.MagicScaler" Version="0.12.1" /> <PackageReference Update="PhotoSauce.MagicScaler" Version="0.12.1" />
<PackageReference Update="Pfim" Version="0.9.1" /> <PackageReference Update="Pfim" Version="0.9.1" />
<PackageReference Update="runtime.osx.10.10-x64.CoreCompat.System.Drawing" Version="5.8.64" Condition="'$(IsOSX)'=='true'" /> <PackageReference Update="runtime.osx.10.10-x64.CoreCompat.System.Drawing" Version="5.8.64" Condition="'$(IsOSX)'=='true'" />
<PackageReference Update="SharpZipLib" Version="1.3.2" /> <PackageReference Update="SharpZipLib" Version="1.4.2" />
<PackageReference Update="SkiaSharp" Version="2.80.2" /> <PackageReference Update="SkiaSharp" Version="2.80.2" />
<PackageReference Update="System.Drawing.Common" Version="6.0.0" /> <PackageReference Update="System.Drawing.Common" Version="6.0.0" />
<PackageReference Update="System.IO.Compression" Version="4.3.0" /> <PackageReference Update="System.IO.Compression" Version="4.3.0" />

20
tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs

@ -13,11 +13,12 @@ public class DrawImageExtensionsTests : BaseImageOperationsExtensionTest
[Fact] [Fact]
public void DrawImage_OpacityOnly_VerifyGraphicOptionsTakenFromContext() public void DrawImage_OpacityOnly_VerifyGraphicOptionsTakenFromContext()
{ {
// non-default values as we cant easly defect usage otherwise // non-default values as we cant easily defect usage otherwise
this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor; this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor;
this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; this.options.ColorBlendingMode = PixelColorBlendingMode.Screen;
this.operations.DrawImage(null, 0.5f); using Image<Rgba32> image = new(Configuration.Default, 1, 1);
this.operations.DrawImage(image, 0.5f);
DrawImageProcessor dip = this.Verify<DrawImageProcessor>(); DrawImageProcessor dip = this.Verify<DrawImageProcessor>();
Assert.Equal(0.5, dip.Opacity); Assert.Equal(0.5, dip.Opacity);
@ -28,11 +29,12 @@ public class DrawImageExtensionsTests : BaseImageOperationsExtensionTest
[Fact] [Fact]
public void DrawImage_OpacityAndBlending_VerifyGraphicOptionsTakenFromContext() public void DrawImage_OpacityAndBlending_VerifyGraphicOptionsTakenFromContext()
{ {
// non-default values as we cant easly defect usage otherwise // non-default values as we cant easily defect usage otherwise
this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor; this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor;
this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; this.options.ColorBlendingMode = PixelColorBlendingMode.Screen;
this.operations.DrawImage(null, PixelColorBlendingMode.Multiply, 0.5f); using Image<Rgba32> image = new(Configuration.Default, 1, 1);
this.operations.DrawImage(image, PixelColorBlendingMode.Multiply, 0.5f);
DrawImageProcessor dip = this.Verify<DrawImageProcessor>(); DrawImageProcessor dip = this.Verify<DrawImageProcessor>();
Assert.Equal(0.5, dip.Opacity); Assert.Equal(0.5, dip.Opacity);
@ -43,11 +45,12 @@ public class DrawImageExtensionsTests : BaseImageOperationsExtensionTest
[Fact] [Fact]
public void DrawImage_LocationAndOpacity_VerifyGraphicOptionsTakenFromContext() public void DrawImage_LocationAndOpacity_VerifyGraphicOptionsTakenFromContext()
{ {
// non-default values as we cant easly defect usage otherwise // non-default values as we cant easily defect usage otherwise
this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor; this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor;
this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; this.options.ColorBlendingMode = PixelColorBlendingMode.Screen;
this.operations.DrawImage(null, Point.Empty, 0.5f); using Image<Rgba32> image = new(Configuration.Default, 1, 1);
this.operations.DrawImage(image, Point.Empty, 0.5f);
DrawImageProcessor dip = this.Verify<DrawImageProcessor>(); DrawImageProcessor dip = this.Verify<DrawImageProcessor>();
Assert.Equal(0.5, dip.Opacity); Assert.Equal(0.5, dip.Opacity);
@ -58,11 +61,12 @@ public class DrawImageExtensionsTests : BaseImageOperationsExtensionTest
[Fact] [Fact]
public void DrawImage_LocationAndOpacityAndBlending_VerifyGraphicOptionsTakenFromContext() public void DrawImage_LocationAndOpacityAndBlending_VerifyGraphicOptionsTakenFromContext()
{ {
// non-default values as we cant easly defect usage otherwise // non-default values as we cant easily defect usage otherwise
this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor; this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor;
this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; this.options.ColorBlendingMode = PixelColorBlendingMode.Screen;
this.operations.DrawImage(null, Point.Empty, PixelColorBlendingMode.Multiply, 0.5f); using Image<Rgba32> image = new(Configuration.Default, 1, 1);
this.operations.DrawImage(image, Point.Empty, PixelColorBlendingMode.Multiply, 0.5f);
DrawImageProcessor dip = this.Verify<DrawImageProcessor>(); DrawImageProcessor dip = this.Verify<DrawImageProcessor>();
Assert.Equal(0.5, dip.Opacity); Assert.Equal(0.5, dip.Opacity);

67
tests/ImageSharp.Tests/Drawing/DrawImageTests.cs

@ -190,18 +190,65 @@ public class DrawImageTests
} }
[Theory] [Theory]
[WithSolidFilledImages(100, 100, 255, 255, 255, PixelTypes.Rgba32, -30, -30)] [WithFile(TestImages.Png.Issue2447, PixelTypes.Rgba32)]
[WithSolidFilledImages(100, 100, 255, 255, 255, PixelTypes.Rgba32, 130, -30)] public void Issue2447_A<TPixel>(TestImageProvider<TPixel> provider)
[WithSolidFilledImages(100, 100, 255, 255, 255, PixelTypes.Rgba32, 130, 130)] where TPixel : unmanaged, IPixel<TPixel>
[WithSolidFilledImages(100, 100, 255, 255, 255, PixelTypes.Rgba32, -30, 130)]
public void NonOverlappingImageThrows(TestImageProvider<Rgba32> provider, int x, int y)
{ {
using Image<Rgba32> background = provider.GetImage(); using Image<TPixel> foreground = provider.GetImage();
using Image<Rgba32> overlay = new(Configuration.Default, 10, 10, Color.Black); using Image<Rgba32> background = new(100, 100, new Rgba32(0, 255, 255));
ImageProcessingException ex = Assert.Throws<ImageProcessingException>(Test);
Assert.Contains("does not overlap", ex.ToString()); background.Mutate(c => c.DrawImage(foreground, new Point(64, 10), new Rectangle(32, 32, 32, 32), 1F));
void Test() => background.Mutate(context => context.DrawImage(overlay, new Point(x, y), new GraphicsOptions())); background.DebugSave(
provider,
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: false);
background.CompareToReferenceOutput(
provider,
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: false);
}
[Theory]
[WithFile(TestImages.Png.Issue2447, PixelTypes.Rgba32)]
public void Issue2447_B<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> foreground = provider.GetImage();
using Image<Rgba32> background = new(100, 100, new Rgba32(0, 255, 255));
background.Mutate(c => c.DrawImage(foreground, new Point(10, 10), new Rectangle(320, 128, 32, 32), 1F));
background.DebugSave(
provider,
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: false);
background.CompareToReferenceOutput(
provider,
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: false);
}
[Theory]
[WithFile(TestImages.Png.Issue2447, PixelTypes.Rgba32)]
public void Issue2447_C<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> foreground = provider.GetImage();
using Image<Rgba32> background = new(100, 100, new Rgba32(0, 255, 255));
background.Mutate(c => c.DrawImage(foreground, new Point(10, 10), new Rectangle(32, 32, 32, 32), 1F));
background.DebugSave(
provider,
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: false);
background.CompareToReferenceOutput(
provider,
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: false);
} }
} }

24
tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs

@ -370,6 +370,30 @@ public class BmpEncoderTests
TestBmpEncoderCore(provider, bitsPerPixel); TestBmpEncoderCore(provider, bitsPerPixel);
} }
[Theory]
[WithFile(BlackWhitePalletDataMatrix, PixelTypes.Rgb24, BmpBitsPerPixel.Pixel1)]
public void Encode_Issue2467<TPixel>(TestImageProvider<TPixel> provider, BmpBitsPerPixel bitsPerPixel)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
using var reencodedStream = new MemoryStream();
var encoder = new BmpEncoder
{
BitsPerPixel = bitsPerPixel,
SupportTransparency = false,
Quantizer = KnownQuantizers.Octree
};
image.SaveAsBmp(reencodedStream, encoder);
reencodedStream.Seek(0, SeekOrigin.Begin);
using Image<TPixel> reencodedImage = Image.Load<TPixel>(reencodedStream);
reencodedImage.DebugSave(provider);
reencodedImage.CompareToOriginal(provider);
}
private static void TestBmpEncoderCore<TPixel>( private static void TestBmpEncoderCore<TPixel>(
TestImageProvider<TPixel> provider, TestImageProvider<TPixel> provider,
BmpBitsPerPixel bitsPerPixel, BmpBitsPerPixel bitsPerPixel,

1
tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs

@ -81,6 +81,7 @@ public class PbmDecoderTests
[Theory] [Theory]
[WithFile(BlackAndWhitePlain, PixelTypes.L8, "pbm")] [WithFile(BlackAndWhitePlain, PixelTypes.L8, "pbm")]
[WithFile(BlackAndWhiteBinary, PixelTypes.L8, "pbm")] [WithFile(BlackAndWhiteBinary, PixelTypes.L8, "pbm")]
[WithFile(Issue2477, PixelTypes.L8, "pbm")]
[WithFile(GrayscalePlain, PixelTypes.L8, "pgm")] [WithFile(GrayscalePlain, PixelTypes.L8, "pgm")]
[WithFile(GrayscalePlainNormalized, PixelTypes.L8, "pgm")] [WithFile(GrayscalePlainNormalized, PixelTypes.L8, "pgm")]
[WithFile(GrayscaleBinary, PixelTypes.L8, "pgm")] [WithFile(GrayscaleBinary, PixelTypes.L8, "pgm")]

6
tests/ImageSharp.Tests/Formats/Pbm/PbmEncoderTests.cs

@ -26,6 +26,7 @@ public class PbmEncoderTests
{ {
{ BlackAndWhiteBinary, PbmColorType.BlackAndWhite }, { BlackAndWhiteBinary, PbmColorType.BlackAndWhite },
{ BlackAndWhitePlain, PbmColorType.BlackAndWhite }, { BlackAndWhitePlain, PbmColorType.BlackAndWhite },
{ Issue2477, PbmColorType.BlackAndWhite },
{ GrayscaleBinary, PbmColorType.Grayscale }, { GrayscaleBinary, PbmColorType.Grayscale },
{ GrayscaleBinaryWide, PbmColorType.Grayscale }, { GrayscaleBinaryWide, PbmColorType.Grayscale },
{ GrayscalePlain, PbmColorType.Grayscale }, { GrayscalePlain, PbmColorType.Grayscale },
@ -96,6 +97,11 @@ public class PbmEncoderTests
public void PbmEncoder_P4_Works<TPixel>(TestImageProvider<TPixel> provider) public void PbmEncoder_P4_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestPbmEncoderCore(provider, PbmColorType.BlackAndWhite, PbmEncoding.Binary); where TPixel : unmanaged, IPixel<TPixel> => TestPbmEncoderCore(provider, PbmColorType.BlackAndWhite, PbmEncoding.Binary);
[Theory]
[WithFile(Issue2477, PixelTypes.Rgb24)]
public void PbmEncoder_P4_Irregular_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> => TestPbmEncoderCore(provider, PbmColorType.BlackAndWhite, PbmEncoding.Binary);
[Theory] [Theory]
[WithFile(GrayscalePlainMagick, PixelTypes.Rgb24)] [WithFile(GrayscalePlainMagick, PixelTypes.Rgb24)]
public void PbmEncoder_P2_Works<TPixel>(TestImageProvider<TPixel> provider) public void PbmEncoder_P2_Works<TPixel>(TestImageProvider<TPixel> provider)

2
tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
@ -537,7 +538,6 @@ public partial class PngDecoderTests
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance); using Image<TPixel> image = provider.GetImage(PngDecoder.Instance);
image.DebugSave(provider);
PngMetadata metadata = image.Metadata.GetPngMetadata(); PngMetadata metadata = image.Metadata.GetPngMetadata();
Assert.True(metadata.HasTransparency); Assert.True(metadata.HasTransparency);
} }

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

@ -129,8 +129,8 @@ public partial class PngEncoderTests
PngFilterMethod.Adaptive, PngFilterMethod.Adaptive,
PngBitDepth.Bit8, PngBitDepth.Bit8,
interlaceMode, interlaceMode,
appendPixelType: true, appendPngColorType: true,
appendPngColorType: true); appendPixelType: true);
} }
} }
@ -321,7 +321,7 @@ public partial class PngEncoderTests
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using Image<TPixel> image = provider.GetImage(); using Image<TPixel> image = provider.GetImage();
using var ms = new MemoryStream(); using MemoryStream ms = new();
image.Save(ms, PngEncoder); image.Save(ms, PngEncoder);
byte[] data = ms.ToArray().Take(8).ToArray(); byte[] data = ms.ToArray().Take(8).ToArray();
@ -344,13 +344,13 @@ public partial class PngEncoderTests
[MemberData(nameof(RatioFiles))] [MemberData(nameof(RatioFiles))]
public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using Image<Rgba32> input = testFile.CreateRgba32Image(); using Image<Rgba32> input = testFile.CreateRgba32Image();
using var memStream = new MemoryStream(); using MemoryStream memStream = new();
input.Save(memStream, PngEncoder); input.Save(memStream, PngEncoder);
memStream.Position = 0; memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream); using Image<Rgba32> output = Image.Load<Rgba32>(memStream);
ImageMetadata meta = output.Metadata; ImageMetadata meta = output.Metadata;
Assert.Equal(xResolution, meta.HorizontalResolution); Assert.Equal(xResolution, meta.HorizontalResolution);
Assert.Equal(yResolution, meta.VerticalResolution); Assert.Equal(yResolution, meta.VerticalResolution);
@ -361,13 +361,13 @@ public partial class PngEncoderTests
[MemberData(nameof(PngBitDepthFiles))] [MemberData(nameof(PngBitDepthFiles))]
public void Encode_PreserveBits(string imagePath, PngBitDepth pngBitDepth) public void Encode_PreserveBits(string imagePath, PngBitDepth pngBitDepth)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using Image<Rgba32> input = testFile.CreateRgba32Image(); using Image<Rgba32> input = testFile.CreateRgba32Image();
using var memStream = new MemoryStream(); using MemoryStream memStream = new();
input.Save(memStream, PngEncoder); input.Save(memStream, PngEncoder);
memStream.Position = 0; memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream); using Image<Rgba32> output = Image.Load<Rgba32>(memStream);
PngMetadata meta = output.Metadata.GetPngMetadata(); PngMetadata meta = output.Metadata.GetPngMetadata();
Assert.Equal(pngBitDepth, meta.BitDepth); Assert.Equal(pngBitDepth, meta.BitDepth);
@ -380,8 +380,8 @@ public partial class PngEncoderTests
public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType colorType) public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType colorType)
{ {
// arrange // arrange
var image = new Image<Rgba32>(50, 50); Image<Rgba32> image = new(50, 50);
var encoder = new PngEncoder() PngEncoder encoder = new()
{ {
TransparentColorMode = PngTransparentColorMode.Clear, TransparentColorMode = PngTransparentColorMode.Clear,
ColorType = colorType ColorType = colorType
@ -391,7 +391,7 @@ public partial class PngEncoderTests
{ {
for (int y = 0; y < image.Height; y++) for (int y = 0; y < image.Height; y++)
{ {
System.Span<Rgba32> rowSpan = accessor.GetRowSpan(y); Span<Rgba32> rowSpan = accessor.GetRowSpan(y);
// Half of the test image should be transparent. // Half of the test image should be transparent.
if (y > 25) if (y > 25)
@ -407,12 +407,12 @@ public partial class PngEncoderTests
}); });
// act // act
using var memStream = new MemoryStream(); using MemoryStream memStream = new();
image.Save(memStream, encoder); image.Save(memStream, encoder);
// assert // assert
memStream.Position = 0; memStream.Position = 0;
using var actual = Image.Load<Rgba32>(memStream); using Image<Rgba32> actual = Image.Load<Rgba32>(memStream);
Rgba32 expectedColor = Color.Blue; Rgba32 expectedColor = Color.Blue;
if (colorType is PngColorType.Grayscale or PngColorType.GrayscaleWithAlpha) if (colorType is PngColorType.Grayscale or PngColorType.GrayscaleWithAlpha)
{ {
@ -424,7 +424,7 @@ public partial class PngEncoderTests
{ {
for (int y = 0; y < accessor.Height; y++) for (int y = 0; y < accessor.Height; y++)
{ {
System.Span<Rgba32> rowSpan = accessor.GetRowSpan(y); Span<Rgba32> rowSpan = accessor.GetRowSpan(y);
if (y > 25) if (y > 25)
{ {
@ -443,15 +443,15 @@ public partial class PngEncoderTests
[MemberData(nameof(PngTrnsFiles))] [MemberData(nameof(PngTrnsFiles))]
public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType)
{ {
var testFile = TestFile.Create(imagePath); TestFile testFile = TestFile.Create(imagePath);
using Image<Rgba32> input = testFile.CreateRgba32Image(); using Image<Rgba32> input = testFile.CreateRgba32Image();
PngMetadata inMeta = input.Metadata.GetPngMetadata(); PngMetadata inMeta = input.Metadata.GetPngMetadata();
Assert.True(inMeta.HasTransparency); Assert.True(inMeta.HasTransparency);
using var memStream = new MemoryStream(); using MemoryStream memStream = new();
input.Save(memStream, PngEncoder); input.Save(memStream, PngEncoder);
memStream.Position = 0; memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream); using Image<Rgba32> output = Image.Load<Rgba32>(memStream);
PngMetadata outMeta = output.Metadata.GetPngMetadata(); PngMetadata outMeta = output.Metadata.GetPngMetadata();
Assert.True(outMeta.HasTransparency); Assert.True(outMeta.HasTransparency);
@ -501,8 +501,8 @@ public partial class PngEncoderTests
PngFilterMethod.Adaptive, PngFilterMethod.Adaptive,
PngBitDepth.Bit8, PngBitDepth.Bit8,
interlaceMode, interlaceMode,
appendPixelType: true, appendPngColorType: true,
appendPngColorType: true); appendPixelType: true);
} }
} }
@ -523,8 +523,8 @@ public partial class PngEncoderTests
PngFilterMethod.Adaptive, PngFilterMethod.Adaptive,
PngBitDepth.Bit8, PngBitDepth.Bit8,
interlaceMode, interlaceMode,
appendPixelType: true, appendPngColorType: true,
appendPngColorType: true); appendPixelType: true);
} }
} }
@ -538,13 +538,27 @@ public partial class PngEncoderTests
public void EncodeFixesInvalidOptions() public void EncodeFixesInvalidOptions()
{ {
// https://github.com/SixLabors/ImageSharp/issues/935 // https://github.com/SixLabors/ImageSharp/issues/935
using var ms = new MemoryStream(); using MemoryStream ms = new();
var testFile = TestFile.Create(TestImages.Png.Issue935); TestFile testFile = TestFile.Create(TestImages.Png.Issue935);
using Image<Rgba32> image = testFile.CreateRgba32Image(PngDecoder.Instance); using Image<Rgba32> image = testFile.CreateRgba32Image(PngDecoder.Instance);
image.Save(ms, new PngEncoder { ColorType = PngColorType.RgbWithAlpha }); image.Save(ms, new PngEncoder { ColorType = PngColorType.RgbWithAlpha });
} }
// https://github.com/SixLabors/ImageSharp/issues/2469
[Theory]
[WithFile(TestImages.Png.Issue2469, PixelTypes.Rgba32)]
public void Issue2469_Quantized_Encode_Artifacts<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage(PngDecoder.Instance);
PngEncoder encoder = new() { BitDepth = PngBitDepth.Bit8, ColorType = PngColorType.Palette };
string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder);
using Image<Rgba32> encoded = Image.Load<Rgba32>(actualOutputFile);
encoded.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
private static void TestPngEncoderCore<TPixel>( private static void TestPngEncoderCore<TPixel>(
TestImageProvider<TPixel> provider, TestImageProvider<TPixel> provider,
PngColorType pngColorType, PngColorType pngColorType,
@ -563,7 +577,7 @@ public partial class PngEncoderTests
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using Image<TPixel> image = provider.GetImage(); using Image<TPixel> image = provider.GetImage();
var encoder = new PngEncoder PngEncoder encoder = new()
{ {
ColorType = pngColorType, ColorType = pngColorType,
FilterMethod = pngFilterMethod, FilterMethod = pngFilterMethod,

1
tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

@ -308,6 +308,7 @@ public class TiffDecoderTests : TiffDecoderBaseTester
[Theory] [Theory]
[WithFile(Cmyk, PixelTypes.Rgba32)] [WithFile(Cmyk, PixelTypes.Rgba32)]
[WithFile(CmykLzwPredictor, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Cmyk<TPixel>(TestImageProvider<TPixel> provider) public void TiffDecoder_CanDecode_Cmyk<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {

8
tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedMemoryPoolTests.Trim.cs

@ -113,9 +113,15 @@ public partial class UniformUnmanagedMemoryPoolTests
public static readonly bool Is32BitProcess = !Environment.Is64BitProcess; public static readonly bool Is32BitProcess = !Environment.Is64BitProcess;
private static readonly List<byte[]> PressureArrays = new(); private static readonly List<byte[]> PressureArrays = new();
[ConditionalFact(nameof(Is32BitProcess))] [Fact]
public static void GC_Collect_OnHighLoad_TrimsEntirePool() public static void GC_Collect_OnHighLoad_TrimsEntirePool()
{ {
if (!Is32BitProcess)
{
// This test is only relevant for 32-bit processes.
return;
}
RemoteExecutor.Invoke(RunTest).Dispose(); RemoteExecutor.Invoke(RunTest).Dispose();
static void RunTest() static void RunTest()

45
tests/ImageSharp.Tests/Numerics/RationalTests.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Tests; namespace SixLabors.ImageSharp.Tests;
@ -14,15 +14,15 @@ public class RationalTests
[Fact] [Fact]
public void AreEqual() public void AreEqual()
{ {
var r1 = new Rational(3, 2); Rational r1 = new(3, 2);
var r2 = new Rational(3, 2); Rational r2 = new(3, 2);
Assert.Equal(r1, r2); Assert.Equal(r1, r2);
Assert.True(r1 == r2); Assert.True(r1 == r2);
var r3 = new Rational(7.55); Rational r3 = new(7.55);
var r4 = new Rational(755, 100); Rational r4 = new(755, 100);
var r5 = new Rational(151, 20); Rational r5 = new(151, 20);
Assert.Equal(r3, r4); Assert.Equal(r3, r4);
Assert.Equal(r4, r5); Assert.Equal(r4, r5);
@ -34,20 +34,39 @@ public class RationalTests
[Fact] [Fact]
public void AreNotEqual() public void AreNotEqual()
{ {
var first = new Rational(0, 100); Rational first = new(0, 100);
var second = new Rational(100, 100); Rational second = new(100, 100);
Assert.NotEqual(first, second); Assert.NotEqual(first, second);
Assert.True(first != second); Assert.True(first != second);
} }
/// <summary>
/// Tests known out-of-range values.
/// </summary>
/// <param name="value">The input value.</param>
/// <param name="numerator">The expected numerator.</param>
/// <param name="denominator">The expected denominator.</param>
[Theory]
[InlineData(0, 0, 1)]
[InlineData(double.NaN, 0, 0)]
[InlineData(double.PositiveInfinity, 1, 0)]
[InlineData(double.NegativeInfinity, 1, 0)]
public void FromDoubleOutOfRange(double value, uint numerator, uint denominator)
{
Rational r = Rational.FromDouble(value);
Assert.Equal(numerator, r.Numerator);
Assert.Equal(denominator, r.Denominator);
}
/// <summary> /// <summary>
/// Tests whether the Rational constructor correctly assign properties. /// Tests whether the Rational constructor correctly assign properties.
/// </summary> /// </summary>
[Fact] [Fact]
public void ConstructorAssignsProperties() public void ConstructorAssignsProperties()
{ {
var rational = new Rational(7, 55); Rational rational = new(7, 55);
Assert.Equal(7U, rational.Numerator); Assert.Equal(7U, rational.Numerator);
Assert.Equal(55U, rational.Denominator); Assert.Equal(55U, rational.Denominator);
@ -71,15 +90,15 @@ public class RationalTests
[Fact] [Fact]
public void Fraction() public void Fraction()
{ {
var first = new Rational(1.0 / 1600); Rational first = new(1.0 / 1600);
var second = new Rational(1.0 / 1600, true); Rational second = new(1.0 / 1600, true);
Assert.False(first.Equals(second)); Assert.False(first.Equals(second));
} }
[Fact] [Fact]
public void ToDouble() public void ToDouble()
{ {
var rational = new Rational(0, 0); Rational rational = new(0, 0);
Assert.Equal(double.NaN, rational.ToDouble()); Assert.Equal(double.NaN, rational.ToDouble());
rational = new Rational(2, 0); rational = new Rational(2, 0);
@ -89,7 +108,7 @@ public class RationalTests
[Fact] [Fact]
public void ToStringRepresentation() public void ToStringRepresentation()
{ {
var rational = new Rational(0, 0); Rational rational = new(0, 0);
Assert.Equal("[ Indeterminate ]", rational.ToString()); Assert.Equal("[ Indeterminate ]", rational.ToString());
rational = new Rational(double.PositiveInfinity); rational = new Rational(double.PositiveInfinity);

12
tests/ImageSharp.Tests/TestImages.cs

@ -129,9 +129,15 @@ public static class TestImages
// Issue 2209: https://github.com/SixLabors/ImageSharp/issues/2209 // Issue 2209: https://github.com/SixLabors/ImageSharp/issues/2209
public const string Issue2209IndexedWithTransparency = "Png/issues/Issue_2209.png"; public const string Issue2209IndexedWithTransparency = "Png/issues/Issue_2209.png";
// Issue 2259: https://github.com/SixLabors/ImageSharp/issues/2259 // Issue 2259: https://github.com/SixLabors/ImageSharp/issues/2469
public const string Issue2259 = "Png/issues/Issue_2259.png"; public const string Issue2259 = "Png/issues/Issue_2259.png";
// Issue 2259: https://github.com/SixLabors/ImageSharp/issues/2469
public const string Issue2469 = "Png/issues/issue_2469.png";
// Issue 2447: https://github.com/SixLabors/ImageSharp/issues/2447
public const string Issue2447 = "Png/issues/issue_2447.png";
public static class Bad public static class Bad
{ {
public const string MissingDataChunk = "Png/xdtn0g01.png"; public const string MissingDataChunk = "Png/xdtn0g01.png";
@ -407,6 +413,8 @@ public static class TestImages
public const string Rgba321010102 = "Bmp/rgba32-1010102.bmp"; public const string Rgba321010102 = "Bmp/rgba32-1010102.bmp";
public const string RgbaAlphaBitfields = "Bmp/rgba32abf.bmp"; public const string RgbaAlphaBitfields = "Bmp/rgba32abf.bmp";
public const string BlackWhitePalletDataMatrix = "Bmp/bit1datamatrix.bmp";
public static readonly string[] BitFields = public static readonly string[] BitFields =
{ {
Rgb32bfdef, Rgb32bfdef,
@ -958,6 +966,7 @@ public static class TestImages
public const string Cmyk = "Tiff/Cmyk.tiff"; public const string Cmyk = "Tiff/Cmyk.tiff";
public const string Cmyk64BitDeflate = "Tiff/cmyk_deflate_64bit.tiff"; public const string Cmyk64BitDeflate = "Tiff/cmyk_deflate_64bit.tiff";
public const string CmykLzwPredictor = "Tiff/Cmyk-lzw-predictor.tiff";
public const string Issues1716Rgb161616BitLittleEndian = "Tiff/Issues/Issue1716.tiff"; public const string Issues1716Rgb161616BitLittleEndian = "Tiff/Issues/Issue1716.tiff";
public const string Issues1891 = "Tiff/Issues/Issue1891.tiff"; public const string Issues1891 = "Tiff/Issues/Issue1891.tiff";
@ -1029,6 +1038,7 @@ public static class TestImages
public const string RgbPlain = "Pbm/rgb_plain.ppm"; public const string RgbPlain = "Pbm/rgb_plain.ppm";
public const string RgbPlainNormalized = "Pbm/rgb_plain_normalized.ppm"; public const string RgbPlainNormalized = "Pbm/rgb_plain_normalized.ppm";
public const string RgbPlainMagick = "Pbm/rgb_plain_magick.ppm"; public const string RgbPlainMagick = "Pbm/rgb_plain_magick.ppm";
public const string Issue2477 = "Pbm/issue2477.pbm";
} }
public static class Qoi public static class Qoi

4
tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4d88eb2e50ca9dbed0e8dfe4ad278cd88ddb9d3408b30d9dfe59102b167f570b oid sha256:98115a7087aced0c28cefa32a57bc72be245886cabeefc4ff7faf7984236218c
size 262887 size 271226

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:97cfbef27319988b67aeac87d469d044edd925c90e4774170465f51eed85c16a oid sha256:58c03e354b108033873e2a4c0b043ce15919c4d0630e6ca72ff70b89cbedb979
size 42915 size 44239

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:3a799b69938507e3fd2a74ffa7c6c6ad6574acb25861a0a50cb8361520d468de oid sha256:f987f4d270568facefc11eee7f81dd156af56c26b69fe3a6d2d2e9818652befa
size 41809 size 43116

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:9932db58eeb966cd293b1b7a375e9c1b17b6d09153c679ebf03d42a08d2ce9b3 oid sha256:ebdad83936e50bbb00fd74b7dd7d2f5a480bb7347aa3d151e7827107cd279bac
size 43332 size 44441

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:67ebf42bc82483d1778254d95a376230437611dce91c80f8ecda608de56bffe7 oid sha256:ccdf5937c30999e3b09071200de2e1db63b606ad9cbf6f7677a7499fb0b52963
size 43108 size 44252

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8d5cdda990ac146a7580f58cc2bcab72f903dde564a394de7df4cc37e6dcf2dd oid sha256:baf70b732646d7c6cec60cfbe569ec673418dfb2dd0b5937bccfb91d9821d586
size 43906 size 45053

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c11e6c197bd1c227ae8f4af7e8c232cfe75db6929ab12bddf5e6554fbaed3f01 oid sha256:f6a1eae610ed730e4cec41693829929ba8db674886c2bd558f1b8893d2b76802
size 50716 size 51201

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:69ff9654eb61f2bfdd44fb25aff959c5b831015e283cc91a90e3abf6f681dc88 oid sha256:ba674e0236c2e146c64a7f3e224c702030769304cd0fd624d1989536da341659
size 52429 size 52814

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:6ee945ac5120e4198d1f94e6467cc0f77c90869bf5a09942e7720dddcfdfbe07 oid sha256:316231c8d837f864cf62dcc79fdce698dc8c45c0327372de42c2b89eac1d9f81
size 51262 size 51851

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:1b023505175ae39a93fa55c85aa31466f0aca76fab0ee54f9667648b91f9aeb9 oid sha256:b58144146585f50960dfd6ac5dc3f52238160287ae5f9b18c6796962cc3d2fd2
size 50789 size 51550

4
tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:6b18e8b80035a3c5985ebedab5eaf1b0e580d26dd2a8167e687e7b3dd6536751 oid sha256:6515be764d7026a87cfeea2d58344c404e4f15908139a25f413d51cc7cc61a0c
size 51922 size 52216

3
tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2447_A.png

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

3
tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2447_B.png

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

3
tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2447_C.png

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

3
tests/Images/External/ReferenceOutput/PbmDecoderTests/DecodeReferenceImage_L8_issue2477.png

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

3
tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png

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

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:97805a6a6de3cf1e97026a4913afa573f7ec40f82e718dd9c5e4df69482a6e19 oid sha256:033bb9e0ce89ffe4abda4d409af5741958d4035f9c9824c28d7598d72c4db96f
size 13097 size 13818

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:3c7d3da0ced1c66c6351d530565a190cfc1fdb7f3b7b05d39844f61fb87871ad oid sha256:9c6617ebf10f2fe1608fbc2a3c75f1a86ff4e3835b5d3fd7fcc2e5d0a4e5bbb1
size 13758 size 14380

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:2a6bb9a04f0663eb8a95d6d46c72557078de35ac935499d5ec4ab591d7f59eb9 oid sha256:5bb52f047f410e2b0bdcd8d186043f0d3b03835f39007775608fb05365ac9a20
size 13940 size 14616

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:97805a6a6de3cf1e97026a4913afa573f7ec40f82e718dd9c5e4df69482a6e19 oid sha256:033bb9e0ce89ffe4abda4d409af5741958d4035f9c9824c28d7598d72c4db96f
size 13097 size 13818

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:f0facae77f6022c92cdaaa7f27efb424962933c0e86ec4e8a7d62237a0f58d03 oid sha256:47e0924ddbf191dca8932eb46b9c533d0983b9fbce956026b392d5fe589fb90a
size 13919 size 14630

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:ec99338895bdada5cabe504afdcb0c0c95d8951e4404d31615a406b9956995c0 oid sha256:4ede7ffc5d07a09c7c5706e8e2554897d29acaabf71701191b0f689f2c22ae71
size 14154 size 17826

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:9699207803467b8718a719c7581e1ed6bf0c923a5adaf325aea8358d274fece5 oid sha256:f91c7f1f687c73dd909b629e40f703740270042507c47aa3834ccd38bf289dc3
size 18334 size 19394

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:0e3acfa5b7c6ef3bec68b5fa8db91b2e6160e01d1f952a055831cea2f0a58b0f oid sha256:2b836ab4e0f1c95fe5d553bf5bca37eac402ba431268d25e4641e86c952f5fdd
size 18675 size 19802

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:97805a6a6de3cf1e97026a4913afa573f7ec40f82e718dd9c5e4df69482a6e19 oid sha256:033bb9e0ce89ffe4abda4d409af5741958d4035f9c9824c28d7598d72c4db96f
size 13097 size 13818

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:fc1c1b5d0d0abec9b52ae7a83946a46020d2394a5f49f42e2ddb50fac988e974 oid sha256:00bcd2ac107f45cb31efee44de275dd597eae6d2d4fda71c397416ff5f2f0914
size 18874 size 20175

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:2eac7954110e82c7c9cb1c0d3734467b7e46745ea19b2fd10d0af7df0aad552c oid sha256:b04b71b0a4718e5b3f91c33c23ef792fc81a67c9fef7b9e4d80bdb9dce3539dd
size 9007 size 9107

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:51b06fc436e322ff9fc9e367b8117eb1178e112eb90fbd41a87847ab64a24136 oid sha256:e0125454d2c3859d8457202856e21591ab96f61e2a29c3f017af29bf03961c48
size 8801 size 8883

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:e46c5f17ef76f11ca1dfe70dd4b38858de049832c26add1e9f987f87319a3491 oid sha256:213ebd9fc7a190ad7226b487387edb9452284193cee4c4720448d7e19ef38e76
size 11029 size 11149

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:3527a0577720e7e8abf36b534540e72d17854d7b3b7d70cf3cdb519318e9e3c8 oid sha256:43b21e948795abb52ebbbf94e785542e55488cc7f17996e2b92404ca8ad1a7cb
size 7702 size 7844

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:e73014c6698526f3341e1f6001938bf5c60501bd6114451903a654c43c5f1997 oid sha256:0bb8f730a43a8f58e4269905014461bab8dc8b47387ec86a84c1064b1cdabe14
size 11719 size 11813

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:420d8ff32aa8ffa789e0c5dd00151856a016bc4f83ad035fdb4a8a22c338e247 oid sha256:7500be583beb22759dec7e5bbb2a8d2230054366bfbd0e39bf10fdc8af63eb58
size 8952 size 8925

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:93f3be15cb660c7c74c0de12d459c390c5f3c950d09dc4bcf617f5093e2b818b oid sha256:c48da7aad9c0aad576293d7085f9ddb2ea90a76d53bea54cbe0cb7aef71c7bb4
size 8606 size 9136

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a035a0b97ac471500a9dbead47a0d13deb449136980b89795b671b3e14481c9e oid sha256:72e6c327e98d9929a4d850905b1471fcd1191088feb38b028e4240e9f93b4996
size 9716 size 9827

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:3527a0577720e7e8abf36b534540e72d17854d7b3b7d70cf3cdb519318e9e3c8 oid sha256:43b21e948795abb52ebbbf94e785542e55488cc7f17996e2b92404ca8ad1a7cb
size 7702 size 7844

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:fac9fc2316ccf7a464e93d0406acdf37d5aac7f76f54c87454fa41b13c8224fc oid sha256:70f8fc84d6e578822582ebee5888514dcd70c8d0da1a920f35e63a1617d1e92c
size 9731 size 9841

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c738cea16a714bdfa54cfcc213102d53ebe3aee576390902d352f04be65edac2 oid sha256:ff4d6e3a7c8e69db0d5a88b7f1c91621692962bdbcedd6b8af1311506243bcde
size 11166 size 11259

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:42b44354480a1d2c869f541e6f3ed9feec15fb04ad32eb2a21b7d65290eeec54 oid sha256:520910b75cae834b9844ce896ad9ab6d0b6c33c44c7bd822ce63752aaa2a8c5a
size 11972 size 12122

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:d7d62b46acff22858a1621656ddaa97c3610a7f13df9c5d77747b7364620b174 oid sha256:8e1fb4bb5d1591ac6bb8a4fb2504e2e836578c9c42d8286061cf4f57f0b7f97d
size 12772 size 12876

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:9e532758291dd3d18b5b81c1d788db7854b322a633557f3ee273bb9d68c465ba oid sha256:3f5babf5f6ae746a9b9f131ecf990f037c8e8bdb257bdbb7f6127460c9b8f98d
size 9582 size 10507

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:581febc9878288785ae82b23f2946dc0c506ae86fba32bb02ba5e69cf1c8cda1 oid sha256:56a9088fdca14b82fa3ac3ecfb67b6b8e97e8d69b89907c8408e17861e8609e0
size 14069 size 14195

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:12f7bacf0402f821e3c80f65c29218bc1f1334392edc463b617cf711667db722 oid sha256:7d4ef129d8846e6802997c0ace90abdc7412d232e9a31fc53f25bb9f32de08f2
size 12381 size 12665

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:436d168a3501da20c327cb3d2909cdd465585ee3f76a2534e37a36771e10115e oid sha256:69b5771a313aa777341d1460db94a7b3cc74b69c44f6c9d1a1b5b3734936e795
size 12596 size 12791

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c952f81377c83b2255c427d0911b898e500d163d870de778b69778a9ab8c8278 oid sha256:a56f72c5a12e6d216a32404c996e72721b4cf350d82071a43ebe44190adef94a
size 12459 size 12895

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:9e532758291dd3d18b5b81c1d788db7854b322a633557f3ee273bb9d68c465ba oid sha256:3f5babf5f6ae746a9b9f131ecf990f037c8e8bdb257bdbb7f6127460c9b8f98d
size 9582 size 10507

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:2b542c86ea4fef3a37e89c1087dddafeeccf523e7c0721743f34d35da5e0653e oid sha256:39f85cb564a257381656fd969acaeda04016e09380133f772eb029e332aeaa95
size 13116 size 13482

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:147b7ebbe92f2379d513a44214a8383ed96a94b92f9d80cb3c5944e5e32e94bc oid sha256:9d528ea896a2e56e0b8967d5ce3486078cbd7bf29e5f0d43a58ef21100147915
size 13097 size 13818

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:5b55add6cd3dc0e130f399a6932ba279aa29dc72579ee575df88e0faf76a3835 oid sha256:4e96967a2a6362f42026ab2e2cdd82437e573c16a52c5631f7495cb30615441d
size 13073 size 13841

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:ed5c1745e2ef33654023ed0a8bfabe5a75d46186aa5c42df54ac1a9506dcf632 oid sha256:d5f9e9e4f7f48681d5b240d6df6ae282c6b9e896eacc1ad73f2a097975fa8d29
size 13431 size 14060

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:147b7ebbe92f2379d513a44214a8383ed96a94b92f9d80cb3c5944e5e32e94bc oid sha256:9d528ea896a2e56e0b8967d5ce3486078cbd7bf29e5f0d43a58ef21100147915
size 13097 size 13818

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:945c33feb2f3408b54e4574781eee3c2868885af25acd9172d420360e505b54a oid sha256:97d6923c3342d600a9a2ab3fa713136b2649b74364d6e90a905de607838e0cb7
size 13463 size 14319

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:3edb6672168fc58a2bb6766d48a0883aa35fdc6873d2f4b9f26d3b5fa6cb46dd oid sha256:66399a4ba262bdacdc5966fa9fc6f8f6bfa3f8c70db889363e9bbd5778dc1ecf
size 15574 size 16081

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:9fd79ec840f8bd82b41d93987187531187a4bd957d7f0d497a86fa61de52cec7 oid sha256:5953a12a2fa67f9fe17485c62d156bb7f80a4bcf4124c123db4440c2559e0e69
size 16733 size 17002

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:360121a75c96434daa57f2b996e9776cc1efdf25aa3f7e926abd6d04c9ee4184 oid sha256:efc08c6969344de404692c2b367130e3f736442c0722067a9105f036a9e4511e
size 17355 size 17616

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:147b7ebbe92f2379d513a44214a8383ed96a94b92f9d80cb3c5944e5e32e94bc oid sha256:9d528ea896a2e56e0b8967d5ce3486078cbd7bf29e5f0d43a58ef21100147915
size 13097 size 13818

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:97d3b5d804c50da0d9c5db7278b16bb807e246dbd083c8c62ec7d4d7a65a1b45 oid sha256:455488369cd943f3c3a0b2c402dbb17d6fc9c384b5f26dbc049634ad4bdab73f
size 18070 size 18259

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:7f7ce90fb4dec4b890eb8bfd182e009b2769104ab2f14e926381c4949d6f7453 oid sha256:2a65ffa4c6b8488f52892306052337e17a4e58d28fa43f18009e6d1f997962de
size 82121 size 83060

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:2430b92bc20b2c3d142b5f84ae9fd62856fc4c717b0b226c2e096d725883d41f oid sha256:1f69909cdc4b65548834e30caf44a31b7e5d41be1db05cb43bd8277613f327ed
size 54154 size 55263

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4cd9433cdab37510cf6d98ce5838a69675359982376f7ef5c9e716c49772af74 oid sha256:ff7d35f1ce04d8f2b6cee41c951487bd24e18f923dc84c77a7944ec3aab61540
size 79370 size 80844

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:d74faa8d188a2915739de64ba9d71b2132b53c8d154db22510c524ae757578a5 oid sha256:48ac9eea396e010b1c110413a6861b1708f3928243271ea78f390e64dfe11737
size 61183 size 62249

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a5ad9cb26866b35f6ad8c0ae054c7172a15b2fb2512bd123af3c0e5685c30410 oid sha256:a4786eb2c04be00302996f3ad65987f54fe5d80ded438fdcccf7b9bfe9520dbb
size 32766 size 33930

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:67ebf42bc82483d1778254d95a376230437611dce91c80f8ecda608de56bffe7 oid sha256:ccdf5937c30999e3b09071200de2e1db63b606ad9cbf6f7677a7499fb0b52963
size 43108 size 44252

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:b5271fba5dcee48982ccad321f987a67d6663dabc01d380eb0cafc178251bc00 oid sha256:898c8524d6fcad8498a22dd97956265302458d43f8d3f93846c2268d7b47fb73
size 33971 size 35351

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:1ba613bc2cf88dfb357e88671464272ab4279667b8c776b8b9db913161b7f450 oid sha256:5f37abc44b703b6feac3a2a950df7f40a8a67fe64fa25c19af59862e5272f0ff
size 33060 size 34311

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:242379eee61c3d82f10e8b36db0567749443f91a6e13e766cc1ee3a3eeff7e2c oid sha256:1cb4518f6b9e1ed1409b0f4e87c17ae990cff2725c650d69941cc76ba90b2f7b
size 43006 size 44672

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:fe72f6268d445f204afcea4723624398ff49e479e8b608843cf287dfb94ebe4e oid sha256:16a592718ba5aa15f79ef4864cba75fae5a7cc5e13ca56eeab5fd13a0e5347de
size 101257 size 102049

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c29c21979beeb7f659979893d05d1da15602a8fbc4a61309cd6380b296d69367 oid sha256:86ebb09209d4bfbe266c633df1c7062755cd413f47d0a96a05bcf003a02cb12b
size 83563 size 84428

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:49e072dc73ba96dffa021b3e9bbf169102bd9ae7b9d4ed0a69b55178f1592ae5 oid sha256:779521e132b4ee6b3ac7a9186fca3250c6d2ace7e55f4f6c9601fe5393d9eb10
size 97415 size 99561

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8c6041ecc220ee8cd576aff06871bc1f3b7363dffe334bbab83344c5b96cbde3 oid sha256:a6d0b12e19b980fd558a4920ec18620a9bdb00bd1379a20719ff0ee92c6887a1
size 94511 size 96007

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:912de82dc98a8dd72ffc5549125c397379a859a23ffe48f01e4f1c5a28ff1d18 oid sha256:82c34b115c081a1f3723540b9a273724353930c53006dd6daea576a227271e01
size 77029 size 78599

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:bedb363c412c4c387fabe4d65ca769079376f4cc56a3bfdd767f0ae8441b3dfb oid sha256:6fbe71277a196e5c57fba7caba5c0a1b2bff2da9eadbd7bab1ae1853fab2dd93
size 92003 size 92581

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:d4a64da29f144d4d4c525ea45e56819e02a46030ae09542be01fdd8ffc85a295 oid sha256:b1061a363744661febdd051ef2f6839bfe288eb83f7ebf281fb06717fbe6703a
size 60377 size 60739

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:eee438f7cbe6615bab0df73689f6924ea153da28eaf1f4c0c22076f24f18085d oid sha256:cacd80b681c086310d3be7d90575da357e6ab0a62e24227a1e7e3ae4cab1de2d
size 46476 size 46905

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:1b023505175ae39a93fa55c85aa31466f0aca76fab0ee54f9667648b91f9aeb9 oid sha256:b58144146585f50960dfd6ac5dc3f52238160287ae5f9b18c6796962cc3d2fd2
size 50789 size 51550

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c175f0db79d3ac74043dce3fe57d5c15c6ca38c954c008baf5fa917d3b9d4e0e oid sha256:d54a2b762a16c76ad52919708d0126ae63958e9d900e3870cced695540e16192
size 67374 size 68366

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:7c76f0df12da8eac1fefb6ba9c0c89f5c8a7bcfbff442a4ebd763f1a4b359637 oid sha256:87450152fdccfaebb55e22040206cb246bc59b61461fd8b6ca6e099256fa0f1d
size 63046 size 63839

4
tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:f2636953295972ede173dbfaf3b67f7cb91f1c3f4ccc79f70e078bd94af9422d oid sha256:7136f92f3fd1927e98204b1140ca36a901dcd9b67c17f7080413588c2e2dcc28
size 68579 size 69579

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

Loading…
Cancel
Save